Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
W
wangxiaolu-export
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
promotion
wangxiaolu-export
Commits
a5cce210
提交
a5cce210
authored
7月 31, 2024
作者:
000516
提交者:
Coding
7月 31, 2024
浏览文件
操作
浏览文件
下载
差异文件
活动记录上传飞书
Merge Request: 活动记录上传飞书 Created By: @李秋林 Accepted By: @李秋林 URL:
https://g-pkkp8204.coding.net/p/promotion/d/wangxiaolu-export/git/merge/78?initial=true
上级
1ec437cd
e57adfc6
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
802 行增加
和
22 行删除
+802
-22
WangxiaoluExportApplication.java
...va/com/wangxiaolu/export/WangxiaoluExportApplication.java
+9
-1
ActivityToFeishuSheet.java
...iaolu/export/controller/feishu/ActivityToFeishuSheet.java
+68
-0
PromotionActivityExport.java
.../export/controller/promotion/PromotionActivityExport.java
+2
-0
FeishuSheetRecordMapper.java
...com/wangxiaolu/export/mapper/FeishuSheetRecordMapper.java
+24
-0
FeishuSheetRecordDO.java
.../wangxiaolu/export/mapper/entity/FeishuSheetRecordDO.java
+47
-0
ActivityVo.java
src/main/java/com/wangxiaolu/export/pojo/ActivityVo.java
+0
-3
ActivityToFeishuSheetService.java
...ngxiaolu/export/service/ActivityToFeishuSheetService.java
+16
-0
ActivityToFeishuSheetServiceImpl.java
...export/service/impl/ActivityToFeishuSheetServiceImpl.java
+340
-0
ExcelUtils.java
src/main/java/com/wangxiaolu/export/util/ExcelUtils.java
+25
-11
FeishuSheetUtils.java
...ain/java/com/wangxiaolu/export/util/FeishuSheetUtils.java
+153
-0
HttpsUtils.java
src/main/java/com/wangxiaolu/export/util/HttpsUtils.java
+65
-0
application-dev.yml
src/main/resources/application-dev.yml
+28
-7
FeishuSheetRecordMapper.xml
src/main/resources/mapper/FeishuSheetRecordMapper.xml
+25
-0
没有找到文件。
src/main/java/com/wangxiaolu/export/WangxiaoluExportApplication.java
浏览文件 @
a5cce210
package
com
.
wangxiaolu
.
export
;
import
org.mybatis.spring.annotation.MapperScan
;
import
org.springframework.boot.SpringApplication
;
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
static
void
main
(
String
[]
args
)
{
...
...
src/main/java/com/wangxiaolu/export/controller/feishu/ActivityToFeishuSheet.java
0 → 100644
浏览文件 @
a5cce210
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
()
+
") =============="
);
}
}
src/main/java/com/wangxiaolu/export/controller/promotion/PromotionActivityExport.java
浏览文件 @
a5cce210
...
...
@@ -211,7 +211,9 @@ public class PromotionActivityExport {
});
log
.
info
(
"活动记录数据处理完成,开始导出"
);
System
.
out
.
println
(
"1:"
+
System
.
currentTimeMillis
());
ExcelUtils
.
export
(
response
,
"活动数据导出_"
+
DateUtil
.
today
(),
sheet
);
System
.
out
.
println
(
"7:"
+
System
.
currentTimeMillis
());
log
.
info
(
"============== 活动记录导出 end =============="
);
}
...
...
src/main/java/com/wangxiaolu/export/mapper/FeishuSheetRecordMapper.java
0 → 100644
浏览文件 @
a5cce210
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
);
}
src/main/java/com/wangxiaolu/export/mapper/entity/FeishuSheetRecordDO.java
0 → 100644
浏览文件 @
a5cce210
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
src/main/java/com/wangxiaolu/export/pojo/ActivityVo.java
浏览文件 @
a5cce210
package
com
.
wangxiaolu
.
export
.
pojo
;
import
cn.hutool.core.date.DateTime
;
import
lombok.Data
;
import
java.util.Date
;
/**
* @author : liqiulin
* @date : 2024-07-03 10
...
...
src/main/java/com/wangxiaolu/export/service/ActivityToFeishuSheetService.java
0 → 100644
浏览文件 @
a5cce210
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
);
}
src/main/java/com/wangxiaolu/export/service/impl/ActivityToFeishuSheetServiceImpl.java
0 → 100644
浏览文件 @
a5cce210
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
();
}
}
src/main/java/com/wangxiaolu/export/util/ExcelUtils.java
浏览文件 @
a5cce210
...
...
@@ -718,28 +718,39 @@ public class ExcelUtils {
Map
<
String
,
List
<
List
<
Object
>>>
sheetMap
,
Map
<
Integer
,
List
<
String
>>
selectMap
)
{
// 整个 Excel 表格 book 对象
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
();
for
(
Entry
<
String
,
List
<
List
<
Object
>>>
entry
:
entries
)
{
List
<
List
<
Object
>>
sheetDataList
=
entry
.
getValue
();
Sheet
sheet
=
book
.
createSheet
(
entry
.
getKey
());
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个字节)
sheet
.
setDefaultColumnWidth
(
15
);
// 创建合并算法数组
int
rowLength
=
sheetDataList
.
size
();
int
columnLength
=
sheetDataList
.
get
(
0
).
size
();
int
[][]
mergeArray
=
new
int
[
rowLength
][
columnLength
];
/**
* 每一行
*/
System
.
out
.
println
(
"3:"
+
System
.
currentTimeMillis
());
for
(
int
i
=
0
;
i
<
sheetDataList
.
size
();
i
++)
{
// 每个 Sheet 页中的行数据
Row
row
=
sheet
.
createRow
(
i
);
...
...
@@ -764,10 +775,12 @@ public class ExcelUtils {
mergeArray
[
i
][
j
]
=
v
;
}
}
System
.
out
.
println
(
"4:"
+
System
.
currentTimeMillis
());
// 合并单元格
mergeCells
(
sheet
,
mergeArray
);
// 设置下拉列表
setSelect
(
sheet
,
selectMap
);
System
.
out
.
println
(
"5:"
+
System
.
currentTimeMillis
());
}
// 写数据
if
(
response
!=
null
)
{
...
...
@@ -790,6 +803,7 @@ public class ExcelUtils {
e
.
printStackTrace
();
}
}
System
.
out
.
println
(
"6:"
+
System
.
currentTimeMillis
());
}
/**
...
...
src/main/java/com/wangxiaolu/export/util/FeishuSheetUtils.java
0 → 100644
浏览文件 @
a5cce210
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
();
}
}
src/main/java/com/wangxiaolu/export/util/HttpsUtils.java
0 → 100644
浏览文件 @
a5cce210
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
;
}
}
}
src/main/resources/application-dev.yml
浏览文件 @
a5cce210
...
...
@@ -5,11 +5,11 @@ spring:
url
:
jdbc:mysql://bj-cdb-j8ppdy86.sql.tencentcdb.com:63569/promotion_dev?autoReconnect=true
username
:
LnNDBM
password
:
fd0%bhD4@oO(%
#
redis:
#
port: 21101
#
host: bj-crs-oyzhz3c6.sql.tencentcdb.com
#
database: 0
#
password: u)R3jrHk(qwt~mv$Tg=U
redis
:
port
:
21101
host
:
bj-crs-oyzhz3c6.sql.tencentcdb.com
database
:
0
password
:
u)R3jrHk(qwt~mv$Tg=U
cloud
:
nacos
:
...
...
@@ -24,4 +24,25 @@ logging:
# mybatis-plus 控制台打印sql日志
mybatis-plus
:
configuration
:
log-impl
:
org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
log-impl
:
org.apache.ibatis.logging.stdout.StdOutImpl
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
src/main/resources/mapper/FeishuSheetRecordMapper.xml
0 → 100644
浏览文件 @
a5cce210
<?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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论