同步外部数据到飞书多维表格
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
c987a7dcbd
commit
33915a8d62
@ -1,8 +1,23 @@
|
||||
package com.ruoyi.flyingbook.LarkHelper;
|
||||
|
||||
import com.ruoyi.common.enums.TableFieldTypeEnum;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-03-18 11:09
|
||||
*/
|
||||
public class DataStructureHelper {
|
||||
|
||||
public static Object buildRecordFieldInfo(Object value,Integer type){
|
||||
TableFieldTypeEnum typeEnum = TableFieldTypeEnum.getByCode(type);
|
||||
if (typeEnum == null){
|
||||
return value;
|
||||
}
|
||||
switch (typeEnum){
|
||||
case DATE:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.ruoyi.flyingbook.controller;
|
||||
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.flyingbook.domain.edi.EdiResponseVo;
|
||||
import com.ruoyi.flyingbook.domain.edi.SyncToTableRequest;
|
||||
import com.ruoyi.flyingbook.edi.EdiOperateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class EdiController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private EdiOperateService ediOperateService;
|
||||
|
||||
/**
|
||||
* 同步数据到飞书表格
|
||||
*/
|
||||
@PostMapping("/sync2Table")
|
||||
public EdiResponseVo sync2Table(@RequestBody SyncToTableRequest request) {
|
||||
return ediOperateService.sync2Table(request);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.ruoyi.flyingbook.domain.edi;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-03-12 16:00
|
||||
*/
|
||||
@Data
|
||||
public class EdiRequestVo {
|
||||
|
||||
private String appId;
|
||||
private String secret;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.ruoyi.flyingbook.domain.edi;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:47
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class EdiResponseVo {
|
||||
|
||||
private Boolean successFlag;
|
||||
|
||||
private String errorMessage;
|
||||
private List<String> errorMessageList;
|
||||
|
||||
public EdiResponseVo(Boolean successFlag, String errorMessage) {
|
||||
this.successFlag = successFlag;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public EdiResponseVo(Boolean successFlag, String... errorMsg) {
|
||||
this.successFlag = successFlag;
|
||||
this.errorMessageList = new ArrayList<>();
|
||||
for (String s : errorMsg) {
|
||||
this.errorMessageList.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
public void addErrorMsg(String errorMessage){
|
||||
if (CollectionUtils.isEmpty(this.errorMessageList)){
|
||||
this.errorMessageList = new ArrayList<>();
|
||||
}
|
||||
this.errorMessageList.add(errorMessage);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.ruoyi.flyingbook.domain.edi;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:43
|
||||
*/
|
||||
@Data
|
||||
public class SyncTableColDetailRequest implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 列对应的值
|
||||
*/
|
||||
private String colName;
|
||||
|
||||
/**
|
||||
* 列对应的值
|
||||
*/
|
||||
private Object colValue;
|
||||
/**
|
||||
* 当前字段对应多维表格的类型
|
||||
*/
|
||||
private Integer type;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.ruoyi.flyingbook.domain.edi;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:43
|
||||
*/
|
||||
@Data
|
||||
public class SyncTableRowDetailRequest implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 列对应的值
|
||||
*/
|
||||
private List<Object> colDetailList;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.ruoyi.flyingbook.domain.edi;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.flyingbook.domain.LarkCompanyRelation;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableConfiguration;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableRelation;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableRowRelation;
|
||||
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections4.MultiValuedMap;
|
||||
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:43
|
||||
*/
|
||||
@Data
|
||||
public class SyncToTableRequest extends EdiRequestVo {
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String appToken;
|
||||
|
||||
/**
|
||||
* 多维表格的id
|
||||
*/
|
||||
private String tableId;
|
||||
|
||||
private List<SyncTableRowDetailRequest> rowDetailList;
|
||||
|
||||
private List<LarkTableRequest> rowBodyList;
|
||||
|
||||
private LarkCompanyRelation larkCompanyRelation;
|
||||
|
||||
private LarkTableRelation larkTableRelations;
|
||||
|
||||
private List<LarkTableConfiguration> configurationList;
|
||||
|
||||
private LarkTableConfiguration createMultiTableConfiguration;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.ruoyi.flyingbook.domain.lark;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-03-18 0:12
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class LarkTableFieldDetail{
|
||||
|
||||
private String field_name;
|
||||
private Integer type;
|
||||
|
||||
public LarkTableFieldDetail(String fieldName, Integer type) {
|
||||
this.field_name = fieldName;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.ruoyi.flyingbook.edi;
|
||||
|
||||
import com.ruoyi.flyingbook.domain.edi.EdiRequestVo;
|
||||
import com.ruoyi.flyingbook.domain.edi.EdiResponseVo;
|
||||
import com.ruoyi.flyingbook.domain.edi.SyncToTableRequest;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:57
|
||||
*/
|
||||
public interface EdiOperateService {
|
||||
|
||||
public EdiResponseVo sync2Table(SyncToTableRequest ediRequestVo);
|
||||
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
package com.ruoyi.flyingbook.edi.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.lark.oapi.service.authen.v1.model.CreateAccessTokenRespBody;
|
||||
import com.lark.oapi.service.bitable.v1.model.AppTableCreateHeader;
|
||||
import com.lark.oapi.service.bitable.v1.model.CreateAppResp;
|
||||
import com.lark.oapi.service.bitable.v1.model.CreateAppRespBody;
|
||||
import com.lark.oapi.service.bitable.v1.model.CreateAppTableRespBody;
|
||||
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserRespBody;
|
||||
import com.lark.oapi.service.contact.v3.model.UserContactInfo;
|
||||
import com.ruoyi.common.enums.*;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.flyingbook.LarkHelper.DataStructureHelper;
|
||||
import com.ruoyi.flyingbook.LarkHelper.LarkTableHelper;
|
||||
import com.ruoyi.flyingbook.LarkHelper.LarkUserHelper;
|
||||
import com.ruoyi.flyingbook.domain.LarkCompanyRelation;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableConfiguration;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableRelation;
|
||||
import com.ruoyi.flyingbook.domain.LarkTableRowRelation;
|
||||
import com.ruoyi.flyingbook.domain.edi.*;
|
||||
import com.ruoyi.flyingbook.domain.lark.LarkTableFieldDetail;
|
||||
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
|
||||
import com.ruoyi.flyingbook.domain.lark.LarkUserRequest;
|
||||
import com.ruoyi.flyingbook.edi.EdiOperateService;
|
||||
import com.ruoyi.flyingbook.mapper.LarkCompanyRelationMapper;
|
||||
import com.ruoyi.flyingbook.mapper.LarkTableConfigurationMapper;
|
||||
import com.ruoyi.flyingbook.mapper.LarkTableRelationMapper;
|
||||
import com.ruoyi.flyingbook.mapper.LarkTableRowRelationMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MultiValuedMap;
|
||||
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-03-12 15:58
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class EdiOperateServiceImpl implements EdiOperateService {
|
||||
|
||||
@Resource
|
||||
private LarkCompanyRelationMapper larkCompanyRelationMapper;
|
||||
@Resource
|
||||
private LarkTableRelationMapper larkTableRelationMapper;
|
||||
@Resource
|
||||
private LarkTableConfigurationMapper larkTableConfigurationMapper;
|
||||
@Autowired
|
||||
private LarkUserHelper larkUserHelper;
|
||||
@Autowired
|
||||
private LarkTableHelper larkTableHelper;
|
||||
|
||||
|
||||
@Override
|
||||
public EdiResponseVo sync2Table(SyncToTableRequest request) {
|
||||
EdiResponseVo vo = new EdiResponseVo();
|
||||
try {
|
||||
//校验参数
|
||||
this.checkParam(request);
|
||||
//创建多维表格
|
||||
this.createMultiTable(request);
|
||||
//创建数据表
|
||||
this.createDataTable(request);
|
||||
//构建消息体
|
||||
this.buildRequestBodyList(request);
|
||||
|
||||
vo.setSuccessFlag(Boolean.TRUE);
|
||||
}catch (Exception e){
|
||||
log.error("同步数据到飞书异常");
|
||||
vo.setSuccessFlag(Boolean.FALSE);
|
||||
vo.setErrorMessage(e.getMessage());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建多维表格
|
||||
*/
|
||||
private void createMultiTable(SyncToTableRequest request){
|
||||
LarkTableConfiguration createMultiTableConfiguration = request.getCreateMultiTableConfiguration();
|
||||
LarkCompanyRelation companyRelation = request.getLarkCompanyRelation();
|
||||
LarkUserRequest larkUserRequest = new LarkUserRequest();
|
||||
larkUserRequest.setAppId(companyRelation.getAppId());
|
||||
larkUserRequest.setAppSecret(companyRelation.getSecret());
|
||||
larkUserRequest.setCode(createMultiTableConfiguration.getParam1());
|
||||
CreateAccessTokenRespBody userToken = larkUserHelper.getUserToken(larkUserRequest);
|
||||
//userToken
|
||||
LarkTableRequest createMultiTable = new LarkTableRequest(companyRelation.getAppId(), userToken.getAccessToken(), request.getTableName());
|
||||
CreateAppRespBody multiTable = larkTableHelper.createMultiTable(createMultiTable);
|
||||
String appToken = multiTable.getApp().getAppToken();
|
||||
request.setAppToken(appToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数据表
|
||||
*/
|
||||
private void createDataTable(SyncToTableRequest request){
|
||||
LarkCompanyRelation larkCompanyRelation = request.getLarkCompanyRelation();
|
||||
List<LarkTableConfiguration> configurationList = request.getConfigurationList();
|
||||
AppTableCreateHeader[] fields = new AppTableCreateHeader[configurationList.size()];
|
||||
for (int i = 0; i < configurationList.size(); i++) {
|
||||
LarkTableConfiguration configuration = configurationList.get(i);
|
||||
AppTableCreateHeader header = new AppTableCreateHeader();
|
||||
header.setFieldName(configuration.getParam1());
|
||||
header.setType(Integer.valueOf(configuration.getParam2()));
|
||||
fields[i] = header;
|
||||
}
|
||||
LarkTableRequest createTableReq = new LarkTableRequest(larkCompanyRelation.getAppId(),larkCompanyRelation.getSecret()
|
||||
,request.getAppToken(),request.getTableName(),request.getTableName()
|
||||
,fields);
|
||||
CreateAppTableRespBody dataTable = larkTableHelper.createDataTable(createTableReq);
|
||||
request.setTableId(dataTable.getTableId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建行记录消息体
|
||||
*/
|
||||
private void buildRequestBodyList(SyncToTableRequest request){
|
||||
List<LarkTableConfiguration> configurationList = request.getConfigurationList();
|
||||
LarkCompanyRelation larkCompanyRelation = request.getLarkCompanyRelation();
|
||||
//多维表格行记录
|
||||
List<LarkTableRequest> rowBodyList = new ArrayList<>();
|
||||
for (SyncTableRowDetailRequest rowDetail : request.getRowDetailList()) {
|
||||
Map<String,Object> body = new HashMap<>();
|
||||
List<Object> colDetailList = rowDetail.getColDetailList();
|
||||
for (int i = 0; i < colDetailList.size(); i++) {
|
||||
Object colValue = colDetailList.get(i);
|
||||
LarkTableConfiguration configuration = configurationList.get(i);
|
||||
String colName = configuration.getParam1();
|
||||
Integer colType = Integer.valueOf(configuration.getParam2());
|
||||
Object value = DataStructureHelper.buildRecordFieldInfo(colValue, colType);
|
||||
body.put(colName,value);
|
||||
}
|
||||
LarkTableRequest rowRequest = new LarkTableRequest(larkCompanyRelation.getAppId(),larkCompanyRelation.getSecret(),request.getAppToken(),request.getTableId(),body);
|
||||
rowBodyList.add(rowRequest);
|
||||
}
|
||||
request.setRowBodyList(rowBodyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验参数信息
|
||||
* @param request
|
||||
*/
|
||||
private void checkParam(SyncToTableRequest request){
|
||||
if (request == null){
|
||||
throw new RuntimeException("请求对象不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getAppId())){
|
||||
throw new RuntimeException("appId不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getSecret())){
|
||||
throw new RuntimeException("密钥不能为空");
|
||||
}
|
||||
if (CollectionUtils.isEmpty(request.getRowDetailList())){
|
||||
throw new RuntimeException("同步行信息不能为空");
|
||||
}
|
||||
LarkCompanyRelation companyRelationRequest = new LarkCompanyRelation();
|
||||
companyRelationRequest.setAppId(request.getAppId());
|
||||
companyRelationRequest.setSecret(request.getSecret());
|
||||
companyRelationRequest.setFlag(FlagStatus.OK.getCode());
|
||||
companyRelationRequest.setAppType(AppType.SYNC_EXTERNAL_DATA_TO_MULTI_TABLE.getCode());
|
||||
List<LarkCompanyRelation> larkCompanyRelations = larkCompanyRelationMapper.selectLarkCompanyRelationList(companyRelationRequest);
|
||||
if (CollectionUtils.isEmpty(larkCompanyRelations)){
|
||||
throw new RuntimeException("无对应公司密钥同步配置信息");
|
||||
}
|
||||
if (larkCompanyRelations.size() > 1){
|
||||
throw new RuntimeException("同时存在多个公司密钥同步配置信息");
|
||||
}
|
||||
LarkCompanyRelation larkCompanyRelation = larkCompanyRelations.get(0);
|
||||
request.setLarkCompanyRelation(larkCompanyRelation);
|
||||
LarkTableRelation tableRelationRequest = new LarkTableRelation();
|
||||
tableRelationRequest.setRelationType(TableRelationTypeEnum.SYNC_EXTERNAL_DATA_TO_MULTI_TABLE.getCode());
|
||||
tableRelationRequest.setLarkCompanyRelationId(larkCompanyRelation.getId());
|
||||
tableRelationRequest.setFlag(FlagStatus.OK.getCode());
|
||||
List<LarkTableRelation> larkTableRelations = larkTableRelationMapper.selectLarkTableRelationList(tableRelationRequest);
|
||||
if (CollectionUtils.isEmpty(larkCompanyRelations)){
|
||||
throw new RuntimeException("无对应多维表格同步配置信息");
|
||||
}
|
||||
if (larkCompanyRelations.size() > 1){
|
||||
throw new RuntimeException("多维表格同步配置信息存在多个");
|
||||
}
|
||||
LarkTableRelation tableRelation = larkTableRelations.get(0);
|
||||
request.setLarkTableRelations(tableRelation);
|
||||
|
||||
LarkTableConfiguration larkTableConfiguration = new LarkTableConfiguration();
|
||||
larkTableConfiguration.setFlag(FlagStatus.OK.getCode());
|
||||
larkTableConfiguration.setLarkTableId(tableRelation.getId());
|
||||
larkTableConfiguration.setConfigType(ConfigurationTypeEnum.CREATE_DATA_TABLE.getCode());
|
||||
larkTableConfiguration.setSubConfigType(ConfigurationSubTypeEnum.CREATE_DATA_TABLE.getCode());
|
||||
List<LarkTableConfiguration> configurationList = larkTableConfigurationMapper.selectLarkTableConfigurationList(larkTableConfiguration);
|
||||
if (CollectionUtils.isEmpty(configurationList)){
|
||||
throw new RuntimeException("无对应数据表格表结构同步配置信息");
|
||||
}
|
||||
configurationList = configurationList.stream().sorted(new Comparator<LarkTableConfiguration>() {
|
||||
@Override
|
||||
public int compare(LarkTableConfiguration o1, LarkTableConfiguration o2) {
|
||||
return Integer.valueOf(o1.getParam3()).compareTo(Integer.valueOf(o2.getParam3()));
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
request.setConfigurationList(configurationList);
|
||||
|
||||
LarkTableConfiguration configurationQuery = new LarkTableConfiguration();
|
||||
configurationQuery.setFlag(FlagStatus.OK.getCode());
|
||||
configurationQuery.setLarkTableId(tableRelation.getId());
|
||||
configurationQuery.setConfigType(ConfigurationTypeEnum.CREATE_MULTI_TABLE.getCode());
|
||||
configurationQuery.setSubConfigType(ConfigurationSubTypeEnum.CREATE_MULTI_TABLE.getCode());
|
||||
List<LarkTableConfiguration> configList = larkTableConfigurationMapper.selectLarkTableConfigurationList(configurationQuery);
|
||||
if (CollectionUtils.isEmpty(configList)){
|
||||
throw new RuntimeException("无对应多维表格表结构同步配置信息");
|
||||
}
|
||||
request.setCreateMultiTableConfiguration(configList.get(0));
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.ruoyi.flyingbook.strategy.sync;
|
||||
|
||||
import com.ruoyi.flyingbook.domain.RequestVo;
|
||||
import com.ruoyi.flyingbook.strategy.LarkOperateAbstract;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author yuxiangyong
|
||||
* @create 2023-05-07 21:40
|
||||
*/
|
||||
@Service
|
||||
public class SyncToTableService extends LarkOperateAbstract {
|
||||
@Override
|
||||
protected void preOperate(RequestVo request) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void businessProcessing(RequestVo request) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String buildResult(RequestVo request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in new issue