提交 e57adfc6 authored 作者: 李秋林's avatar 李秋林

活动记录上传飞书

上级 1ec437cd
package com.wangxiaolu.export; package com.wangxiaolu.export;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication @EnableAsync
@EnableConfigurationProperties
@EnableAspectJAutoProxy
@SpringBootApplication(scanBasePackages = {"com"})
@MapperScan("com.wangxiaolu.export.mapper")
public class WangxiaoluExportApplication { public class WangxiaoluExportApplication {
public static void main(String[] args) { public static void main(String[] args) {
......
package com.wangxiaolu.export.controller.feishu;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityClockDO;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityPhotoDO;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityReportedDO;
import com.wangxiaolu.export.pojo.ActivityVo;
import com.wangxiaolu.export.service.ActivityToFeishuSheetService;
import com.wangxiaolu.export.service.PromotionActivityService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author : liqiulin
* @date : 2024-06-14 11
* @describe :
*/
@Slf4j
@RestController
@RequestMapping("/promotion/activity")
public class ActivityToFeishuSheet {
@Autowired
PromotionActivityService promotionActivityService;
@Autowired
ActivityToFeishuSheetService activityToFeishuSheetService;
/**
* 飞书电子表格
* @param activityVo 查询活动创建日期范围
*/
@PostMapping("/feishu/sheet")
public void activityList(@RequestBody ActivityVo activityVo) {
/**
* 1>> 查询活动记录
* 查询当天的记录
*/
List<TemporaryActivityReportedDO> reportedDos = promotionActivityService.findActivityList(activityVo);
List<Long> activityId = reportedDos.stream().map(TemporaryActivityReportedDO::getId).collect(Collectors.toList());
Map<Long, List<TemporaryActivityPhotoDO>> activityPhotos = promotionActivityService.findActivityPhotos(activityId);
/**
* 2>> 查询打卡记录
*/
List<TemporaryActivityClockDO> clockPhoto = promotionActivityService.findClockPhoto(activityVo);
Map<String, List<TemporaryActivityPhotoDO>> clockPhotoMap = new HashMap<>();
clockPhoto.stream().forEach(cp -> {
clockPhotoMap.put(cp.getTemporaryId() + "-" + cp.getCreateDate(), cp.getPhotoList());
});
log.info("============== 活动记录上传飞书 start(" + System.currentTimeMillis() + ") ==============");
activityToFeishuSheetService.activityDataToFeishuSheet(reportedDos,activityPhotos,clockPhotoMap);
log.info("============== 活动记录上传飞书 end(" + System.currentTimeMillis() + ") ==============");
}
}
...@@ -211,7 +211,9 @@ public class PromotionActivityExport { ...@@ -211,7 +211,9 @@ public class PromotionActivityExport {
}); });
log.info("活动记录数据处理完成,开始导出"); log.info("活动记录数据处理完成,开始导出");
System.out.println("1:"+System.currentTimeMillis());
ExcelUtils.export(response, "活动数据导出_"+ DateUtil.today(), sheet); ExcelUtils.export(response, "活动数据导出_"+ DateUtil.today(), sheet);
System.out.println("7:"+System.currentTimeMillis());
log.info("============== 活动记录导出 end =============="); log.info("============== 活动记录导出 end ==============");
} }
......
package com.wangxiaolu.export.mapper;
import com.wangxiaolu.export.mapper.entity.FeishuSheetRecordDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @author a02200059
* @description 针对表【feishu_sheet_record】的数据库操作Mapper
* @createDate 2024-07-30 15:09:39
* @Entity com.wangxiaolu.export.mapper.entity.FeishuSheetRecordDO
*/
@Mapper
@Repository
public interface FeishuSheetRecordMapper extends BaseMapper<FeishuSheetRecordDO> {
FeishuSheetRecordDO selectOneByCreateMonth(String month);
}
package com.wangxiaolu.export.mapper.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
*
* @TableName feishu_sheet_record
*/
@TableName(value ="feishu_sheet_record")
@Data
public class FeishuSheetRecordDO implements Serializable {
/**
* 主键id
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 电子表格token
*/
private String sheetToken;
/**
* 工作表id
*/
private String sheetId;
/**
* 创建月份
*/
private String createMonth;
/**
* 创建时间
*/
private Date createTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
package com.wangxiaolu.export.pojo; package com.wangxiaolu.export.pojo;
import cn.hutool.core.date.DateTime;
import lombok.Data; import lombok.Data;
import java.util.Date;
/** /**
* @author : liqiulin * @author : liqiulin
* @date : 2024-07-03 10 * @date : 2024-07-03 10
......
package com.wangxiaolu.export.service;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityPhotoDO;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityReportedDO;
import java.util.List;
import java.util.Map;
/**
* @author : liqiulin
* @date : 2024-07-29 15
* @describe :
*/
public interface ActivityToFeishuSheetService {
void activityDataToFeishuSheet(List<TemporaryActivityReportedDO> reportedDos, Map<Long, List<TemporaryActivityPhotoDO>> activityPhotos, Map<String, List<TemporaryActivityPhotoDO>> clockPhotoMap);
}
package com.wangxiaolu.export.service.impl;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.wangxiaolu.export.mapper.FeishuSheetRecordMapper;
import com.wangxiaolu.export.mapper.entity.FeishuSheetRecordDO;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityPhotoDO;
import com.wangxiaolu.export.mapper.entity.TemporaryActivityReportedDO;
import com.wangxiaolu.export.service.ActivityToFeishuSheetService;
import com.wangxiaolu.export.util.FeishuSheetUtils;
import com.wangxiaolu.promotion.common.redis.RedisKeys;
import com.wangxiaolu.promotion.common.redis.service.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author : liqiulin
* @date : 2024-07-29 15
* @describe :
*/
@Slf4j
@Service
public class ActivityToFeishuSheetServiceImpl implements ActivityToFeishuSheetService {
private static FeishuSheetRecordDO sheetInfoD = null;
@Value("${feishu.activity_robot_1.app_id}")
private String appId1;
@Value("${feishu.activity_robot_1.app_secret}")
private String appSecret1;
@Value("${feishu.activity_robot_2.app_id}")
private String appId2;
@Value("${feishu.activity_robot_2.app_secret}")
private String appSecret2;
@Autowired
RedisCache redisCache;
@Autowired
FeishuSheetUtils feishuSheetUtils;
@Autowired
FeishuSheetRecordMapper feishuSheetRecordMapper;
@Override
public void activityDataToFeishuSheet(List<TemporaryActivityReportedDO> reportedDos, Map<Long, List<TemporaryActivityPhotoDO>> activityPhotos, Map<String, List<TemporaryActivityPhotoDO>> clockPhotoMap) {
sheetInfoD = null;
// 查询要更新的电子表格、工作表,每天晚上10点开始更新,所以获取当前日期
String month = DateUtil.format(new Date(), "yyyy-MM");
FeishuSheetRecordDO sheetInfo = feishuSheetRecordMapper.selectOneByCreateMonth(month);
if (Objects.isNull(sheetInfo)) {
log.error("电子文档token信息获取失败,取消上传");
return;
}
sheetInfoD = sheetInfo;
log.info("上传至电子文档中的活动记录共「{}」条", reportedDos.size());
int index = 1;
for (TemporaryActivityReportedDO rdo : reportedDos) {
log.info("------- 上传标号{} start -------", index);
try {
// [temporaryId]-[createDate]: 做唯一key
String clockKey = rdo.getTemporaryId() + "-" + rdo.getCreateDate();
List<TemporaryActivityPhotoDO> temporaryActivityPhotoDOS = activityPhotos.get(rdo.getId());
List<TemporaryActivityPhotoDO> activityClock = clockPhotoMap.containsKey(clockKey) ? clockPhotoMap.get(clockKey) : new ArrayList<>();
activityDataToSheetRow(rdo, temporaryActivityPhotoDOS, activityClock);
} catch (Exception e) {
log.error("上传标号{}报错,跳过此次上传,上传数据:{}", index,JSONObject.toJSONString(rdo));
}
log.info("------- 上传标号{} end -------", index);
++index;
}
}
/**
* 组装单个活动记录,对应表格中的一行数据
*
* @param rdo 活动数据
* @param temporaryActivityPhotoDOS 活动中涉及到的照片(推广、POS)
* @param activityClock(打卡照片)
*/
private void activityDataToSheetRow(TemporaryActivityReportedDO rdo, List<TemporaryActivityPhotoDO> temporaryActivityPhotoDOS, List<TemporaryActivityPhotoDO> activityClock) throws Exception {
List<Object> row = new ArrayList<>();
// 证明标识(请忽略),一定要在开头第一个单元格有数据,才能保证之后的数据即使缺失也不会串行
row.add("0");
// 月份
String createDate = rdo.getCreateDate();
String[] dateArr = createDate.split("-");
// 战区
row.add(rdo.getOrgName());
// 城市经理
row.add(rdo.getApproveName());
// 执行城市
row.add(rdo.getCity());
// 执行日期
row.add(dateArr[1] + "月" + dateArr[2] + "日");
// 场次
row.add("1");
// 系统名称
row.add(rdo.getLineName());
// 门店名称
row.add(rdo.getStoreName());
// 活动形式
row.add(rdo.getActivityPattern());
// 推广活动销额(元)
row.add("0");
// 上传文本数据
addactivityDataRow(row);
String rowNumStr = redisCache.get(getRowNumRedisKey());
if (StringUtils.isBlank(rowNumStr)) {
log.error("行标识[{}]为未发生改变,当前行不做图片处理,上传数据:{}", rowNumStr, row.toString());
return;
}
/**
* 获取推广、POS图片
*/
Map<Integer, List<TemporaryActivityPhotoDO>> photoTypeMap = new HashMap<>();
if (!CollectionUtils.isEmpty(temporaryActivityPhotoDOS)) {
photoTypeMap = temporaryActivityPhotoDOS.stream().collect(Collectors.groupingBy(TemporaryActivityPhotoDO::getType));
}
String rangFormat = sheetInfoD.getSheetId() + "!%s" + rowNumStr + ":%s" + rowNumStr;
/**
* 推广照>> 真实pos证明反馈
*/
List<TemporaryActivityPhotoDO> photosType7 = Objects.isNull(photoTypeMap.get(7)) ? new ArrayList<>() : photoTypeMap.get(7);
int photosType7Size = photosType7.size();
// 真实pos证明反馈1 >>> K
if (!(photosType7Size < 1 || Objects.isNull(photosType7.get(0)))) {
valuesImageToSheet(String.format(rangFormat, "K", "K"), photosType7.get(0).getPhotoUrl());
}
// 真实pos证明反馈2 >>> L
if (!(photosType7Size < 2 || Objects.isNull(photosType7.get(1)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "L", "L"), photosType7.get(1).getPhotoUrl());
}
// 真实pos证明反馈3 >>> M
if (!(photosType7Size < 3 || Objects.isNull(photosType7.get(2)))) {
valuesImageToSheet(String.format(rangFormat, "M", "M"), photosType7.get(2).getPhotoUrl());
}
// 真实pos证明反馈4 >>> N
if (!(photosType7Size < 4 || Objects.isNull(photosType7.get(3)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "N", "N"), photosType7.get(3).getPhotoUrl());
}
log.info("上传pos照片完成,行号:{}", rowNumStr);
/**
* 打卡照片
*/
Map<Integer, String> clockMap = activityClock.stream().collect(Collectors.toMap(TemporaryActivityPhotoDO::getType, TemporaryActivityPhotoDO::getPhotoUrl));
// 上班打卡照片 >>> O
if (clockMap.containsKey(4)) {
valuesImageToSheet(String.format(rangFormat, "O", "O"), clockMap.get(4));
}
// 午休下班打卡照片 >>> P
if (clockMap.containsKey(5)) {
valuesImageToSheetByRobot2(String.format(rangFormat, "P", "P"), clockMap.get(5));
}
// 午休上班打卡照片 >>> Q
if (clockMap.containsKey(6)) {
valuesImageToSheet(String.format(rangFormat, "Q", "Q"), clockMap.get(6));
}
// 下班打卡照片 >>> R
if (clockMap.containsKey(7)) {
valuesImageToSheetByRobot2(String.format(rangFormat, "R", "R"), clockMap.get(7));
}
log.info("上传打卡照片完成,行号:{}", rowNumStr);
/**
* 推广试吃照片
*/
List<TemporaryActivityPhotoDO> photosType1 = Objects.isNull(photoTypeMap.get(1)) ? new ArrayList<>() : photoTypeMap.get(1);
int photosType1Size = photosType1.size();
// 推广试吃照片1 >>> S
if (!(photosType1Size < 1 || Objects.isNull(photosType1.get(0)))) {
valuesImageToSheet(String.format(rangFormat, "S", "S"), photosType1.get(0).getPhotoUrl());
}
// 推广试吃照片2 >>> T
if (!(photosType1Size < 2 || Objects.isNull(photosType1.get(1)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "T", "T"), photosType1.get(1).getPhotoUrl());
}
// 推广试吃照片3 >>> U
if (!(photosType1Size < 3 || Objects.isNull(photosType1.get(2)))) {
valuesImageToSheet(String.format(rangFormat, "U", "U"), photosType1.get(2).getPhotoUrl());
}
// 推广试吃照片4 >>> V
if (!(photosType1Size < 4 || Objects.isNull(photosType1.get(3)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "V", "V"), photosType1.get(3).getPhotoUrl());
}
log.info("上传推广-试吃照片完成,行号:{}", rowNumStr);
/**
* 推广互动照片
*/
List<TemporaryActivityPhotoDO> photosType2 = Objects.isNull(photoTypeMap.get(2)) ? new ArrayList<>() : photoTypeMap.get(2);
int photosType2Size = photosType2.size();
// 推广互动照片1 >>> W
if (!(photosType2Size < 1 || Objects.isNull(photosType2.get(0)))) {
valuesImageToSheet(String.format(rangFormat, "W", "W"), photosType2.get(0).getPhotoUrl());
}
// 推广互动照片2 >>> X
if (!(photosType2Size < 2 || Objects.isNull(photosType2.get(1)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "X", "X"), photosType2.get(1).getPhotoUrl());
}
// 推广互动照片3 >>> Y
if (!(photosType2Size < 3 || Objects.isNull(photosType2.get(2)))) {
valuesImageToSheet(String.format(rangFormat, "Y", "Y"), photosType2.get(2).getPhotoUrl());
}
// 推广互动照片4 >>> Z
if (!(photosType2Size < 4 || Objects.isNull(photosType2.get(3)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "Z", "Z"), photosType2.get(3).getPhotoUrl());
}
log.info("上传推广-互动照片完成,行号:{}", rowNumStr);
/**
* 推广成交照片
*/
List<TemporaryActivityPhotoDO> photosType3 = Objects.isNull(photoTypeMap.get(3)) ? new ArrayList<>() : photoTypeMap.get(3);
int photosType3Size = photosType3.size();
// 推广成交照片1 >>> AA
if (!(photosType3Size < 1 || Objects.isNull(photosType3.get(0)))) {
valuesImageToSheet(String.format(rangFormat, "AA", "AA"), photosType3.get(0).getPhotoUrl());
}
// 推广成交照片2 >>> AB
if (!(photosType3Size < 2 || Objects.isNull(photosType3.get(1)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "AB", "AB"), photosType3.get(1).getPhotoUrl());
}
// 推广成交照片3 >>> AC
if (!(photosType3Size < 3 || Objects.isNull(photosType3.get(2)))) {
valuesImageToSheet(String.format(rangFormat, "AC", "AC"), photosType3.get(2).getPhotoUrl());
}
// 推广成交照片4 >>> AD
if (!(photosType3Size < 4 || Objects.isNull(photosType3.get(3)))) {
valuesImageToSheetByRobot2(String.format(rangFormat, "AD", "AD"), photosType3.get(3).getPhotoUrl());
}
log.info("上传推广-成交照片完成,行号:{}", rowNumStr);
}
private void addactivityDataRow(List<Object> rowData) {
String redisKey = getRowNumRedisKey();
String rowNumStr = redisCache.get(redisKey);
Integer rowNumNext = StringUtils.isBlank(rowNumStr) ? 2 : Integer.parseInt(rowNumStr) + 1;
String range = sheetInfoD.getSheetId() + "!A" + rowNumNext + ":J" + rowNumNext;
Integer rowNumEnd = feishuSheetUtils.appendValueToSheet(range, rowData, sheetInfoD.getSheetToken(), getFeishuTenantToken1());
if (rowNumEnd < 1) {
redisCache.removeKey(redisKey);
} else {
redisCache.addToMinute(redisKey, rowNumEnd + "", 60);
}
log.info("修改文档行号:{}", rowNumEnd);
}
private void valuesImageToSheet(String range, String photoUrl) {
feishuSheetUtils.valuesImageToSheet(range, photoUrl, sheetInfoD.getSheetToken(), getFeishuTenantToken1());
}
// @Async
private void valuesImageToSheetByRobot2(String range, String photoUrl) {
feishuSheetUtils.valuesImageToSheet(range, photoUrl, sheetInfoD.getSheetToken(), getFeishuTenantToken2());
}
private String getFeishuTenantToken1() {
String tokenKey = RedisKeys.ExportKeys.FEISHU_TENANT_TOKEN_ACTIVITY_ROBOT_1.getKey();
String token = redisCache.get(tokenKey);
if (StringUtils.isNotBlank(token)) {
return token;
}
JSONObject tokenObj = feishuSheetUtils.getFeishuTenantToken(appId1, appSecret1);
token = tokenObj.getString("tenant_access_token");
Integer expire = tokenObj.getInteger("expire");
if (expire <= 110) {
throw new RuntimeException("获取1号机器人tenant_access_token错误,有效期过短" + tokenObj);
}
redisCache.addToSeconds(tokenKey, token, expire - 100);
return token;
}
private String getFeishuTenantToken2() {
String tokenKey = RedisKeys.ExportKeys.FEISHU_TENANT_TOKEN_ACTIVITY_ROBOT_2.getKey();
String token = redisCache.get(tokenKey);
if (StringUtils.isNotBlank(token)) {
return token;
}
JSONObject tokenObj = feishuSheetUtils.getFeishuTenantToken(appId2, appSecret2);
token = tokenObj.getString("tenant_access_token");
Integer expire = tokenObj.getInteger("expire");
if (expire <= 110) {
throw new RuntimeException("获取2号机器人tenant_access_token错误,有效期过短" + tokenObj);
}
redisCache.addToSeconds(tokenKey, token, expire - 100);
return token;
}
private String getRowNumRedisKey() {
String key = RedisKeys.ExportKeys.ACTIVITY_REPORTED_PUSH_FEISHU_SHEET.getKey();
return key + DateUtil.today();
}
}
...@@ -718,28 +718,39 @@ public class ExcelUtils { ...@@ -718,28 +718,39 @@ public class ExcelUtils {
Map<String, List<List<Object>>> sheetMap, Map<Integer, List<String>> selectMap) { Map<String, List<List<Object>>> sheetMap, Map<Integer, List<String>> selectMap) {
// 整个 Excel 表格 book 对象 // 整个 Excel 表格 book 对象
SXSSFWorkbook book = new SXSSFWorkbook(); SXSSFWorkbook book = new SXSSFWorkbook();
// 每个 Sheet 页 // 设置表头背景色(灰色)
CellStyle headStyle = book.createCellStyle();
headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index);
headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headStyle.setAlignment(HorizontalAlignment.CENTER);
headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
// 设置表身背景色(默认色)
CellStyle rowStyle = book.createCellStyle();
rowStyle.setAlignment(HorizontalAlignment.CENTER);
rowStyle.setVerticalAlignment(VerticalAlignment.CENTER);
/**
* 每个 Sheet 页
*/
System.out.println("2:"+System.currentTimeMillis());
Set<Entry<String, List<List<Object>>>> entries = sheetMap.entrySet(); Set<Entry<String, List<List<Object>>>> entries = sheetMap.entrySet();
for (Entry<String, List<List<Object>>> entry : entries) { for (Entry<String, List<List<Object>>> entry : entries) {
List<List<Object>> sheetDataList = entry.getValue(); List<List<Object>> sheetDataList = entry.getValue();
Sheet sheet = book.createSheet(entry.getKey()); Sheet sheet = book.createSheet(entry.getKey());
Drawing<?> patriarch = sheet.createDrawingPatriarch(); Drawing<?> patriarch = sheet.createDrawingPatriarch();
// 设置表头背景色(灰色)
CellStyle headStyle = book.createCellStyle();
headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index);
headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headStyle.setAlignment(HorizontalAlignment.CENTER);
headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
// 设置表身背景色(默认色)
CellStyle rowStyle = book.createCellStyle();
rowStyle.setAlignment(HorizontalAlignment.CENTER);
rowStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置表格列宽度(默认为15个字节) // 设置表格列宽度(默认为15个字节)
sheet.setDefaultColumnWidth(15); sheet.setDefaultColumnWidth(15);
// 创建合并算法数组 // 创建合并算法数组
int rowLength = sheetDataList.size(); int rowLength = sheetDataList.size();
int columnLength = sheetDataList.get(0).size(); int columnLength = sheetDataList.get(0).size();
int[][] mergeArray = new int[rowLength][columnLength]; int[][] mergeArray = new int[rowLength][columnLength];
/**
* 每一行
*/
System.out.println("3:"+System.currentTimeMillis());
for (int i = 0; i < sheetDataList.size(); i++) { for (int i = 0; i < sheetDataList.size(); i++) {
// 每个 Sheet 页中的行数据 // 每个 Sheet 页中的行数据
Row row = sheet.createRow(i); Row row = sheet.createRow(i);
...@@ -764,10 +775,12 @@ public class ExcelUtils { ...@@ -764,10 +775,12 @@ public class ExcelUtils {
mergeArray[i][j] = v; mergeArray[i][j] = v;
} }
} }
System.out.println("4:"+System.currentTimeMillis());
// 合并单元格 // 合并单元格
mergeCells(sheet, mergeArray); mergeCells(sheet, mergeArray);
// 设置下拉列表 // 设置下拉列表
setSelect(sheet, selectMap); setSelect(sheet, selectMap);
System.out.println("5:"+System.currentTimeMillis());
} }
// 写数据 // 写数据
if (response != null) { if (response != null) {
...@@ -790,6 +803,7 @@ public class ExcelUtils { ...@@ -790,6 +803,7 @@ public class ExcelUtils {
e.printStackTrace(); e.printStackTrace();
} }
} }
System.out.println("6:"+System.currentTimeMillis());
} }
/** /**
......
package com.wangxiaolu.export.util;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.wangxiaolu.promotion.common.util.NumberUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.net.ssl.HttpsURLConnection;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author : liqiulin
* @date : 2024-07-29 14
* @describe :
*/
@Slf4j
@Component
public class FeishuSheetUtils {
private static final String CONTENT_TYPE = "application/json; charset=utf-8";
private static final String SHEET_URL = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/";
private static final String TENANT_ACCESS_TOKEN_URL = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
private static final String VALUES_APPEND = "/values_append";
private static final String VALUES_IMAGE = "/values_image";
/**
* 追加一条记录
*
* @return 修改的行号
*/
public Integer appendValueToSheet(String range, List<Object> datas, String sheetToken,String autoToken) {
// 组装参数
Map<String, Map<String, Object>> bodyMap = new HashMap<>();
Map<String, Object> valueRange = new HashMap<>();
valueRange.put("range", range);
valueRange.put("values", Arrays.asList(datas));
bodyMap.put("valueRange", valueRange);
String bodyJson = JSONObject.toJSONString(bodyMap);
// body上传
String result = HttpUtil.createPost(SHEET_URL + sheetToken + VALUES_APPEND)
.auth("Bearer "+ autoToken).contentType(CONTENT_TYPE)
.body(bodyJson)
.execute().body();
// 上传结果判断
JSONObject resultJson = JSONObject.parseObject(result);
int code = resultJson.getInteger("code");
if (code != 0) {
log.error("活动上报错误:==============\n{}", result);
log.error("请求参数:==============\n{}", bodyJson);
return -1;
}
// 此次上传数据范围
String tableRange = resultJson.getJSONObject("data").getString("tableRange");
return NumberUtils.matcherNum(tableRange.split(":")[1]);
}
public void valuesImageToSheet(String range, String imageUrl, String sheetToken,String autoToken) {
if (StringUtils.isBlank(imageUrl) || !imageUrl.startsWith("https")) {
return;
}
try {
// 获取图片二进制流
byte[] imageByte = imageToByte(imageUrl);
// 组装参数
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("range", range);
bodyMap.put("image", imageByte);
bodyMap.put("name", imageUrl);
String bodyJson = JSONObject.toJSONString(bodyMap);
// 上传boday
String result = HttpUtil.createPost(SHEET_URL + sheetToken + VALUES_IMAGE)
.auth("Bearer "+ autoToken).contentType(CONTENT_TYPE)
.body(bodyJson)
.execute().body();
// 判断上传结果
JSONObject resultJson = JSONObject.parseObject(result);
int code = resultJson.getInteger("code");
if (code != 0) {
log.error("图片上传错误,上传表格位置:{},报错详情:\n{}", range, result);
}
} catch (Exception e) {
log.error("图片转换/上传异常,上传表格位置:{}", range);
}
}
public JSONObject getFeishuTenantToken(String appId,String appSecret) {
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("app_id", appId);
bodyMap.put("app_secret", appSecret);
String bodyJson = JSONObject.toJSONString(bodyMap);
String result = HttpUtil.createPost(TENANT_ACCESS_TOKEN_URL)
.contentType(CONTENT_TYPE)
.body(bodyJson)
.execute().body();
JSONObject resultJson = JSONObject.parseObject(result);
int code = resultJson.getInteger("code");
if (code != 0) {
throw new RuntimeException("获取tenant_access_token错误");
}
return resultJson;
}
private byte[] imageToByte(String fileUrl) throws Exception {
URL url = new URL(fileUrl);
// 打开链接,并且跳过 SSL 证书验证
HttpsUtils.trustAllHttpsCertificates();
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5 * 1000);
// 通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
// 得到文件的二进制数据,以二进制封装得到数据,具有通用性
byte[] data = readInputStream(inStream);
// 关闭流
inStream.close();
return data;
}
private byte[] readInputStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
// 每次读取的字符串长度,如果为-1,代表全部读取完毕
int len = 0;
// 使用一个输入流从buffer里把数据读取出来
while ((len = inStream.read(buffer)) != -1) {
// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len);
}
// 关闭输入流
inStream.close();
// 把outStream里的数据写入内存
return outStream.toByteArray();
}
}
package com.wangxiaolu.export.util;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
/**
* @author : liqiulin
* @date : 2024-07-29 14
* @describe :
*/
public class HttpsUtils {
// 设置 https 请求
public static void trustAllHttpsCertificates() throws Exception {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String str, SSLSession session) {
return true;
}
});
javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
javax.net.ssl.TrustManager tm = new miTM();
trustAllCerts[0] = tm;
javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
.getInstance("SSL");
sc.init(null, trustAllCerts, null);
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
}
// 设置 https 请求证书
static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(
java.security.cert.X509Certificate[] certs) {
return true;
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws java.security.cert.CertificateException {
return;
}
}
}
...@@ -5,11 +5,11 @@ spring: ...@@ -5,11 +5,11 @@ spring:
url: jdbc:mysql://bj-cdb-j8ppdy86.sql.tencentcdb.com:63569/promotion_dev?autoReconnect=true url: jdbc:mysql://bj-cdb-j8ppdy86.sql.tencentcdb.com:63569/promotion_dev?autoReconnect=true
username: LnNDBM username: LnNDBM
password: fd0%bhD4@oO(% password: fd0%bhD4@oO(%
# redis: redis:
# port: 21101 port: 21101
# host: bj-crs-oyzhz3c6.sql.tencentcdb.com host: bj-crs-oyzhz3c6.sql.tencentcdb.com
# database: 0 database: 0
# password: u)R3jrHk(qwt~mv$Tg=U password: u)R3jrHk(qwt~mv$Tg=U
cloud: cloud:
nacos: nacos:
...@@ -24,4 +24,25 @@ logging: ...@@ -24,4 +24,25 @@ logging:
# mybatis-plus 控制台打印sql日志 # mybatis-plus 控制台打印sql日志
mybatis-plus: mybatis-plus:
configuration: configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
wx:
miniapp:
configs:
- appid:
secret:
token: #微信小程序消息服务器配置的token
aesKey: #微信小程序消息服务器配置的EncodingAESKey
msgDataFormat:
temporary:
token_secret:
employee:
token_secret:
feishu:
activity_robot_1:
app_id: cli_a622204c69e8100b
app_secret: qzezaWe7Kxd61quiU9zRIf7COb4piEkF
activity_robot_2:
app_id: cli_a6220d5dcadf900b
app_secret: WeVaZ6yGXFEON6Lkl53rFdhHc8beQF1Y
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxiaolu.export.mapper.FeishuSheetRecordMapper">
<resultMap id="BaseResultMap" type="com.wangxiaolu.export.mapper.entity.FeishuSheetRecordDO">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="sheetToken" column="sheet_token" jdbcType="VARCHAR"/>
<result property="sheetId" column="sheet_id" jdbcType="VARCHAR"/>
<result property="createMonth" column="create_month" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,sheet_token,sheet_id,
create_month,create_time
</sql>
<select id="selectOneByCreateMonth" resultMap="BaseResultMap">
select sheet_token, sheet_id
from feishu_sheet_record
where create_month = #{month}
</select>
</mapper>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论