Compare commits

...

155 Commits

Author SHA1 Message Date
c2ce6f91ed 日志调整 2025-06-13 16:55:11 +08:00
da3de2cc89 缓存时间调整 2025-06-13 15:36:29 +08:00
d245d09837 支持跳过景区文件删除,跳过重复adapter 2025-06-13 15:36:29 +08:00
4d8236afa1 通过identity定义是否相同 2025-06-13 15:35:11 +08:00
04e2ade669 添加锁避免高并发冲突 2025-06-13 15:35:11 +08:00
cd4678120d 修复删除逻辑 2025-06-13 15:35:11 +08:00
cf9802f9ec 添加后台订单筛选 2025-06-10 16:46:18 +08:00
a84b38dab5 推客统计 2025-06-10 16:46:18 +08:00
e32f231a8f 设备支持自定义标定区域 2025-06-10 16:46:18 +08:00
f9fcb06355 根据经纬度查询景区,并添加查询所有景区的功能 2025-06-10 16:46:18 +08:00
2ae0b3c4b3 参数错误打印错误请求地址方便排查 2025-06-05 14:24:47 +08:00
3bd8face68 缓存统计信息 2025-06-04 13:46:10 +08:00
1841e43b85 1 2025-06-03 15:02:45 +08:00
a9655814ae 测试 2025-06-03 09:51:04 +08:00
c1b4bc8952 congmingPay:添加device参数 2025-06-03 09:50:43 +08:00
4bacdbe39a 返回null 2025-06-02 09:46:01 +08:00
4273cda7cd 调整 2025-06-02 09:46:01 +08:00
ceba1e1b01 没有vlog也切片 2025-06-02 09:46:01 +08:00
34dbc7d036 聪明付 2025-06-02 09:46:01 +08:00
89e112e13a 返回null 2025-06-02 09:42:31 +08:00
26a9be80f6 不要删除人脸样本还有的素材 2025-06-02 09:42:15 +08:00
a4a6e9b5af 使用urI 2025-05-30 17:25:28 +08:00
0d5aabe317 1 2025-05-30 17:25:28 +08:00
5d2cf4fd31 test~ 2025-05-30 17:25:28 +08:00
80f4491836 Java21 2025-05-30 17:25:28 +08:00
115edc19fa Deprecated 2025-05-30 09:37:13 +08:00
bfd37fc764 逻辑修正 2025-05-30 09:35:24 +08:00
ef0ba3ddb4 sb aws 2025-05-29 14:35:47 +08:00
88cce9357d 删除无用代码 2025-05-29 14:33:35 +08:00
c50cd84af0 jvm21! 2025-05-29 14:26:42 +08:00
0c40cdad4e 1 2025-05-29 09:55:18 +08:00
a41b87713f 清理删除逻辑优化 2025-05-29 01:03:57 +08:00
06a07514cc 对景区摄像头进行统计 2025-05-27 16:23:47 +08:00
0292b754fe 统计 2025-05-26 17:29:13 +08:00
460b4ea42a broker 2025-05-26 15:46:42 +08:00
7fd62e9aba 微信获取手机号 2025-05-25 16:31:13 +08:00
3b3c768bbe 打印 2025-05-25 16:31:04 +08:00
1e993c6fd4 避免返回videoId未null 2025-05-25 13:56:47 +08:00
937c2b33d3 照片打印 2025-05-22 14:05:40 +08:00
9b00b34a68 不要删除已经购买了的人脸 2025-05-21 17:01:56 +08:00
c01ff160c3 水印,使用设备名称 2025-05-21 16:47:25 +08:00
aaddbab2ab 照片打印,基础 2025-05-21 15:35:44 +08:00
570267fd83 调整 2025-05-19 15:45:05 +08:00
44e0f4933b 打印 2025-05-19 15:03:36 +08:00
ab2be3d56b 兼容 2025-05-16 15:31:25 +08:00
077698cdaa 文件夹名称 2025-05-12 18:39:44 +08:00
b141b39e50 删除无用内容 2025-05-12 18:38:20 +08:00
c366495805 调整下清理时机 2025-05-12 18:17:44 +08:00
870e79cde5 统计方法 2025-05-10 17:32:42 +08:00
2bf8bb4df5 更新,sourceId传入无需传url 2025-05-09 10:30:55 +08:00
164e76495e 删除无用字段 2025-05-08 17:32:47 +08:00
d9360acb5f bug 2025-05-08 17:32:47 +08:00
2e92cf5c91 人脸真实删除、清理逻辑优化 2025-05-08 17:32:47 +08:00
ef978529ac 1 2025-05-04 10:51:27 +08:00
6197f13e8e 统计不统计 2025-04-30 18:29:24 +08:00
00f38c949c 模板支持相同机位 2025-04-30 18:29:14 +08:00
c45dffa0a0 统计修一修 2025-04-30 18:28:36 +08:00
f8f49891a5 删除无用内容 2025-04-30 18:28:24 +08:00
7771f85618 2 2025-04-27 14:17:20 +08:00
7583c9e22e 统计调整 2025-04-27 04:36:12 +08:00
bb26fa43bf 当价格配置未命中缓存时,不返回空 2025-04-27 04:36:12 +08:00
46a8b254b5 添加支付异常提示 2025-04-27 04:36:12 +08:00
2e41f72e0e 限制主动下载的速度 2025-04-27 04:36:12 +08:00
e9d80cecc7 支付,支持微信新的公钥支付模式 2025-04-27 04:36:12 +08:00
5a4f6a5af3 几个高频/轮询接口迁走了 2025-04-27 04:36:12 +08:00
8ef2ef4b15 避免空指针、水印并发加,让前端更好展示大锁页面 2025-04-22 10:28:45 +08:00
3863c0d963 渲染机支持配置存储地址 2025-04-20 15:06:02 +08:00
b36da6ff35 删除无用字段,后台添加更多商品信息 2025-04-17 17:59:13 +08:00
da20a44049 景区设置添加一个,返回status状态 2025-04-17 10:49:31 +08:00
877f37b6f9 系统支付对接、避免返回过多数据 2025-04-17 10:49:31 +08:00
f6f847e41c 支付 2025-04-17 10:49:11 +08:00
8ac386242d 多给一天 2025-04-15 03:17:32 +08:00
3f11aadd75 1 2025-04-15 03:17:20 +08:00
d620bde5fa 补救措施没结果时,不使用补救措施结果 2025-04-15 03:17:14 +08:00
5a7c39429e bug 2025-04-15 03:13:13 +08:00
7234e08616 定时任务时支持补救措施 2025-04-12 19:08:23 +08:00
45409ba1ab 渲染机支持仅渲染几个景区的工作 2025-04-12 14:35:26 +08:00
b5b9064f30 区分临时和本地存储 2025-04-12 14:34:59 +08:00
d0d4e37526 修改 2025-04-11 16:58:52 +08:00
73d393b436 entityId格式 2025-04-09 10:05:39 +08:00
2835346447 多个wxMpConfig兼容 2025-04-08 16:24:33 +08:00
75eb3732fc 价格配置加个状态 2025-04-08 16:24:33 +08:00
692df3a1a2 避免null 2025-04-08 14:40:57 +08:00
fe0397af8e 统计:基础 2025-04-08 14:40:57 +08:00
f17e2364b6 entityId重入一致性 2025-04-08 14:40:57 +08:00
59978b6be5 修整代码 2025-04-08 14:40:57 +08:00
20d78cb487 不存request了 2025-04-08 14:32:45 +08:00
4e9d6807d6 再改改 2025-04-08 01:28:12 +08:00
8af8bd6bcf pc后台统计 2025-04-08 01:28:04 +08:00
248c06a30c 速率限制 2025-04-08 01:27:40 +08:00
dabdde33a6 空! 2025-04-07 16:36:45 +08:00
c9a4116ed6 捯饬捯饬代码 2025-04-07 16:36:45 +08:00
79ea08898b 加字段 2025-04-07 12:16:59 +08:00
52d0c4bc36 清理逻辑 2025-04-07 09:51:10 +08:00
84287df87b 避免重复创建 2025-04-07 09:51:03 +08:00
389c28300f 添加字段 2025-04-07 09:39:36 +08:00
10e7421672 统计优化 2025-04-07 09:38:41 +08:00
cf3a49d590 人脸搜索优化 2025-04-07 09:38:41 +08:00
083f67e516 数据库列表不允许返回null 2025-04-07 09:38:41 +08:00
3e53fd8367 订单接口支持memberId筛选 2025-04-07 09:38:41 +08:00
86d09134a6 接口调整,使用受限制的 2025-04-07 09:38:41 +08:00
082d8830bd 不重复生成二维码 2025-04-07 09:38:41 +08:00
d95c16aa01 百度云接口调整 2025-04-06 17:56:08 +08:00
a45929753f 删除手动添加限制 2025-04-06 17:56:08 +08:00
a46d4d8fac 添加exist 2025-04-06 17:56:08 +08:00
c8874064f0 初始化时吧所有的都用了 2025-04-06 17:56:08 +08:00
cecc7aa181 分设备队列 2025-04-06 17:56:08 +08:00
7cea8093c7 删除时添加token 2025-04-06 17:56:08 +08:00
ff82644f47 添加更多锁 2025-04-06 17:56:08 +08:00
b4aa3619ba 规整下代码 2025-04-05 16:42:46 +08:00
117a13cc2c 百度人脸识别 2025-04-05 16:42:46 +08:00
ab0f38cd97 逻辑调整 2025-04-05 14:48:12 +08:00
0ab142e1c4 修改 2025-04-05 13:27:20 +08:00
67dca0d4d4 人脸 2025-04-05 13:21:41 +08:00
36f1242e79 打印机 2025-04-03 15:56:01 +08:00
06ebc1d05e 删除realName相关 2025-04-01 16:50:47 +08:00
7d8483b6e4 打印机相关 2025-04-01 16:22:52 +08:00
dc7c4a13cb 统计bug 2025-04-01 16:22:27 +08:00
c963324cfb 景区删除逻辑 2025-03-31 18:52:47 +08:00
af2947e44a 退款订单列表信息 2025-03-31 18:19:49 +08:00
fcddc4fc8c 权限 2025-03-31 18:19:36 +08:00
da72e7e0a9 景区账号管理 2025-03-31 17:15:47 +08:00
d9619e6fea 列表显示商品内容、添加用户UID返回 2025-03-31 17:15:21 +08:00
938f9702ea 优惠券、通知加参数 2025-03-29 17:22:48 +08:00
4b03bfb871 1 2025-03-28 20:10:57 +08:00
80e93ecd39 价格 2025-03-28 16:23:35 +08:00
e128101563 人脸检索 2025-03-28 14:24:22 +08:00
a1eb29c49d 升级 2025-03-28 14:23:30 +08:00
48a3dfb313 AutoClosable 2025-03-26 14:31:11 +08:00
a08f4adf2d 时间线兜底逻辑 2025-03-25 12:43:42 +08:00
a0703e48c9 1 2025-03-25 12:43:42 +08:00
2b43d8a7b7 规整规整项目 2025-03-25 12:43:42 +08:00
decfe18b9a 添加游玩时间 2025-03-25 10:49:42 +08:00
9ec6825372 乱七八糟的调整,wx接口对其 2025-03-25 10:49:28 +08:00
f9a8a5f20e 优惠券 2025-03-23 17:45:53 +08:00
a5f67b1eac 任务调度修改 2025-03-23 17:45:38 +08:00
a8601548c6 图片可指定格式,可推荐格式,压缩 2025-03-19 17:56:18 +08:00
fd85b7ad77 修改接口,务必返回视频地址 2025-03-19 17:55:54 +08:00
bcf8e8e88d 设备关联逻辑 2025-03-19 16:57:33 +08:00
fb530a1eb4 统计添加注释 2025-03-19 16:57:25 +08:00
8a7021d759 下载逻辑换成内网地址 2025-03-19 16:57:25 +08:00
26dc53ca6a 加个普通水印、推送订单纠正、水印预览和下载 2025-03-19 16:57:25 +08:00
46f6532164 用常量 2025-03-17 18:37:37 +08:00
50a7c2e9c4 清理数据根据景区清理 2025-03-17 18:36:38 +08:00
f36416bad2 改下逻辑 2025-03-17 18:36:23 +08:00
180ba67de8 水印 2025-03-17 18:35:31 +08:00
7e8eebdef5 free 2025-03-17 18:35:31 +08:00
eac1c48cb2 支持别人看我的照片信息 2025-03-17 18:35:31 +08:00
0ae47d3f71 画画的 2025-03-17 18:35:31 +08:00
072a1a6131 一口价避免买到别人的东西(不展示) 2025-03-17 10:15:26 +08:00
aa4048ad26 订单,查询限制放宽 2025-03-17 09:50:30 +08:00
6bfff19c5a 删除无用内容 2025-03-14 17:01:54 +08:00
41aba63e5d 用户UID 2025-03-14 16:48:54 +08:00
05bc2773b9 3 2025-03-14 11:47:47 +08:00
c2ebbd71e2 2 2025-03-11 12:07:34 +08:00
363 changed files with 10574 additions and 6143 deletions

90
pom.xml
View File

@ -5,22 +5,22 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<version>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ycwl</groupId>
<artifactId>basic</artifactId>
<artifactId>basic21</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>liuying</name>
<description>流影</description>
<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<mybatisplus.boot.starter.version>3.4.0</mybatisplus.boot.starter.version>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<hutool-all.version>5.8.24</hutool-all.version>
<mysql-connector.version>8.0.33</mysql-connector.version>
<fastjson.version>1.2.83</fastjson.version>
<knife4j-spring-boot-starter.version>2.0.7</knife4j-spring-boot-starter.version>
<pagehelper.version>5.3.1</pagehelper.version>
@ -30,11 +30,18 @@
<dependencies>
<!-- 微信支付-->
<!-- 添加 jakarta.servlet-api 依赖 -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<!-- 微信支付 -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.12</version>
<version>0.2.14</version>
</dependency>
<!-- 引入aop相关 -->
<dependency>
@ -52,23 +59,13 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- 引入mysql连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
<scope>runtime</scope>
</dependency>
@ -78,6 +75,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@ -88,14 +90,14 @@
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.boot.starter.version}</version>
<version>3.5.5</version>
</dependency>
<!-- 引入lombok工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!--<scope>provided</scope>-->
<scope>provided</scope>
</dependency>
<!-- hutool工具类 -->
@ -159,17 +161,11 @@
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.22.0</version>
</dependency>
<!-- 阿里云对象存储 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
<version>3.18.0</version>
</dependency>
<!-- S3对象存储 -->
@ -188,21 +184,57 @@
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.6.1</version>
<version>4.6.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-facebody</artifactId>
<version>2.0.12</version>
</dependency>
<!-- 百度智能云人脸识别 -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.19</version>
</dependency>
</dependencies>
<build>
<resources>
<!-- 确保 src/main/resources 下的资源文件被包含 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.png</include> <!-- 明确包含 PNG 文件 -->
<include>**/*.ttf</include> <!-- 明确包含 TTF 文件 -->
<include>**/*</include> <!-- 包含其他所有资源文件 -->
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 跳过测试执行 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>${skipTests}</skip>
</configuration>
</plugin>
<!-- 跳过测试编译 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<testExcludes>
<testExclude>**/*Test.java</testExclude>
</testExcludes>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -1,11 +0,0 @@
package com.ycwl.basic.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
public @interface RequestToFile {
}

View File

@ -1,71 +0,0 @@
package com.ycwl.basic.aspectj;
import com.ycwl.basic.annotation.RequestToFile;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.stream.Collectors;
@Aspect
@Component
@Slf4j
public class HttpSaver {
@Pointcut("@annotation(com.ycwl.basic.annotation.RequestToFile)")
public void requestToFilePointCut() {
}
@After("requestToFilePointCut()")
public void requestToFile() throws IOException {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
saveRequestToFile(request);
}
public static void saveRequestToFile(HttpServletRequest request) throws IOException {
StringBuilder rawReq = new StringBuilder();
rawReq.append(request.getMethod()).append(" ").append(request.getRequestURL());
String queryString = request.getQueryString();
if (queryString != null) {
rawReq.append("?").append(queryString);
}
rawReq.append("\r\n");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
rawReq.append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
}
rawReq.append("\r\n");
// 获取body
try {
rawReq.append(request.getReader().lines().collect(Collectors.joining("\r\n")));
rawReq.append("\r\n");
} catch (IOException ignore) {
}
// 写入文件
File file = new File("./request/"+System.currentTimeMillis()+".http");
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
try (java.io.FileWriter writer = new java.io.FileWriter(file, true)) {
writer.write(rawReq.toString());
}
}
}

View File

@ -13,8 +13,8 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;

View File

@ -53,7 +53,7 @@ public class BrokerBiz {
expireDay = scenicConfig.getSampleStoreDay();
}
List<Long> brokerIdList = statisticsMapper.getBrokerIdListForUser(order.getMemberId(), DateUtil.offsetDay(DateUtil.beginOfDay(order.getCreateAt()), -expireDay), order.getCreateAt());
Long directBrokerId = brokerIdList.get(0);
Long directBrokerId = brokerIdList.getFirst();
List<BrokerRespVO> brokerInfoList = brokerIdList.stream().map(brokerId -> {
BrokerRespVO broker = brokerMapper.getById(brokerId);
if (broker == null) {
@ -77,7 +77,7 @@ public class BrokerBiz {
if (brokerInfoList.size() == 1) {
// 直接算佣金
String reason = "单人提成:";
BrokerRespVO broker = brokerInfoList.get(0);
BrokerRespVO broker = brokerInfoList.getFirst();
BrokerRecord brokerRecord = new BrokerRecord();
brokerRecord.setBrokerId(broker.getId());
brokerRecord.setOrderId(orderId);
@ -95,7 +95,7 @@ public class BrokerBiz {
brokerRecord.setReason(reason);
brokerRecordList.add(brokerRecord);
} else {
BrokerRespVO broker = brokerInfoList.get(0);
BrokerRespVO broker = brokerInfoList.getFirst();
BigDecimal realRate = broker.getBrokerRate();
BigDecimal brokerPrice = order.getPayPrice().multiply(realRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN);
// todo 需要计算实际提成比例
@ -141,9 +141,7 @@ public class BrokerBiz {
brokerRecordList.add(brokerRecord);
}
revokeOrder(orderId);
brokerRecordList.forEach(brokerRecord -> {
brokerRecordMapper.add(brokerRecord);
});
brokerRecordList.forEach(brokerRecordMapper::add);
}
public void revokeOrder(Long orderId) {

View File

@ -0,0 +1,91 @@
package com.ycwl.basic.biz;
import com.ycwl.basic.mapper.CouponMapper;
import com.ycwl.basic.mapper.CouponRecordMapper;
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
import com.ycwl.basic.model.pc.couponRecord.entity.CouponRecordEntity;
import com.ycwl.basic.model.pc.couponRecord.resp.CouponRecordQueryResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@Component
public class CouponBiz {
@Autowired
private CouponMapper couponMapper;
@Autowired
private CouponRecordMapper couponRecordMapper;
public CouponRecordQueryResp queryUserCouponRecord(Long scenicId, Long memberId, Long faceId, String goodsId) {
CouponRecordQueryResp resp = new CouponRecordQueryResp();
List<CouponRecordEntity> recordList = couponRecordMapper.queryByUserWithGoodsId(scenicId, memberId, goodsId);
if (recordList != null && !recordList.isEmpty()) {
Optional<CouponRecordEntity> record = recordList.stream().filter(item -> item.getStatus() == 0).filter(item -> item.getFaceId() == null || item.getFaceId().equals(faceId)).findAny();
if (record.isPresent()) {
CouponRecordEntity recordEntity = record.get();
resp.setExist(true);
resp.setId(recordEntity.getId());
resp.setCouponId(recordEntity.getCouponId());
CouponEntity coupon = couponMapper.getById(recordEntity.getCouponId());
if (coupon != null) {
resp.setMemberId(recordEntity.getMemberId());
resp.setFaceId(recordEntity.getFaceId());
resp.setStatus(recordEntity.getStatus());
resp.setCreateTime(recordEntity.getCreateTime());
resp.setUsedTime(recordEntity.getUsedTime());
resp.setUsedOrderId(recordEntity.getUsedOrderId());
resp.setCoupon(coupon);
} else {
resp.setExist(false);
}
} else {
Optional<CouponRecordEntity> usedRecord = recordList.stream().filter(item -> item.getStatus() != 0).filter(item -> item.getFaceId() == null || item.getFaceId().equals(faceId)).findAny();
if (usedRecord.isPresent()) {
CouponRecordEntity recordEntity = usedRecord.get();
resp.setExist(true);
resp.setId(recordEntity.getId());
resp.setCouponId(recordEntity.getCouponId());
CouponEntity coupon = couponMapper.getById(recordEntity.getCouponId());
if (coupon != null) {
resp.setMemberId(recordEntity.getMemberId());
resp.setFaceId(recordEntity.getFaceId());
resp.setStatus(recordEntity.getStatus());
resp.setCreateTime(recordEntity.getCreateTime());
resp.setUsedTime(recordEntity.getUsedTime());
resp.setUsedOrderId(recordEntity.getUsedOrderId());
resp.setCoupon(coupon);
} else {
resp.setExist(false);
}
}
}
}
return resp;
}
public boolean userGetCoupon(Long memberId, Long faceId, Integer couponId) {
CouponEntity coupon = couponMapper.getById(couponId);
if (coupon == null) {
return false;
}
CouponRecordEntity entity = new CouponRecordEntity();
entity.setCouponId(couponId);
entity.setFaceId(faceId);
entity.setMemberId(memberId);
entity.setStatus(0);
entity.setCreateTime(new Date());
return couponRecordMapper.insert(entity) > 0;
}
public boolean userUseCoupon(Long memberId, Long faceId, Integer couponRecordId, Long orderId) {
CouponRecordEntity entity = new CouponRecordEntity();
entity.setId(couponRecordId);
entity.setStatus(1);
entity.setUsedTime(new Date());
entity.setUsedOrderId(orderId);
return couponRecordMapper.updateById(entity) > 0;
}
}

View File

@ -8,6 +8,8 @@ import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
import com.ycwl.basic.model.pc.couponRecord.resp.CouponRecordQueryResp;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
@ -30,8 +32,10 @@ import com.ycwl.basic.repository.SourceRepository;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.repository.VideoRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.utils.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@ -70,6 +74,11 @@ public class OrderBiz {
private VideoTaskRepository videoTaskRepository;
@Autowired
private BrokerBiz brokerBiz;
@Autowired
private CouponBiz couponBiz;
@Autowired
@Lazy
private PrinterService printerService;
public PriceObj queryPrice(Long scenicId, int goodsType, Long goodsId) {
PriceObj priceObj = new PriceObj();
@ -124,6 +133,18 @@ public class OrderBiz {
return priceObj;
}
public OrderEntity hasTypeOrder(Long userId, Long scenicId, int orderType, Integer configId) {
OrderEntity orderEntity = orderMapper.queryTypeOrder(userId, scenicId, orderType, configId);
if (orderEntity == null) {
return null;
}
if (Integer.valueOf(1).equals(orderEntity.getStatus())) {
return orderEntity;
} else {
return null;
}
}
public IsBuyRespVO isBuy(Long userId, Long scenicId, int goodsType, Long goodsId) {
IsBuyRespVO respVO = new IsBuyRespVO();
boolean isBuy = orderRepository.checkUserBuyItem(userId, goodsType, goodsId);
@ -145,23 +166,19 @@ public class OrderBiz {
}
// 免费送逻辑,之前已经赠送了的
if (!isBuy) {
switch (goodsType) {
case 0:
isBuy = videoRepository.getUserIsBuy(userId, goodsId);
break;
case 1:
case 2:
isBuy = sourceRepository.getUserIsBuy(userId, goodsType, goodsId);
break;
}
isBuy = switch (goodsType) {
case 0 -> videoRepository.getUserIsBuy(userId, goodsId);
case 1, 2 -> sourceRepository.getUserIsBuy(userId, goodsType, goodsId);
default -> false;
};
} else {
OrderEntity orderEntity = orderRepository.getUserBuyItem(userId, goodsType, goodsId);
if (orderEntity != null) {
respVO.setOrderId(orderEntity.getId());
}
}
// 还是没买
respVO.setBuy(isBuy);
// 还是没买
if (!isBuy) {
PriceObj priceObj = queryPrice(scenicId, goodsType, goodsId);
if (priceObj == null) {
@ -170,8 +187,38 @@ public class OrderBiz {
respVO.setFree(priceObj.isFree());
respVO.setGoodsType(goodsType);
respVO.setGoodsId(goodsId);
respVO.setPrice(priceObj.getPrice());
respVO.setOrigPrice(priceObj.getPrice());
respVO.setSlashPrice(priceObj.getSlashPrice());
switch (goodsType) {
case 0: // vlog
VideoEntity video = videoRepository.getVideo(goodsId);
TaskEntity taskById = videoTaskRepository.getTaskById(video.getTaskId());
if (taskById != null) {
CouponRecordQueryResp recordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, taskById.getFaceId(), taskById.getTemplateId().toString());
if (recordQueryResp.isUsable()) {
respVO.setCouponId(recordQueryResp.getCouponId());
respVO.setCouponRecordId(recordQueryResp.getId());
CouponEntity coupon = recordQueryResp.getCoupon();
if (coupon != null) {
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceObj.getPrice()));
}
}
}
break;
case 1:
case 2:
CouponRecordQueryResp recordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, goodsId, String.valueOf(goodsType));
if (recordQueryResp.isUsable()) {
respVO.setCouponId(recordQueryResp.getCouponId());
respVO.setCouponRecordId(recordQueryResp.getId());
CouponEntity coupon = recordQueryResp.getCoupon();
if (coupon != null) {
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceObj.getPrice()));
}
}
break;
}
}
return respVO;
}
@ -191,9 +238,14 @@ public class OrderBiz {
case 1: // 视频原素材
case 2: // 照片原素材
sourceRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsType(), item.getGoodsId(), order.getId());
case 3:
printerService.setUserIsBuyItem(order.getMemberId(), item.getGoodsId(), order.getId());
}
});
orderRepository.clearOrderCache(orderId); // 更新完了,清理下
if (order.getCouponRecordId() != null) {
couponBiz.userUseCoupon(order.getMemberId(), order.getFaceId(), order.getCouponRecordId(), orderId);
}
//支付时间
OrderAppRespVO orderDetail = orderMapper.appDetail(orderId);
@ -201,7 +253,7 @@ public class OrderBiz {
//商品创建时间
Date goodsCreateTime = new Date();
if (!orderDetail.getOrderItemList().isEmpty()) {
OrderItemVO orderItemVO = orderDetail.getOrderItemList().get(0);
OrderItemVO orderItemVO = orderDetail.getOrderItemList().getFirst();
switch (orderItemVO.getGoodsType()) {
case 0:
VideoEntity video = videoRepository.getVideo(orderItemVO.getGoodsId());
@ -228,18 +280,12 @@ public class OrderBiz {
StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
statisticsRecordAddReq.setMemberId(order.getMemberId());
Calendar calendar = Calendar.getInstance();
calendar.setTime(goodsCreateTime);
calendar.set(Calendar.HOUR_OF_DAY, 21);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
// TODO: 他的购买的内容于内容生成当天晚9点之前算现场订单,否则算推送订单
if(calendar.getTime().compareTo(payAt)>0){//
Long enterType = statisticsMapper.getUserRecentEnterType(order.getMemberId(), order.getCreateAt());
if(!Long.valueOf(1014).equals(enterType)){//
statisticsRecordAddReq.setType(StatisticEnum.ON_SITE_PAYMENT.code);
}else {
statisticsRecordAddReq.setType(StatisticEnum.POST_PAYMENT.code);
}
calendar.clear();
statisticsRecordAddReq.setScenicId(order.getScenicId());
statisticsRecordAddReq.setMorphId(orderId);
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);

View File

@ -1,9 +1,15 @@
package com.ycwl.basic.biz;
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
import com.ycwl.basic.model.pc.couponRecord.resp.CouponRecordQueryResp;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.PriceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.TemplateRepository;
@ -11,6 +17,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -24,6 +31,12 @@ public class PriceBiz {
private ScenicRepository scenicRepository;
@Autowired
private PriceRepository priceRepository;
@Autowired
private OrderBiz orderBiz;
@Autowired
private FaceRepository faceRepository;
@Autowired
private CouponBiz couponBiz;
public List<GoodsListRespVO> listGoodsByScenic(Long scenicId) {
List<GoodsListRespVO> goodsList = new ArrayList<>();
@ -66,4 +79,65 @@ public class PriceBiz {
return false;
}).collect(Collectors.toList());
}
public IsBuyBatchRespVO isBuy(Long userId, Long faceId, Long scenicId, Integer type, String goodsIds) {
IsBuyBatchRespVO respVO = new IsBuyBatchRespVO();
PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(scenicId, type, goodsIds);
if (priceConfig == null) {
return null;
}
FaceEntity face = faceRepository.getFace(faceId);
if (face != null && !face.getMemberId().equals(userId)) {
return null;
}
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null) {
if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
// 景区全免
respVO.setFree(true);
respVO.setSlashPrice(BigDecimal.ZERO);
return respVO;
}
}
switch (type) {
case 0: // 单个定价
CouponRecordQueryResp recordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, faceId, goodsIds);
if (recordQueryResp.isUsable()) {
respVO.setCouponId(recordQueryResp.getCouponId());
respVO.setCouponRecordId(recordQueryResp.getId());
CouponEntity coupon = recordQueryResp.getCoupon();
if (coupon != null) {
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceConfig.getPrice()));
}
}
break;
case -1:
CouponRecordQueryResp oneCouponRecordQueryResp = couponBiz.queryUserCouponRecord(scenicId, userId, faceId, "-1");
if (oneCouponRecordQueryResp.isUsable()) {
respVO.setCouponId(oneCouponRecordQueryResp.getCouponId());
respVO.setCouponRecordId(oneCouponRecordQueryResp.getId());
CouponEntity coupon = oneCouponRecordQueryResp.getCoupon();
if (coupon != null) {
respVO.setCouponPrice(coupon.calculateDiscountPrice(priceConfig.getPrice()));
}
}
break;
}
respVO.setConfigId(priceConfig.getId());
respVO.setGoodsIds(goodsIds);
respVO.setType(type);
respVO.setOrigPrice(priceConfig.getPrice());
respVO.setSlashPrice(priceConfig.getSlashPrice());
// 查询用户是否有此类订单
respVO.setBuy(false);
if (userId != null) {
OrderEntity orderEntity = orderBiz.hasTypeOrder(userId, scenicId, type, priceConfig.getId());
if (orderEntity != null) {
respVO.setOrderId(orderEntity.getId());
respVO.setBuy(Integer.valueOf(1).equals(orderEntity.getStatus()));
}
}
return respVO;
}
}

View File

@ -112,7 +112,7 @@ public class TaskStatusBiz {
int faceCutStatus = getFaceCutStatus(faceId);
if (faceCutStatus != 1) {
// 正在切片
if (templateBiz.determineTemplateCanGenerate(templateList.get(0).getId(), faceId, false)) {
if (templateBiz.determineTemplateCanGenerate(templateList.getFirst().getId(), faceId, false)) {
response.setStatus(2);
} else {
response.setStatus(0);

View File

@ -107,7 +107,7 @@ public class TemplateBiz {
List<SourceEntity> sourceEntities = sourceMapper.listVideoByScenicFaceRelation(face.getScenicId(), faceId);
count = sourceEntities.stream()
.map(SourceEntity::getDeviceId)
.filter(deviceId -> deviceId != null) // 添加对 null 的检查
.filter(Objects::nonNull) // 添加对 null 的检查
.distinct()
.filter(deviceId -> placeholderList.contains(deviceId.toString()))
.count();

View File

@ -1,26 +0,0 @@
package com.ycwl.basic.config;
import com.ycwl.basic.storage.entity.AliOssStorageConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 阿里云OSS配置
*
* @author songmingsong
**/
@Data
@Component
public class FaceDetectConfig {
@Value("${aliFace.accessKeyId}")
private String accessKeyId;
@Value("${aliFace.accessKeySecret}")
private String accessKeySecret;
@Value("${aliFace.region}")
private String region;
}

View File

@ -1,50 +0,0 @@
package com.ycwl.basic.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource;
@Configuration
public class RedisConfig {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

View File

@ -1,31 +0,0 @@
//package com.ycwl.basic.config;
//
//import org.redisson.Redisson;
//import org.redisson.api.RedissonClient;
//import org.redisson.config.Config;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//@Configuration
//public class RedissonConfig {
//
// @Value("${spring.redis.host}")
// private String host;
// @Value("${spring.redis.port}")
// private String port;
// @Value("${spring.redis.password}")
// private String password;
//
// @Bean
// public RedissonClient getRedisSon() {
// Config config = new Config();
// String address = new StringBuilder("redis://").append(host).append(":").append(port).toString();
// config.useSingleServer().setAddress(address);
// if (null != password && !"".equals(password.trim())) {
// config.useSingleServer().setPassword(password);
// }
// return Redisson.create(config);
// }
//
//}

View File

@ -12,8 +12,11 @@ public class SchedulerConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(256);
scheduler.setPoolSize(32); // 核心/最大线程数
scheduler.setAwaitTerminationSeconds(0); // 空闲线程存活时间(秒)
scheduler.setThreadNamePrefix("Scheduler-");
scheduler.setAwaitTerminationSeconds(60); // 等待任务终止的时间
scheduler.setRemoveOnCancelPolicy(true); // 取消任务后移除线程
return scheduler;
}
}

View File

@ -25,7 +25,7 @@ import java.util.List;
*/
@Configuration
@EnableSwagger2WebMvc
@Profile({"!prod"})
@Profile({"test"})
public class SwaggerConfig {
/**

View File

@ -3,8 +3,7 @@ package com.ycwl.basic.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.ycwl.basic.interceptor.AuthInterceptor;
import com.ycwl.basic.xss.XssJacksonDeserializer;
import com.ycwl.basic.xss.XssJacksonSerializer;
import com.ycwl.basic.stats.interceptor.StatsInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -29,13 +28,17 @@ public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Autowired
private StatsInterceptor statsInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
// 拦截除指定接口外的所有请求,通过判断 注解 来决定是否需要做登录验证
.addPathPatterns("/**")
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/api-docs", "/doc.html/**", "/error", "/csrf", "/");
.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/api-docs", "/doc.html/**", "/error", "/");
registry.addInterceptor(statsInterceptor)
.addPathPatterns("/api/mobile/**");
}
/**
@ -58,7 +61,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// config.setAllowCredentials(true);
// 允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// 允许访问的头信息,*表示全部
@ -78,25 +81,6 @@ public class WebMvcConfig implements WebMvcConfigurer {
}
@Bean
public WebMvcConfigurer createConvert() {
return new WebMvcConfigurer() {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
ObjectMapper mapper = builder.build();
/*注入自定义的序列化工具,将RequestBody的参数进行转译后传输*/
SimpleModule simpleModule = new SimpleModule();
// XSS序列化
simpleModule.addSerializer(String.class, new XssJacksonSerializer());
simpleModule.addDeserializer(String.class, new XssJacksonDeserializer());
mapper.registerModule(simpleModule);
converters.add(new MappingJackson2HttpMessageConverter(mapper));
}
};
}
@Autowired
private StringHttpMessageConverter stringHttpMessageConverter;
@Autowired

View File

@ -1,73 +0,0 @@
package com.ycwl.basic.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 微信小程序配置
*
* @author songmingsong
**/
@Data
@Component
@ConfigurationProperties(prefix = "wx")
public class WechatConfig {
/**
* 公众号的appId
*/
private String appId;
/**
* 公众号的密钥
*/
private String appSecret;
/**
* 小程序的AppId
*/
private String miniProgramAppId;
/**
* 小程序的secret
*/
private String miniProgramSecret;
/**
* 申请openid授权
*/
private String grandType;
/**
* 商户号
*/
private String mchId;
/**
* 商户证书序列号
*/
private String mchSerialNo;
/**
* 支付回调接口地址
*/
private String payNotifyUrl;
/**
* 退款回调接口地址
*/
private String refundNotifyUrl;
/**
* 商户API私钥路径
*/
private String keyPath;
/**
* 商户APIV3密钥
*/
private String apiV3;
}

View File

@ -1,7 +1,7 @@
package com.ycwl.basic.constant;
import com.ycwl.basic.utils.StringUtil;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.time.LocalDateTime;
import java.util.HashMap;
@ -10,29 +10,29 @@ import java.util.Map;
@Data
public class BaseContextHandler {
public static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal();
public static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();
public BaseContextHandler() {
}
public static void set(String key, Object value) {
Object map;
if ((map = (Map) threadLocal.get()) == null) {
map = new HashMap();
threadLocal.set((Map<String, Object>) map);
Map<String, Object> map;
if ((map = threadLocal.get()) == null) {
map = new HashMap<>();
threadLocal.set(map);
}
((Map) map).put(key, value);
map.put(key, value);
}
public static Object get(String key) {
Object map;
if ((map = (Map) threadLocal.get()) == null) {
map = new HashMap();
threadLocal.set((Map<String, Object>) map);
Map<String, Object> map;
if ((map = threadLocal.get()) == null) {
map = new HashMap<>();
threadLocal.set(map);
}
return ((Map) map).get(key);
return (map).get(key);
}
public static void setToken(String token) {
@ -40,7 +40,13 @@ public class BaseContextHandler {
}
public static String getToken() {
return StringUtil.a(get("currentUserToken"));
if (get("currentUserToken") == null) {
return "";
}
if (StringUtils.isEmpty(get("currentUserToken").toString())) {
return "";
}
return get("currentUserToken").toString();
}
public static String getAccount() {

View File

@ -4,4 +4,7 @@ public class StorageConstant {
public static final String VLOG_PATH = "vlog";
public static final String VIDEO_PIECE_PATH = "source_video";
public static final String PHOTO_PATH = "source_photo";
public static final String PHOTO_WATERMARKED_PATH = "photo_w";
public static final String VIID_FACE = "viid_face";
public static final String USER_FACE = "user_face";
}

View File

@ -1,126 +0,0 @@
package com.ycwl.basic.constant;
import com.wechat.pay.java.service.payments.model.Transaction;
import java.util.HashMap;
import java.util.Map;
/**
* <p>@description: 微信常量 </p>
* <p>@author: songmingsong </p>
**/
public class WeiXinConstant {
private static final Map<Transaction.TradeStateEnum, String> STATE_DESCRIPTION_MAP = new HashMap<>();
static {
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.SUCCESS, "SUCCESS");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.REFUND, "REFUND");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.NOTPAY, "NOTPAY");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.CLOSED, "CLOSED");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.REVOKED, "REVOKED");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.USERPAYING, "USERPAYING");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.PAYERROR, "PAYERROR");
STATE_DESCRIPTION_MAP.put(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum.ACCEPT, "ACCEPT");
}
public static String getDescriptionState(com.wechat.pay.java.service.payments.model.Transaction.TradeStateEnum state) {
return STATE_DESCRIPTION_MAP.getOrDefault(state, "未知状态");
}
private static final Map<com.wechat.pay.java.service.payments.model.Transaction.TradeTypeEnum, String> STATE_DESCRIPTION_MAP_TYPE = new HashMap<>();
static {
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.JSAPI, "JSAPI");
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.NATIVE, "NATIVE");
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.APP, "APP");
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.MICROPAY, "MICROPAY");
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.MWEB, "MWEB");
STATE_DESCRIPTION_MAP_TYPE.put(Transaction.TradeTypeEnum.FACEPAY, "FACEPAY");
}
public static String getDescriptionType(Transaction.TradeTypeEnum type) {
return STATE_DESCRIPTION_MAP_TYPE.getOrDefault(type, "未知类型");
}
/**
* 公众号模板地址
*/
public static final String PUBLIC_ACCOUNT_TEMPLATE =
"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
/**
* 获取微信用户基本信息地址
*/
public static final String WECHAT_OAUTH_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";
/**
* 获取ACCESS_TOKEN
*/
public static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
/**
* 登录凭证校验
*/
public static final String GET_OPEN_ID = "https://api.weixin.qq.com/sns/jscode2session";
/**
* 获取小程序地址
*/
public static final String GET_MINI_QRCODE = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
/**
* 获取用户基本信息
*/
public static final String GET_USER_BASIC_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";
/**
* 获取包含请求参数ACCESS_TOKEN
*/
public static final String ACCESS_TOKEN_WITH_PARAM = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
/**
* 获取小程序 URL Link
*/
public static final String GENERATE_URL_LINK = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s";
/**
* 发送模板消息
*/
public static final String MESSAGE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
/*-----------------------------*/
/* */
/* 支付相关 */
/* */
/*-----------------------------*/
/**
* 退款链接
*/
public static final String REFUNDS_URL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
public static final String REFUNDS_URi = "/v3/refund/domestic/refunds/";
/**
* 其他
*/
public static final String WECHATPAY_STATUS = "status";
public static final String WECHATPAY_SUCCESS = "SUCCESS";
public static final String WECHATPAY_PROCESSING = "PROCESSING";
public static final String WECHATPAY_OUT_TRADE_NO = "out_trade_no";
public static final String WECHATPAY_OUT_REFUND_NO = "out_refund_no";
public static final String WECHATPAY_REFUND = "refund";
public static final String WECHATPAY_TOTAL = "total";
public static final String WECHATPAY_CURRENCY = "currency";
public static final String WECHATPAY_CURRENCY_CNY = "CNY";
public static final String WECHATPAY_AMOUNT = "amount";
public static final String WECHATPAY_NOTIFY_URL = "notify_url";
public static final String REFUNDS_RESOURCE = "resource";
public static final String REFUNDS_CIPHERTEXT = "ciphertext";
public static final String REFUNDS_NONCE = "nonce";
public static final String REFUNDS_REFUND_STATUS = "refund_status";
public static final String REFUNDS_ASSOCIATED_DATA = "associated_data";
public static final String WECHAT_ERRCODE = "errcode";
public static final String WECHAT_ERRMSG = "errmsg";
/**
* 退款的token的SCHEMA
*/
public static final String REFUNDS_SCHEMA = "Wechatpay-Signature-Type "; // 注意有一个空格
/**
* 支付请求头
*/
public static final String WECHATPAY_SIGNATURE_TYPE = "Wechatpay-Signature-Type";
}

View File

@ -15,27 +15,23 @@ import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.member.entity.MemberEntity;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
import com.ycwl.basic.repository.VideoRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.mobile.GoodsService;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.service.task.impl.TaskTaskServiceImpl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
@ -59,8 +55,6 @@ public class LyCompatibleController {
@Autowired
private FaceMapper faceMapper;
@Autowired
private AppScenicService appScenicService;
@Autowired
private VideoRepository videoRepository;
@Autowired
private VideoMapper videoMapper;
@ -72,7 +66,7 @@ public class LyCompatibleController {
@PostMapping("sendPhoto")
@IgnoreToken
public R sendPhoto(@RequestParam(value = "file", required = false) MultipartFile file, HttpServletRequest request) {
Map<String, String> headersMap = new HashMap<String, String>();
Map<String, String> headersMap = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
@ -129,7 +123,7 @@ public class LyCompatibleController {
@RequestMapping("getIsVideo")
@IgnoreToken
public R getIsVideo(HttpServletRequest request) {
Map<String, String> headersMap = new HashMap<String, String>();
Map<String, String> headersMap = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
@ -171,7 +165,7 @@ public class LyCompatibleController {
@RequestMapping("getNewVideo")
@IgnoreToken
public R getNewVideo(HttpServletRequest request) {
Map<String, String> headersMap = new HashMap<String, String>();
Map<String, String> headersMap = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
@ -197,7 +191,7 @@ public class LyCompatibleController {
return R.error("用户没有上传过照片!");
}
VideoTaskStatusVO taskStatusVO = goodsService.getTaskStatusByScenicId(member.getId(), member.getScenicId());
List<ContentPageVO> listApiResponse = appScenicService.faceContentList(member.getId(), faceVO.getId());
List<ContentPageVO> listApiResponse = faceService.faceContentList(faceVO.getId());
Map<Integer, List<ContentPageVO>> collect = listApiResponse.stream()
.filter(contentPageVO -> contentPageVO.getLockType() < 0)
.collect(Collectors.groupingBy(ContentPageVO::getGoodsType));
@ -210,7 +204,7 @@ public class LyCompatibleController {
}
List<Map<String, Object>> videoList = collect.get(0).stream().collect(Collectors.groupingBy(ContentPageVO::getTemplateId))
.values().stream().map(contentPageVOs -> {
ContentPageVO contentPageVO = contentPageVOs.get(0);
ContentPageVO contentPageVO = contentPageVOs.getFirst();
Map<String, Object> map = new HashMap<>();
VideoEntity videoRespVO = videoRepository.getVideo(contentPageVO.getContentId());
map.put("id", videoRespVO.getId().toString());
@ -224,8 +218,9 @@ public class LyCompatibleController {
return map;
}).collect(Collectors.toList());
GoodsReqQuery goodsReqQuery = new GoodsReqQuery();
goodsReqQuery.setFaceId(faceVO.getId());
goodsReqQuery.setSourceType(1);
List<GoodsDetailVO> sourceGoodsList = goodsService.sourceGoodsList(member.getId(), goodsReqQuery);
List<GoodsDetailVO> sourceGoodsList = goodsService.sourceGoodsList(goodsReqQuery);
List<Map<String, Object>> userVideoList = sourceGoodsList.stream().map(goodsDetailVO -> {
Map<String, Object> map = new HashMap<>();
map.put("id", goodsDetailVO.getGoodsId().toString());

View File

@ -1,5 +1,6 @@
package com.ycwl.basic.controller.extern;
import java.io.Serial;
import java.util.HashMap;
import java.util.Map;
@ -11,6 +12,7 @@ import java.util.Map;
* @date 2016年10月27日 下午9:59:27
*/
public class R extends HashMap<String, Object> {
@Serial
private static final long serialVersionUID = 1L;
public R() {

View File

@ -0,0 +1,9 @@
package com.ycwl.basic.controller.mobile;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/mobile/controller/v1")
public class AppCouponController {
}

View File

@ -1,15 +0,0 @@
package com.ycwl.basic.controller.mobile;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author:longbinbin
* @Date:2024/12/6 10:18
*/
@RestController
@RequestMapping("/api/mobile/scenic/v1")
@Api(tags = "设备相关接口")
public class AppDeviceController {
}

View File

@ -2,6 +2,7 @@ package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.utils.ApiResponse;
@ -38,7 +39,7 @@ AppFaceController {
*/
@ApiOperation("人脸照片上传")
@PostMapping("/faceUPload")
public ApiResponse faceUpload(@RequestParam("file")MultipartFile file, @RequestParam("scenicId") Long scenicId) {
public ApiResponse<FaceRecognizeResp> faceUpload(@RequestParam("file")MultipartFile file, @RequestParam("scenicId") Long scenicId) {
//获取用户id
JwtInfo worker = JwtTokenUtil.getWorker();
Long userId = worker.getUserId();
@ -60,13 +61,21 @@ AppFaceController {
}
@DeleteMapping("/{faceId}")
public ApiResponse deleteFace(@PathVariable("faceId") Long faceId) {
public ApiResponse<String> deleteFace(@PathVariable("faceId") Long faceId) {
return faceService.deleteFace(faceId);
}
@PostMapping("/{faceId}/match")
public ApiResponse match(@PathVariable("faceId") Long faceId) {
public ApiResponse<String> match(@PathVariable("faceId") Long faceId) {
faceService.matchFaceId(faceId);
return ApiResponse.success("");
}
@ApiOperation("景区视频源素材列表")
@GetMapping("/{faceId}/contentList")
public ApiResponse<List<ContentPageVO>> contentList(@PathVariable Long faceId) {
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
return ApiResponse.success(contentPageVOS);
}
}

View File

@ -1,13 +1,10 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.biz.TaskStatusBiz;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.exception.CheckTokenException;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.*;
import com.ycwl.basic.service.mobile.GoodsService;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import io.swagger.annotations.Api;
@ -15,7 +12,6 @@ import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.List;
/**
@ -30,10 +26,6 @@ public class AppGoodsController {
@Autowired
private GoodsService goodsService;
@Autowired
private TaskService taskService;
@Autowired
private TaskStatusBiz taskStatusBiz;
@ApiOperation("商品列表")
@PostMapping("/goodsList")
@ -44,10 +36,30 @@ public class AppGoodsController {
@ApiOperation("源素材(原片/照片)商品列表")
@PostMapping("/sourceGoodsList")
public ApiResponse<List<GoodsDetailVO>> sourceGoodsList(@RequestBody GoodsReqQuery query) {
List<GoodsDetailVO> goodsDetailVOS = goodsService.sourceGoodsList(Long.valueOf(BaseContextHandler.getUserId()), query);
List<GoodsDetailVO> goodsDetailVOS = goodsService.sourceGoodsList(query);
return ApiResponse.success(goodsDetailVOS);
}
@ApiOperation("源素材(原片/照片)商品数量")
@PostMapping("/sourceGoodsCount")
public ApiResponse<Integer> sourceGoodsCount(@RequestBody GoodsReqQuery query) {
Integer count = goodsService.sourceGoodsCount(query);
return ApiResponse.success(count);
}
@PostMapping("/sourceGoodsList/preview")
public ApiResponse<List<GoodsUrlVO>> sourceGoodsListPreview(@RequestBody GoodsReqQuery query) {
List<GoodsUrlVO> goodsUrlList = goodsService.sourceGoodsListPreview(query);
return ApiResponse.success(goodsUrlList);
}
@PostMapping("/sourceGoodsList/download")
public ApiResponse<List<GoodsUrlVO>> sourceGoodsListDownload(@RequestBody GoodsReqQuery query) {
List<GoodsUrlVO> goodsUrlList = goodsService.sourceGoodsListDownload(query);
return ApiResponse.success(goodsUrlList);
}
@ApiOperation("成片vlog商品详情")
@GetMapping("/getVideoGoodsDetail/{videoId}")
@IgnoreToken
@ -62,8 +74,7 @@ public class AppGoodsController {
@GetMapping("/sourceGoods/{sourceId}")
public ApiResponse<GoodsDetailVO> sourceGoodsInfo(@PathVariable("sourceId") Long sourceId) {
JwtInfo worker = JwtTokenUtil.getWorker();
return goodsService.sourceGoodsInfo(worker.getUserId(), sourceId);
return goodsService.sourceGoodsInfo(sourceId);
}
/**
@ -88,6 +99,6 @@ public class AppGoodsController {
@GetMapping("/task/face/{faceId}/template/{templateId}")
public ApiResponse<VideoTaskStatusVO> getTemplateTaskStatus(@PathVariable("faceId") Long faceId, @PathVariable("templateId") Long templateId) {
JwtInfo worker = JwtTokenUtil.getWorker();
return ApiResponse.success(goodsService.getTaskStatusByTemplateId(worker.getUserId(), faceId, templateId));
return ApiResponse.success(goodsService.getTaskStatusByTemplateId(faceId, templateId));
}
}

View File

@ -1,54 +0,0 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.mobile.index.TopStateResp;
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author:longbinbin
* @Date:2024/12/5 10:20
*/
@RestController
@RequestMapping("/api/mobile/index/v1")
@Api(tags = "首页相关接口")
public class AppIndexController {
@Autowired
private AppScenicService scenicService;
/**
* 首页景区列表
*
* @return
*/
// @ApiOperation(value = "首页景区列表", notes = "首页景区列表")
// @PostMapping("/scenicList")
// @IgnoreToken
// public ApiResponse<List<ScenicAppVO>> scenicList(@RequestBody ScenicIndexVO scenicIndexVO) {
// return scenicService.scenicList(scenicIndexVO);
// }
// @ApiOperation(value = "顶部状态", notes = "顶部状态")
// @GetMapping("/topState")
// @IgnoreToken
// public ApiResponse<TopStateResp> topState() {
// return scenicService.topState();
// }
@GetMapping("/faceAgreement")
public ApiResponse<String> faceAgreement() {
return ApiResponse.success("人脸识别隐私协议:\n" +
"1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n" +
"1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n" +
"1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n1、xxx\n");
}
}

View File

@ -62,29 +62,9 @@ public class AppMemberController {
return memberService.update(userInfoUpdateDTO);
}
/**
* 同意用户协议
*
* @return
*/
@ApiOperation("同意用户协议")
@GetMapping("/agreement")
public ApiResponse<?> agreement() {
return memberService.agreement();
}
@ApiOperation("是否首次获取视频")
@GetMapping("/isFirstObtainVideo")
public ApiResponse isFirstTimeObtainingVideo() {
// TODO 判断是否首次获取视频逻辑
return ApiResponse.success("");
}
@ApiOperation("新增或修改景区服务通知状态")
@GetMapping("/updateScenicServiceNoticeStatus")
public ApiResponse updateScenicServiceNoticeStatus(Long scenicId) {
public ApiResponse<String> updateScenicServiceNoticeStatus(Long scenicId) {
return memberService.updateScenicServiceNoticeStatus(scenicId);
}

View File

@ -2,19 +2,19 @@ package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.PriceBiz;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.GoodsPriceQueryReq;
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.OrderAppPageReq;
import com.ycwl.basic.model.mobile.order.RefundOrderReq;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.order.req.CreateBatchOrderReqVO;
import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO;
import com.ycwl.basic.model.pc.order.req.OrderAddReq;
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.service.mobile.GoodsService;
import com.ycwl.basic.pay.entity.PayResponse;
import com.ycwl.basic.service.pc.OrderService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
@ -23,6 +23,8 @@ import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* @Author:longbinbin
* @Date:2024/12/4 17:16
@ -35,9 +37,11 @@ public class AppOrderController {
@Autowired
private OrderService orderService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderBiz orderBiz;
@Autowired
private PriceBiz priceBiz;
@Autowired
private FaceMapper faceMapper;
@ApiOperation("用户端订单列表查询")
@PostMapping("/page")
@ -55,15 +59,20 @@ public class AppOrderController {
@ApiOperation("用户端订单新增")
@PostMapping("/addOrder")
public ApiResponse<WxPayRespVO> addOrder(@RequestBody CreateOrderReqVO orderAddReq) throws Exception {
public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateOrderReqVO orderAddReq) throws Exception {
JwtInfo worker = JwtTokenUtil.getWorker();
return orderService.createOrder(worker.getUserId(), orderAddReq);
}
@ApiOperation("查询订单")
@GetMapping("/queryOrder")
public ApiResponse<PayResponse> queryOrder(@RequestParam("orderId") Long orderId) {
return ApiResponse.success(orderService.queryOrder(orderId));
}
@ApiOperation("用户端打包订单新增")
@PostMapping("/addBatchOrder")
public ApiResponse<WxPayRespVO> addOrder(@RequestBody CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
public ApiResponse<Map<String, Object>> addOrder(@RequestBody CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
JwtInfo worker = JwtTokenUtil.getWorker();
return orderService.createBatchOrder(worker.getUserId(), batchOrderReqVO);
}
@ -88,4 +97,21 @@ public class AppOrderController {
Long userId = Long.parseLong(BaseContextHandler.getUserId());
return ApiResponse.success(orderBiz.isBuy(userId, scenicId, type, goodsId));
}
@GetMapping("/scenic/{scenicId}/queryBatchPrice")
public ApiResponse<IsBuyBatchRespVO> queryPrice(@PathVariable("scenicId") Long scenicId, @RequestParam("type") Integer type, @RequestParam(value = "faceId", required = false) Long faceId, @RequestParam(value = "goodsIds", required = false) String goodsIds) {
Long userId = Long.parseLong(BaseContextHandler.getUserId());
if (faceId == null) {
FaceRespVO lastFaceByUserId = faceMapper.findLastFaceByUserId(BaseContextHandler.getUserId());
if (lastFaceByUserId == null) {
return ApiResponse.fail("您还未上传人脸");
}
faceId = lastFaceByUserId.getId();
}
IsBuyBatchRespVO buy = priceBiz.isBuy(userId, faceId, scenicId, type, goodsIds);
if (buy == null) {
return ApiResponse.fail("该套餐暂未开放购买");
}
return ApiResponse.success(buy);
}
}

View File

@ -0,0 +1,106 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
import com.ycwl.basic.model.pc.printer.resp.PrinterResp;
import com.ycwl.basic.model.printer.req.FromSourceReq;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/api/mobile/printer/v1")
public class AppPrinterController {
@Autowired
private PrinterService printerService;
@GetMapping("/listFor/{scenicId}")
@IgnoreToken
public ApiResponse<List<PrinterResp>> listFor(@PathVariable("scenicId") Long scenicId) {
return ApiResponse.success(printerService.listByScenicId(scenicId));
}
@GetMapping("/getListFor/{scenicId}")
public ApiResponse<List<MemberPrintResp>> getListFor(@PathVariable("scenicId") Long scenicId) {
JwtInfo worker = JwtTokenUtil.getWorker();
return ApiResponse.success(printerService.getUserPhotoList(worker.getUserId(), scenicId));
}
@GetMapping("/getItem/{scenicId}/{id}")
public ApiResponse<MemberPrintResp> getItem(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id) {
JwtInfo worker = JwtTokenUtil.getWorker();
MemberPrintResp userPhoto = printerService.getUserPhoto(worker.getUserId(), scenicId, id);
if (userPhoto == null) {
return ApiResponse.fail("未找到该图片");
}
return ApiResponse.success(userPhoto);
}
@PostMapping("/deleteFrom/{scenicId}/{id}")
public ApiResponse<?> deleteFrom(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id) throws IOException {
JwtInfo worker = JwtTokenUtil.getWorker();
printerService.deleteUserPhoto(worker.getUserId(), scenicId, id);
return ApiResponse.success(null);
}
@PostMapping("/uploadTo/{scenicId}")
public ApiResponse<?> upload(@PathVariable("scenicId") Long scenicId, @RequestParam(value = "file") MultipartFile file) throws IOException {
String[] split = file.getOriginalFilename().split("\\.");
String ext = split[split.length - 1];
String url = StorageFactory.use().uploadFile(file, "printer", UUID.randomUUID() + "." + ext);
printerService.addUserPhoto(JwtTokenUtil.getWorker().getUserId(), scenicId, url);
return ApiResponse.success(url);
}
@PostMapping("/uploadTo/{scenicId}/cropped/{id}")
public ApiResponse<?> uploadReplace(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id, @RequestParam(value = "file") MultipartFile file) throws IOException {
String[] split = file.getOriginalFilename().split("\\.");
String ext = split[split.length - 1];
String url = StorageFactory.use().uploadFile(file, "printer", UUID.randomUUID() + "." + ext);
printerService.setPhotoCropped(JwtTokenUtil.getWorker().getUserId(), scenicId, id, url);
return ApiResponse.success(url);
}
@PostMapping("/uploadTo/{scenicId}/formSource")
public ApiResponse<?> uploadFromSource(@PathVariable("scenicId") Long scenicId, @RequestBody FromSourceReq req) throws IOException {
printerService.addUserPhotoFromSource(JwtTokenUtil.getWorker().getUserId(), scenicId, req);
return ApiResponse.success(null);
}
@PostMapping("/setQuantity/{scenicId}/{id}")
public ApiResponse<?> setQuantity(@PathVariable("scenicId") Long scenicId, @PathVariable("id") Long id, @RequestParam("quantity") Integer quantity) {
if (quantity == null) {
return ApiResponse.fail("请输入数量");
}
if (quantity < 0) {
return ApiResponse.fail("数量不能小于0");
}
printerService.setPhotoQuantity(JwtTokenUtil.getWorker().getUserId(), scenicId, id, quantity);
return ApiResponse.success(null);
}
@GetMapping("/price/{scenicId}")
public ApiResponse<?> queryPrice(@PathVariable("scenicId") Long scenicId) {
return ApiResponse.success(printerService.queryPrice(JwtTokenUtil.getWorker().getUserId(), scenicId));
}
@PostMapping("/order/{scenicId}")
public ApiResponse<Map<String, Object>> createOrder(@PathVariable("scenicId") Long scenicId) {
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, null));
}
@PostMapping("/order/{scenicId}/toPrinter/{printerId}")
public ApiResponse<Map<String, Object>> createOrderToPrinter(@PathVariable("scenicId") Long scenicId, @PathVariable("printerId") Integer printerId) {
return ApiResponse.success(printerService.createOrder(JwtTokenUtil.getWorker().getUserId(), scenicId, printerId));
}
}

View File

@ -4,17 +4,17 @@ import com.github.pagehelper.PageInfo;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.GoodsPageVO;
import com.ycwl.basic.model.mobile.goods.GoodsReqQuery;
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicConfigResp;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import io.swagger.annotations.Api;
@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
@ -31,20 +32,33 @@ import java.util.List;
* @Date:2024/12/5 10:22
*/
@Slf4j
@Deprecated
@RestController
@RequestMapping("/api/mobile/scenic/v1")
@Api(tags = "景区相关接口")
public class AppScenicController {
@Autowired
private FaceService faceService;
@Autowired
private AppScenicService appScenicService;
@Autowired
private ScenicRepository scenicRepository;
private static final List<String> ENABLED_USER_IDs = new ArrayList<>(){{
add("3932535453961555968");
add("3936121342868459520");
add("3936940597855784960");
}};
@ApiOperation("分页查询景区列表")
@PostMapping("/page")
public ApiResponse<PageInfo<ScenicAppVO>> pageQuery(@RequestBody ScenicReqQuery scenicReqQuery){
return appScenicService.pageQuery(scenicReqQuery);
String userId = BaseContextHandler.getUserId();
if (ENABLED_USER_IDs.contains(userId)) {
return appScenicService.pageQuery(scenicReqQuery);
} else {
return ApiResponse.success(new PageInfo<>(new ArrayList<>()));
}
}
@ApiOperation("根据id查询景区详情")
@IgnoreToken
@ -55,9 +69,26 @@ public class AppScenicController {
@GetMapping("/{id}/config")
@IgnoreToken
public ApiResponse<ScenicConfigEntity> getConfig(@PathVariable Long id){
public ApiResponse<ScenicConfigResp> getConfig(@PathVariable Long id){
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(id);
return ApiResponse.success(scenicConfig);
ScenicConfigResp resp = new ScenicConfigResp();
resp.setBookRoutine(scenicConfig.getBookRoutine());
resp.setForceFinishTime(scenicConfig.getForceFinishTime());
resp.setTourTime(scenicConfig.getTourTime());
resp.setSampleStoreDay(scenicConfig.getSampleStoreDay());
resp.setFaceStoreDay(scenicConfig.getFaceStoreDay());
resp.setVideoStoreDay(scenicConfig.getVideoStoreDay());
resp.setAllFree(scenicConfig.getAllFree());
resp.setDisableSourceVideo(scenicConfig.getDisableSourceVideo());
resp.setDisableSourceImage(scenicConfig.getDisableSourceImage());
resp.setAntiScreenRecordType(scenicConfig.getAntiScreenRecordType());
resp.setVideoSourceStoreDay(scenicConfig.getVideoSourceStoreDay());
resp.setImageSourceStoreDay(scenicConfig.getImageSourceStoreDay());
resp.setUserSourceExpireDay(scenicConfig.getUserSourceExpireDay());
resp.setBrokerDirectRate(scenicConfig.getBrokerDirectRate());
resp.setVideoSourcePackHint(scenicConfig.getVideoSourcePackHint());
resp.setImageSourcePackHint(scenicConfig.getImageSourcePackHint());
return ApiResponse.success(resp);
}
@ApiOperation("查询景区设备总数和拍到用户的机位数量")
@ -69,21 +100,19 @@ public class AppScenicController {
@ApiOperation("景区视频源素材列表")
@GetMapping("/contentList/")
public ApiResponse<List<ContentPageVO>> contentList() {
return appScenicService.contentListUseDefaultFace();
return faceService.contentListUseDefaultFace();
}
@ApiOperation("景区视频源素材列表")
@GetMapping("/face/{faceId}/contentList")
public ApiResponse<List<ContentPageVO>> contentList(@PathVariable String faceId) {
if (!StringUtils.isNumeric(faceId)) {
log.error("请求异常, faceId: [{}]",faceId);
return ApiResponse.fail("请求异常");
}
Long id = Long.parseLong(faceId);
JwtInfo worker = JwtTokenUtil.getWorker();
List<ContentPageVO> contentPageVOS = appScenicService.faceContentList(worker.getUserId(), id);
public ApiResponse<List<ContentPageVO>> contentList(@PathVariable Long faceId) {
List<ContentPageVO> contentPageVOS = faceService.faceContentList(faceId);
return ApiResponse.success(contentPageVOS);
}
@PostMapping("/nearby")
public ApiResponse<List<ScenicAppVO>> nearby(@RequestBody ScenicIndexVO scenicIndexVO) {
List<ScenicAppVO> list = appScenicService.scenicListByLnLa(scenicIndexVO);
return ApiResponse.success(list);
}
}

View File

@ -1,7 +1,6 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.biz.TaskStatusBiz;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.VideoTaskReq;
import com.ycwl.basic.model.mobile.goods.VideoTaskStatusVO;
@ -30,7 +29,7 @@ public class AppTaskController {
@IgnoreLogReq
public ApiResponse<VideoTaskStatusVO> getTaskStatusByFaceId(@PathVariable("faceId") Long faceId) {
JwtInfo worker = JwtTokenUtil.getWorker();
return ApiResponse.success(goodsService.getTaskStatusByFaceId(worker.getUserId(), faceId));
return ApiResponse.success(goodsService.getTaskStatusByFaceId(faceId));
}
@GetMapping("/scenic/{scenicId}")
@IgnoreLogReq
@ -52,7 +51,7 @@ public class AppTaskController {
@IgnoreLogReq
public ApiResponse<VideoTaskStatusVO> getTemplateTaskStatus(@PathVariable("faceId") Long faceId, @PathVariable("templateId") Long templateId) {
JwtInfo worker = JwtTokenUtil.getWorker();
return ApiResponse.success(goodsService.getTaskStatusByTemplateId(worker.getUserId(), faceId, templateId));
return ApiResponse.success(goodsService.getTaskStatusByTemplateId(faceId, templateId));
}
@PostMapping("/submit")

View File

@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Deprecated
@RestController
@RequestMapping("/api/mobile/video/v1")
public class AppVideoController {

View File

@ -1,20 +1,14 @@
package com.ycwl.basic.controller.mobile;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.wx.WechatMessageSubscribeForm;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.WxNotifyService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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;
@ -31,8 +25,6 @@ import java.util.List;
@RequestMapping("/api/mobile/wx/notify/v1")
@Api(tags = "微信消息模板通知")
public class AppWxNotifyController {
@Autowired
private WxNotifyService wxNotifyService;
@Autowired
private ScenicRepository scenicRepository;
//
@ -47,7 +39,7 @@ public class AppWxNotifyController {
@GetMapping({"/getIds", "/"})
@IgnoreToken
public ApiResponse<List<String>> getIds() {
return ApiResponse.success(new ArrayList<String>() {{
return ApiResponse.success(new ArrayList<>() {{
add("5b8vTm7kvwYubqDxb3dxBs0BqxMsgVgGw573aahTEd8");
add("vPIzbkA0x4mMj-vdbWx6_45e8juWXzs3FGYnDsIPv3A");
add("HB1vp-0BXc2WyYeoYN3a3GuZV9HtPLXUTT7blCBq9eY");
@ -57,7 +49,7 @@ public class AppWxNotifyController {
@GetMapping("/{scenicId}")
@IgnoreToken
public ApiResponse<List<String>> getIds(@PathVariable("scenicId") Long scenicId) {
return ApiResponse.success(new ArrayList<String>() {{
return ApiResponse.success(new ArrayList<>() {{
String videoGeneratedTemplateId = scenicRepository.getVideoGeneratedTemplateId(scenicId);
if (StringUtils.isNotBlank(videoGeneratedTemplateId)) {
add(videoGeneratedTemplateId);

View File

@ -2,22 +2,24 @@ package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.annotation.RequestToFile;
import com.ycwl.basic.aspectj.HttpSaver;
import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.pay.entity.PayResponse;
import com.ycwl.basic.service.mobile.WxPayService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
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 javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.GeneralSecurityException;
@ -35,12 +37,6 @@ public class AppWxPayController {
@Autowired
private WxPayService wxPayService;
@ApiOperation(value = "微信预支付", notes = "微信预支付")
@PostMapping("/createOrder")
public ApiResponse<WxPayRespVO> createOrder(@RequestBody WXPayOrderReqVO req) throws Exception {
return ApiResponse.success(wxPayService.createOrder(req));
}
@ApiOperation(value = "微信支付回调", notes = "微信支付回调")
@PostMapping("/payNotify")
@IgnoreToken
@ -49,28 +45,25 @@ public class AppWxPayController {
return ApiResponse.success(BizCodeEnum.REQUEST_OK);
}
@ApiOperation(value = "微信退款", notes = "微信退款")
@PostMapping("/refundOrder")
public ApiResponse<?> refundOrder(@RequestBody String orderId) throws Exception {
return ApiResponse.buildResult(wxPayService.refundOrder(orderId) ?
BizCodeEnum.SUCCESS :
BizCodeEnum.ADVANCE_PAYMENT_REFUND_FAILED);
@RequestMapping("/{scenicId}/payNotify")
@IgnoreToken
public Object payNotifyByScenicId(@PathVariable Long scenicId, HttpServletRequest request) {
PayResponse payResponse = wxPayService.payNotify(scenicId, request);
if (payResponse == null) {
return ApiResponse.buildResult(BizCodeEnum.ADVANCE_PAYMENT_CALLBACK_FAILED);
}
if (StringUtils.isNotBlank(payResponse.getCustomResponse())) {
return payResponse.getCustomResponse();
}
return ApiResponse.success(BizCodeEnum.REQUEST_OK);
}
@ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调")
@PostMapping("/refundNotify")
@PostMapping("/{scenicId}/refundNotify")
@IgnoreToken
public ApiResponse<?> refundNotify(@RequestBody String refundResult) throws GeneralSecurityException, IOException {
return ApiResponse.buildResult(wxPayService.refundNotify(refundResult) ?
public ApiResponse<?> refundNotify(@PathVariable Long scenicId, HttpServletRequest request) throws GeneralSecurityException, IOException {
return ApiResponse.buildResult(wxPayService.refundNotify(scenicId, request) ?
BizCodeEnum.SUCCESS :
BizCodeEnum.ADVANCE_PAYMENT_CALLBACK_REFUND_FAILED);
}
@ApiOperation(value = "微信关闭订单", notes = "微信关闭订单")
@PostMapping("/closeOrder")
@IgnoreToken
public ApiResponse<?> closeOrder(@RequestBody String orderId) {
wxPayService.closeOrder(orderId);
return ApiResponse.buildResult(BizCodeEnum.REQUEST_OK);
}
}

View File

@ -61,7 +61,7 @@ public class AppStatisticsController {
@ApiOperation("统计数据记录")
@PostMapping("/addStatistics")
@IgnoreToken
public ApiResponse addStatistics(@RequestBody StatisticsRecordAddReq req) {
public ApiResponse<String> addStatistics(@RequestBody StatisticsRecordAddReq req) {
return statisticsService.addStatistics(req);
}

View File

@ -3,11 +3,11 @@ package com.ycwl.basic.controller.pc;
import com.ycwl.basic.model.pc.broker.entity.BrokerEntity;
import com.ycwl.basic.model.pc.broker.req.BrokerRecordReqQuery;
import com.ycwl.basic.model.pc.broker.req.BrokerReqQuery;
import com.ycwl.basic.model.pc.broker.resp.BrokerRecordRespVO;
import com.ycwl.basic.model.pc.broker.resp.BrokerRespVO;
import com.ycwl.basic.model.pc.broker.resp.DailySummaryRespVO;
import com.ycwl.basic.service.pc.BrokerRecordService;
import com.ycwl.basic.service.pc.BrokerService;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.WxMpUtil;
import com.ycwl.basic.repository.ScenicRepository;
@ -123,12 +123,16 @@ public class BrokerController {
String appState = mpConfig.getState();
String path = "pages/home/index?scenicId=" + broker.getScenicId() + "&morphId=" + id;
String filePath = "qr_code_tk_" + id + ".jpg";
IStorageAdapter adapter = StorageFactory.use();
if (adapter.isExists(filePath)) {
return ApiResponse.success(adapter.getUrl(filePath));
}
try {
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
IStorageAdapter adapter = StorageFactory.use();
File file = new File(filePath);
String s = adapter.uploadFile(file, filePath);
String s = adapter.uploadFile(null, file, filePath);
file.delete();
adapter.setAcl(StorageAcl.PUBLIC_READ, filePath);
return ApiResponse.success(s);
} catch (Exception e) {
return ApiResponse.fail("生成二维码失败");

View File

@ -0,0 +1,72 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.biz.PriceBiz;
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
import com.ycwl.basic.model.pc.coupon.req.CouponQueryReq;
import com.ycwl.basic.model.pc.coupon.resp.CouponRespVO;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.service.pc.CouponService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/coupon/v1")
@Api(tags = "优惠券管理")
public class CouponController {
@Autowired
private CouponService couponService;
@Autowired
private PriceBiz priceBiz;
@GetMapping("/{scenicId}/goodsList")
public ApiResponse<List<GoodsListRespVO>> scenicGoodsList(@PathVariable Long scenicId) {
List<GoodsListRespVO> data = priceBiz.listGoodsByScenic(scenicId);
data.add(new GoodsListRespVO(-1L, "一口价"));
return ApiResponse.success(data);
}
@ApiOperation("新增优惠券")
@PostMapping("/add")
public ApiResponse<Integer> add(@RequestBody CouponEntity coupon) {
return ApiResponse.success(couponService.add(coupon));
}
@ApiOperation("更新优惠券")
@PostMapping("/update/{id}")
public ApiResponse<Boolean> update(@PathVariable Integer id, @RequestBody CouponEntity coupon) {
coupon.setId(id);
return ApiResponse.success(couponService.update(coupon));
}
@PutMapping("/updateStatus/{id}")
public ApiResponse<Boolean> updateStatus(@PathVariable Integer id) {
return ApiResponse.success(couponService.updateStatus(id));
}
@ApiOperation("删除优惠券")
@DeleteMapping("/delete/{id}")
public ApiResponse<Boolean> delete(@PathVariable Integer id) {
return ApiResponse.success(couponService.delete(id));
}
@ApiOperation("根据ID查询优惠券")
@GetMapping("/get/{id}")
public ApiResponse<CouponEntity> getById(@PathVariable Integer id) {
return ApiResponse.success(couponService.getById(id));
}
@ApiOperation("分页查询优惠券列表")
@PostMapping("/page")
public ApiResponse<PageInfo<CouponRespVO>> list(@RequestBody CouponQueryReq couponQuery) {
PageHelper.startPage(couponQuery.getPageNum(), couponQuery.getPageSize());
List<CouponRespVO> list = couponService.list(couponQuery);
PageInfo<CouponRespVO> pageInfo = new PageInfo<>(list);
return ApiResponse.success(pageInfo);
}
}

View File

@ -3,6 +3,7 @@ package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.model.pc.device.req.DeviceAddOrUpdateReq;
import com.ycwl.basic.model.pc.device.req.DeviceBatchSortRequest;
import com.ycwl.basic.model.pc.device.req.DeviceReqQuery;
import com.ycwl.basic.model.pc.device.req.DeviceSortRequest;
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
@ -62,6 +63,11 @@ public class DeviceController {
return deviceService.sortDevice(request.getDeviceId(), request.getAfterDeviceId());
}
@PostMapping("/scenic/{scenicId}/sortBatch")
public ApiResponse<Boolean> sortDeviceBatch(@PathVariable("scenicId") Long scenicId, @RequestBody DeviceBatchSortRequest request) {
return deviceService.batchSort(scenicId, request);
}
@GetMapping("/config/{id}")
public ApiResponse<DeviceConfigEntity> getConfig(@PathVariable("id") Long id) {
return ApiResponse.success(deviceService.getConfig(id));

View File

@ -0,0 +1,23 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.model.pc.scenicDeviceStats.req.DeviceStatsReq;
import com.ycwl.basic.model.pc.scenicDeviceStats.resp.ScenicDeviceStatsListResp;
import com.ycwl.basic.utils.ApiResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
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;
@RestController
@RequestMapping("/api/deviceStats/v1")
public class DeviceStatsController {
@Autowired
private com.ycwl.basic.service.pc.DeviceStatsService service;
@PostMapping("/{scenicId}")
public ApiResponse<ScenicDeviceStatsListResp> queryByScenic(@PathVariable("scenicId") Long scenicId, @RequestBody DeviceStatsReq req) {
return ApiResponse.success(service.queryByScenicId(scenicId, req.getStartTime(), req.getEndTime()));
}
}

View File

@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Deprecated
@RestController
@RequestMapping("/api/face/detect_log/v1")
public class FaceDetectLogController {

View File

@ -17,6 +17,7 @@ import java.util.List;
* @Author:longbinbin
* @Date:2024/12/2 16:33
*/
@Deprecated
@RestController
@RequestMapping("/api/faceSample/v1")
@Api(tags = "人脸样本管理")

View File

@ -0,0 +1,56 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.model.pc.permission.entity.PermissionEntity;
import com.ycwl.basic.model.pc.permission.req.PermissionSaveReq;
import com.ycwl.basic.model.pc.permission.resp.PermissionResp;
import com.ycwl.basic.service.pc.PermissionService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.ArrayList;
import java.util.Arrays;
@RestController
@RequestMapping("/api/permission/v1")
@Api(tags = "权限管理接口")
public class PermissionController {
@Autowired
private PermissionService permissionService;
@GetMapping("/get/")
public ApiResponse<PermissionResp> getPermissionByUser() {
String userId = BaseContextHandler.getUserId();
PermissionEntity permission = permissionService.getPermissionByUserId(Long.parseLong(userId));
if (permission == null || StringUtils.isEmpty(permission.getPermString())) {
return ApiResponse.success(new PermissionResp(new ArrayList<>()));
}
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermString(), ","))));
}
@ApiOperation("根据用户ID查询权限信息")
@GetMapping("/get/{userId}")
public ApiResponse<PermissionResp> getPermissionByUser(@PathVariable Long userId) {
PermissionEntity permission = permissionService.getPermissionByUserId(userId);
if (permission == null || StringUtils.isEmpty(permission.getPermString())) {
return ApiResponse.success(new PermissionResp(new ArrayList<>()));
}
return ApiResponse.success(new PermissionResp(Arrays.asList(StringUtils.split(permission.getPermString(), ","))));
}
@ApiOperation("保存或更新权限信息")
@PostMapping("/save/{userId}")
public ApiResponse saveOrUpdate(@PathVariable Long userId, @RequestBody PermissionSaveReq req) {
permissionService.saveOrUpdate(userId, StringUtils.join(req.getPermissions(), ","));
return ApiResponse.success(true);
}
}

View File

@ -47,6 +47,15 @@ public class PriceConfigController {
public ApiResponse<Boolean> deletePriceConfig(@PathVariable Integer id) {
priceRepository.clearPriceCache(id);
priceConfigService.removeById(id);
priceRepository.clearPriceCache(id);
return ApiResponse.success(true);
}
@PostMapping("/{id}/status")
public ApiResponse<Boolean> updateStatus(@PathVariable Integer id) {
priceRepository.clearPriceCache(id);
priceConfigService.updateStatus(id);
priceRepository.clearPriceCache(id);
return ApiResponse.success(true);
}

View File

@ -0,0 +1,54 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.List;
@RestController
@RequestMapping("/api/printer/v1")
public class PrinterController {
@Autowired
private PrinterService printerService;
@ApiOperation("查询列表")
@PostMapping("/list")
public ApiResponse<List<PrinterEntity>> list(@RequestBody PrinterEntity condition) {
return printerService.list(condition);
}
@ApiOperation("获取详情")
@GetMapping("/get/{id}")
public ApiResponse<PrinterEntity> get(@PathVariable("id") Integer id) {
return printerService.get(id);
}
@ApiOperation("新增")
@PostMapping("/add")
public ApiResponse<Integer> add(@RequestBody PrinterEntity entity) {
return printerService.add(entity);
}
@ApiOperation("更新")
@PostMapping("/update")
public ApiResponse<Integer> update(@RequestBody PrinterEntity entity) {
return printerService.update(entity);
}
@ApiOperation("删除")
@DeleteMapping("/delete/{id}")
public ApiResponse<Integer> delete(@PathVariable("id") Integer id) {
return printerService.delete(id);
}
}

View File

@ -0,0 +1,68 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAccountReqQuery;
import com.ycwl.basic.service.pc.ScenicAccountService;
import com.ycwl.basic.utils.ApiResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@RestController
@RequestMapping("/api/scenicAccount/v1")
public class ScenicAccountController {
@Autowired
private ScenicAccountService service;
// 添加景区账号
@PostMapping("/add")
public ApiResponse addScenicAccount(@RequestBody ScenicAccountEntity entity) {
int result = service.addScenicAccount(entity);
return result > 0 ? ApiResponse.success("添加成功") : ApiResponse.fail("添加失败");
}
// 删除景区账号
@DeleteMapping("/delete/{id}")
public ApiResponse deleteScenicAccount(@PathVariable Long id) {
int result = service.deleteScenicAccount(id);
return result > 0 ? ApiResponse.success("删除成功") : ApiResponse.fail("删除失败");
}
@PostMapping("/updateStatus/{id}")
public ApiResponse updateStatus(@PathVariable Long id) {
int result = service.updateStatus(id);
return result > 0 ? ApiResponse.success("更新成功") : ApiResponse.fail("更新失败");
}
// 更新景区账号
@PostMapping("/update")
public ApiResponse updateScenicAccount(@RequestBody ScenicAccountEntity entity) {
int result = service.updateScenicAccount(entity);
return result > 0 ? ApiResponse.success("更新成功") : ApiResponse.fail("更新失败");
}
// 根据ID查询景区账号
@GetMapping("/get/{id}")
public ApiResponse getScenicAccount(@PathVariable Long id) {
ScenicAccountEntity entity = service.getScenicAccountById(id);
return entity != null ? ApiResponse.success(entity) : ApiResponse.fail("未找到该账号");
}
// 根据景区ID查询超级账号
@GetMapping("/super/{scenicId}")
public ApiResponse getSuperAccount(@PathVariable Long scenicId) {
ScenicAccountEntity entity = service.getSuperAccountByScenicId(scenicId);
return entity != null ? ApiResponse.success(entity) : ApiResponse.fail("未找到超级账号");
}
// 新增分页查询接口
@PostMapping("/page")
public ApiResponse<PageInfo<ScenicAccountEntity>> pageQuery(@RequestBody ScenicAccountReqQuery req) {
PageHelper.startPage(req.getPageNum(), req.getPageSize());
List<ScenicAccountEntity> list = service.pageQuery(req);
PageInfo<ScenicAccountEntity> pageInfo = new PageInfo<>(list);
return ApiResponse.success(pageInfo);
}
}

View File

@ -1,13 +1,16 @@
package com.ycwl.basic.controller.pc;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.model.mobile.statistic.req.CommonQueryReq;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.service.mobile.AppStatisticsService;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.WxMpUtil;
import com.ycwl.basic.repository.ScenicRepository;
@ -34,6 +37,8 @@ public class ScenicController {
@Autowired
private ScenicRepository scenicRepository;
@Autowired
private AppStatisticsService appStatisticsService;
@ApiOperation("分页查询景区")
@PostMapping("/page")
@ -109,15 +114,40 @@ public class ScenicController {
String appState = mpConfig.getState();
String path = "pages/home/index?scenicId=" + id;
String filePath = "qr_code_" + id + ".jpg";
IStorageAdapter adapter = StorageFactory.use();
if (adapter.isExists(filePath)) {
return ApiResponse.success(adapter.getUrl(filePath));
}
try {
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
IStorageAdapter adapter = StorageFactory.use();
File file = new File(filePath);
String s = adapter.uploadFile(file, filePath);
String s = adapter.uploadFile(null, file, filePath);
file.delete();
adapter.setAcl(StorageAcl.PUBLIC_READ, filePath);
return ApiResponse.success(s);
} catch (Exception e) {
return ApiResponse.fail("生成二维码失败");
}
}
@PostMapping("/{scenicId}/one")
public ApiResponse getStatisticsOne(@PathVariable("scenicId") Long scenicId, @RequestBody CommonQueryReq query) {
query.setScenicId(scenicId);
return appStatisticsService.oneStatistics(query);
}
@PostMapping("/{scenicId}/two")
public ApiResponse getStatisticsTwo(@PathVariable("scenicId") Long scenicId, @RequestBody CommonQueryReq query) {
query.setScenicId(scenicId);
return appStatisticsService.twoStatistics(query);
}
@PostMapping("/{scenicId}/three")
public ApiResponse getStatisticsThree(@PathVariable("scenicId") Long scenicId, @RequestBody CommonQueryReq query) {
query.setScenicId(scenicId);
return appStatisticsService.freeStatistics(query);
}
@PostMapping("/{scenicId}/fun")
public ApiResponse getStatisticsFun(@PathVariable("scenicId") Long scenicId, @RequestBody CommonQueryReq query) {
query.setScenicId(scenicId);
return appStatisticsService.userConversionFunnel(query);
}
}

View File

@ -1,5 +1,6 @@
package com.ycwl.basic.controller.pc;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
@ -23,41 +24,29 @@ public class SourceController {
@Autowired
private SourceService sourceService;
@Deprecated
@ApiOperation("分页查询视频源")
@PostMapping("/page")
public ApiResponse pageQuery(@RequestBody SourceReqQuery sourceReqQuery) {
return sourceService.pageQuery(sourceReqQuery);
}
@Deprecated
@ApiOperation("查询视频源列表")
@PostMapping("/list")
public ApiResponse list(@RequestBody SourceReqQuery sourceReqQuery) {
return sourceService.list(sourceReqQuery);
}
@ApiOperation("查询视频源详情")
@GetMapping("getDetail/{id}")
public ApiResponse getById(@PathVariable Long id) {
JwtInfo worker = JwtTokenUtil.getWorker();
return sourceService.getById(id, worker.getUserId());
}
@PostMapping("/{id}/cutVideo")
@IgnoreToken
public ApiResponse cutVideo(@PathVariable("id") Long id) {
return sourceService.cutVideo(id);
}
@ApiOperation("添加视频源")
@PostMapping("/add")
public ApiResponse add(@RequestBody SourceEntity source) {
return sourceService.add(source);
}
@Deprecated
@ApiOperation("删除视频源")
@DeleteMapping("/delete/{id}")
public ApiResponse deleteById(@PathVariable Long id) {
return sourceService.deleteById(id);
}
@ApiOperation("修改视频源")
@PostMapping("/update")
public ApiResponse update(@RequestBody SourceEntity source) {
return sourceService.update(source);
}
}

View File

@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.*;
*/
@RestController
@RequestMapping("/api/task/v1")
@Deprecated
@Api(tags = "任务列表管理")
public class TaskController {

View File

@ -20,6 +20,7 @@ import java.util.List;
@RestController
@RequestMapping("/api/video/v1")
@Deprecated
@Api(tags = "视频成片管理")
public class VideoController {

View File

@ -0,0 +1,44 @@
package com.ycwl.basic.controller.printer;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.printer.req.PrinterSyncReq;
import com.ycwl.basic.model.printer.req.WorkerAuthReqVo;
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
import com.ycwl.basic.model.printer.resp.TaskSyncResp;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@IgnoreToken
@Api(tags = "打印机对接接口")
@RestController
@RequestMapping("/printer/v1")
public class PrinterTaskController {
@Autowired
private PrinterService printerService;
@PostMapping("/sync")
public ApiResponse<TaskSyncResp> sync(@RequestBody PrinterSyncReq req) {
List<PrintTaskResp> tasks = printerService.sync(req);
TaskSyncResp resp = new TaskSyncResp();
resp.setTasks(tasks);
return ApiResponse.success(resp);
}
@PostMapping("/{taskId}/success")
public ApiResponse taskSuccess(@PathVariable Integer taskId, @RequestBody WorkerAuthReqVo req) {
printerService.taskSuccess(taskId, req);
return ApiResponse.success("OK");
}
@PostMapping("/{taskId}/fail")
public ApiResponse taskFail(@PathVariable Integer taskId, @RequestBody WorkerAuthReqVo req) {
printerService.taskFail(taskId, req);
return ApiResponse.success("OK");
}
}

View File

@ -0,0 +1,76 @@
package com.ycwl.basic.controller.proxy;
import com.ycwl.basic.annotation.IgnoreToken;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
@Deprecated
@RestController
public class ProxyController {
@IgnoreToken
@RequestMapping(value = "/proxy", method = RequestMethod.GET)
public void proxy(@RequestParam(value = "url") String url,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url; // 或根据业务逻辑选择默认协议
}
// 新增User-Agent检测逻辑
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && userAgent.contains("Lavf/")) {
response.sendRedirect(url);
return;
}
// 创建HTTP连接
URL urlObj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection();
// 设置请求方法和请求头
connection.setRequestMethod("GET");
for (Enumeration<String> headers = request.getHeaderNames(); headers.hasMoreElements();) {
String headerName = headers.nextElement();
connection.addRequestProperty(headerName, request.getHeader(headerName));
}
// 处理响应
int responseCode = connection.getResponseCode();
response.setStatus(responseCode);
// 转发响应头
Map<String, List<String>> headerFields = connection.getHeaderFields();
for (Map.Entry<String, List<String>> entry : headerFields.entrySet()) {
if (entry.getKey() != null) {
for (String value : entry.getValue()) {
response.addHeader(entry.getKey(), value);
}
}
}
// 流式传输响应体
try (InputStream inputStream = connection.getInputStream();
OutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
return;
}
}
}

View File

@ -2,6 +2,7 @@ package com.ycwl.basic.controller.task;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.model.task.req.TaskReqVo;
import com.ycwl.basic.model.task.req.TaskSuccessReqVo;
@ -11,14 +12,13 @@ import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.Date;
@IgnoreToken
@RestController
@Api(tags = "渲染端对接接口")
@ -37,6 +37,11 @@ public class TaskTaskController {
return ApiResponse.success(respVo);
}
@GetMapping("/{taskId}/info")
public ApiResponse<TaskRespVO> taskInfo(@PathVariable Long taskId) {
return ApiResponse.success(taskService.taskInfo(taskId));
}
@PostMapping("/template/{templateId}")
public ApiResponse<TemplateRespVO> getTemplateById(@PathVariable Long templateId, @RequestBody WorkerAuthReqVo req) {
return ApiResponse.success(taskService.workerGetTemplate(templateId, req));
@ -45,7 +50,6 @@ public class TaskTaskController {
@PostMapping("/{taskId}/uploadUrl")
public ApiResponse<String> getUploadUrl(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
String urlForUpload = taskService.getUploadUrl(taskId, req);
urlForUpload = urlForUpload.replace("-internal.aliyuncs.com", ".aliyuncs.com");
return ApiResponse.success(urlForUpload);
}

View File

@ -1,19 +1,19 @@
package com.ycwl.basic.controller.viid;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.annotation.RequestToFile;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
import com.ycwl.basic.model.viid.entity.FaceListObject;
@ -32,6 +32,7 @@ import com.ycwl.basic.model.viid.resp.SystemTimeResp;
import com.ycwl.basic.model.viid.resp.VIIDBaseResp;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
@ -51,7 +52,8 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -59,9 +61,15 @@ import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
import static com.ycwl.basic.constant.StorageConstant.VIID_FACE;
@IgnoreToken
@RestController
@ -78,6 +86,23 @@ public class ViidController {
private DeviceRepository deviceRepository;
@Autowired
private ScenicRepository scenicRepository;
@Autowired
private TaskFaceService taskFaceService;
private final Map<Long, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
@Autowired
private ScenicService scenicService;
private ThreadPoolExecutor getExecutor(Long scenicId) {
return executors.computeIfAbsent(scenicId, k -> {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNamePrefix("VIID-" + scenicId + "-t")
.build();
return new ThreadPoolExecutor(
4, 1024, 0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1024),
threadFactory);
});
}
// region 注册注销基础接口
/**
@ -194,8 +219,6 @@ public class ViidController {
@Autowired
private FaceSampleMapper faceSampleMapper;
@Autowired
private TaskFaceService taskFaceService;
private final SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
@ -220,10 +243,6 @@ public class ViidController {
if (device == null) {
continue;
}
if (!Integer.valueOf(1).equals(device.getStatus())) {
log.info("设备状态为关闭,跳过该设备。deviceId:{}", deviceID);
continue;
}
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
int viidMode = 0;
if (deviceConfig != null && deviceConfig.getViidType() != null) {
@ -248,21 +267,15 @@ public class ViidController {
}
if (shotTime == null) {
shotTime = new Date();
} else if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) > + 24 * 60 * 60 * 1000) {
} else if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) > 24 * 60 * 60 * 1000) {
shotTime = new Date();
}
Long scenicId = device.getScenicId();
if (scenicId == null) {
continue;
}
IStorageAdapter scenicStorageAdapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
scenicStorageAdapter = StorageFactory.get(scenicConfig.getStoreType());
scenicStorageAdapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
} else {
scenicStorageAdapter = StorageFactory.use("video");
}
IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
FacePositionObject facePosition = new FacePositionObject();
facePosition.setLtY(face.getLeftTopY());
facePosition.setLtX(face.getLeftTopX());
@ -284,22 +297,33 @@ public class ViidController {
// Type=11 人脸
if (subImage.getType().equals("11")) {
// 上传oss
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
new Thread(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
}).start();
if (Integer.valueOf(1).equals(device.getStatus())) {
FaceSampleEntity faceSample = new FaceSampleEntity();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
ThreadPoolExecutor executor = getExecutor(scenicId);
executor.execute(() -> {
if (faceBodyAdapter != null) {
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
if (addFaceResp != null) {
faceSample.setScore(addFaceResp.getScore());
faceSampleMapper.update(faceSample);
}
}
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
});
}
for (SubImageInfoObject _subImage : type14ImageList) {
facePosition.setImgHeight(_subImage.getHeight());
facePosition.setImgWidth(_subImage.getWidth());
@ -334,24 +358,34 @@ public class ViidController {
// Type=14 人脸,传™的,有这么传的嘛
if (subImage.getType().equals("14")) {
// 上传oss
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
DynamicTaskGenerator.addTask(faceSample.getId());
new Thread(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
}).start();
log.info("模式1人脸信息入库成功!设备ID:{}", deviceID);
if (Integer.valueOf(1).equals(device.getStatus())) {
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
DynamicTaskGenerator.addTask(faceSample.getId());
ThreadPoolExecutor executor = getExecutor(scenicId);
executor.execute(() -> {
if (faceBodyAdapter != null) {
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
if (addFaceResp != null) {
faceSample.setScore(addFaceResp.getScore());
faceSampleMapper.update(faceSample);
}
}
if (Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
});
log.info("模式1人脸信息入库成功!设备ID:{}", deviceID);
}
}
}
}
@ -365,8 +399,7 @@ public class ViidController {
@RequestMapping(value = "/Images", method = RequestMethod.POST)
@IgnoreLogReq
public VIIDBaseResp images(@RequestBody ImageUploadReq req) {
log.info("Images:{}", req);
public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
return new VIIDBaseResp(
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
);

View File

@ -1,23 +1,19 @@
package com.ycwl.basic.controller.vpt;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.StorageConstant;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.operator.VptPassiveStorageOperator;
import com.ycwl.basic.device.operator.VptPassiveStorageOperator;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.wvp.WvpSyncReqVo;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -26,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
@IgnoreToken
@ -35,11 +30,8 @@ import java.util.Map;
@RequestMapping("/vpt/v1/")
public class VptController {
private final ScenicRepository scenicRepository;
public VptController(ScenicRepository scenicRepository) {
this.scenicRepository = scenicRepository;
}
@Autowired
private ScenicService scenicService;
@IgnoreLogReq
@PostMapping("/scenic/{scenicId}/sync")
@ -48,14 +40,7 @@ public class VptController {
}
@PostMapping("/scenic/{scenicId}/{taskId}/uploadUrl")
public String uploadUrl(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId) {
IStorageAdapter adapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
adapter = StorageFactory.get(scenicConfig.getStoreType());
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
} else {
adapter = StorageFactory.use("video");
}
IStorageAdapter adapter = scenicService.getScenicLocalStorageAdapter(scenicId);
String filename = StorageUtil.joinPath(StorageConstant.VIDEO_PIECE_PATH, taskId.toString() + ".mp4");
String urlForUpload = adapter.getUrlForUpload(new Date(System.currentTimeMillis() + 1000 * 60 * 60), "video/mp4", filename);
urlForUpload = urlForUpload.replace("-internal.aliyuncs.com", ".aliyuncs.com");
@ -63,14 +48,7 @@ public class VptController {
}
@PostMapping("/scenic/{scenicId}/{taskId}/success")
public ApiResponse<String> success(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId, @RequestBody FileObject fileObject) {
IStorageAdapter adapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
adapter = StorageFactory.get(scenicConfig.getStoreType());
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
} else {
adapter = StorageFactory.use("video");
}
IStorageAdapter adapter = scenicService.getScenicLocalStorageAdapter(scenicId);
String filename = StorageUtil.joinPath(StorageConstant.VIDEO_PIECE_PATH, taskId.toString() + ".mp4");
fileObject.setUrl(adapter.getUrl(filename));
adapter.setAcl(StorageAcl.PUBLIC_READ, filename);

View File

@ -1,23 +1,19 @@
package com.ycwl.basic.controller.wvp;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.constant.StorageConstant;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.operator.WvpPassiveStorageOperator;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.wvp.WvpSyncReqVo;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.DeviceService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -27,7 +23,6 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
@IgnoreToken
@ -39,7 +34,7 @@ public class WvpController {
@Autowired
private DeviceService deviceService;
@Autowired
private ScenicRepository scenicRepository;
private ScenicService scenicService;
@IgnoreLogReq
@PostMapping("/scenic/{scenicId}/sync")
@ -50,14 +45,7 @@ public class WvpController {
@PostMapping("/scenic/{scenicId}/{taskId}/uploadUrl")
public String uploadUrl(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId) {
IStorageAdapter adapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
adapter = StorageFactory.get(scenicConfig.getStoreType());
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
} else {
adapter = StorageFactory.use("video");
}
IStorageAdapter adapter = scenicService.getScenicLocalStorageAdapter(scenicId);
String filename = StorageUtil.joinPath(StorageConstant.VIDEO_PIECE_PATH, taskId.toString() + ".mp4");
String urlForUpload = adapter.getUrlForUpload(new Date(System.currentTimeMillis() + 1000 * 60 * 60), "video/mp4", filename);
urlForUpload = urlForUpload.replace("-internal.aliyuncs.com", ".aliyuncs.com");
@ -65,14 +53,7 @@ public class WvpController {
}
@PostMapping("/scenic/{scenicId}/{taskId}/success")
public ApiResponse<String> success(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId, @RequestBody FileObject fileObject) {
IStorageAdapter adapter;
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null && scenicConfig.getStoreType() != null) {
adapter = StorageFactory.get(scenicConfig.getStoreType());
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
} else {
adapter = StorageFactory.use("video");
}
IStorageAdapter adapter = scenicService.getScenicLocalStorageAdapter(scenicId);
String filename = StorageUtil.joinPath(StorageConstant.VIDEO_PIECE_PATH, taskId.toString() + ".mp4");
fileObject.setUrl(adapter.getUrl(filename));
adapter.setAcl(StorageAcl.PUBLIC_READ, filename);

View File

@ -76,7 +76,7 @@ public class AliOssStorageOperator extends ADeviceStorageOperator {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.set(Calendar.SECOND, 0);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd/HHmm");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
while (calendar.getTime().before(endDate)) {
String prefix = dateFormat.format(calendar.getTime());
List<FileObject> fileListByPrefix = getOssFileListByPrefix(prefix);

View File

@ -1,6 +1,8 @@
package com.ycwl.basic.device.operator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.entity.vpt_passive.VptPassiveStorageConfig;
import com.ycwl.basic.device.entity.wvp_passive.WvpPassiveStorageConfig;
@ -9,6 +11,7 @@ import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.ArrayList;
import java.util.Collections;
@ -16,6 +19,7 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@ -25,12 +29,18 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
public Long scenicId;
public Long deviceId;
public String deviceNo;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date startTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date endTime;
}
private static List<Task> taskList = new CopyOnWriteArrayList<>();
private static ConcurrentHashMap<Long, FileObject> fileListMap = new ConcurrentHashMap<>();
private static RedisTemplate<String, String> redisTemplate = null;
private static final String TASK_KEY = "vpt:task:s%s:d%s:";
private VptPassiveStorageConfig config;
@ -38,6 +48,10 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
loadConfig(configJson);
}
public static void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
VptPassiveStorageOperator.redisTemplate = redisTemplate;
}
public static void onReceiveResult(Long taskId, FileObject fileObject) {
if (fileObject == null) {
log.info("任务{}获取视频失败!", taskId);
@ -77,11 +91,15 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
}
task.startTime = startDate;
task.endTime = endDate;
taskList.add(task);
if (redisTemplate == null) {
taskList.add(task);
} else {
redisTemplate.opsForValue().set(String.format(TASK_KEY, task.scenicId, task.deviceNo) + task.taskId, JSON.toJSONString(task), 10 * 60L, TimeUnit.SECONDS);
}
log.info("任务{}获取视频开始!共{}", task.taskId, taskList.size());
Date taskStartTime = new Date();
while (true) {
if (new Date().getTime() - taskStartTime.getTime() > 80000L) {
if (new Date().getTime() - taskStartTime.getTime() > 60000L) {
log.info("任务{}获取视频超时!", task.taskId);
fileListMap.remove(task.taskId);
return Collections.emptyList();
@ -99,6 +117,7 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
}
} else {
try {
//noinspection BusyWait 得等待
Thread.sleep(1000L);
} catch (InterruptedException e) {
return Collections.emptyList();

View File

@ -1,12 +1,15 @@
package com.ycwl.basic.device.operator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ycwl.basic.device.entity.common.FileObject;
import com.ycwl.basic.device.entity.wvp_passive.WvpPassiveStorageConfig;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.ArrayList;
import java.util.Collections;
@ -14,21 +17,29 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
public class WvpPassiveStorageOperator extends ADeviceStorageOperator {
public static class Task {
public Long taskId;
public Long scenicId;
public Long deviceId;
public String deviceNo;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date startTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date endTime;
}
private static List<Task> taskList = new CopyOnWriteArrayList<>();
private static ConcurrentHashMap<Long, FileObject> fileListMap = new ConcurrentHashMap<>();
private static RedisTemplate<String, String> redisTemplate = null;
private static final String TASK_KEY = "wvp:task:s%s:d%s:";
private WvpPassiveStorageConfig config;
@ -36,6 +47,11 @@ public class WvpPassiveStorageOperator extends ADeviceStorageOperator {
loadConfig(configJson);
}
public static void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
WvpPassiveStorageOperator.redisTemplate = redisTemplate;
}
public static void onReceiveResult(Long taskId, FileObject fileObject) {
if (fileObject == null) {
log.info("任务{}获取视频失败!", taskId);
@ -72,10 +88,14 @@ public class WvpPassiveStorageOperator extends ADeviceStorageOperator {
}
task.startTime = startDate;
task.endTime = endDate;
taskList.add(task);
if (redisTemplate == null) {
taskList.add(task);
} else {
redisTemplate.opsForValue().set(String.format(TASK_KEY, task.scenicId, task.deviceNo) + task.taskId, JSON.toJSONString(task), 10 * 60L, TimeUnit.SECONDS);
}
Date taskStartTime = new Date();
while (true) {
if (new Date().getTime() - taskStartTime.getTime() > 80000L) {
if (new Date().getTime() - taskStartTime.getTime() > 60000L) {
log.info("任务{}获取视频超时!", task.taskId);
fileListMap.remove(task.taskId);
return Collections.emptyList();
@ -93,6 +113,7 @@ public class WvpPassiveStorageOperator extends ADeviceStorageOperator {
}
} else {
try {
//noinspection BusyWait 得等待
Thread.sleep(1000L);
} catch (InterruptedException e) {
return Collections.emptyList();

View File

@ -0,0 +1,20 @@
package com.ycwl.basic.device.starter;
import com.ycwl.basic.device.operator.VptPassiveStorageOperator;
import com.ycwl.basic.device.operator.WvpPassiveStorageOperator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class DeviceStorageOperatorStarter implements InitializingBean {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public void afterPropertiesSet() {
WvpPassiveStorageOperator.setRedisTemplate(redisTemplate);
VptPassiveStorageOperator.setRedisTemplate(redisTemplate);
}
}

View File

@ -1,20 +0,0 @@
package com.ycwl.basic.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* 是否同意用户协议枚举
*
* @author songmingsong
*/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum AgreementEnum {
AGREE(1, "同意"),
NOT_AGREE(0, "未同意");
private int type;
private String remark;
}

View File

@ -1,69 +0,0 @@
package com.ycwl.basic.enums;
import java.util.HashMap;
import java.util.Map;
/**
* @Author:longbinbin
* @Date:2024/12/6 16:46
*/
public enum GoodsTypeEnum {
VIDEO(1,"成片"),
SOURCE(2,"源素材")
;
public Integer code;
private String value;
public static final Map<Integer, GoodsTypeEnum> cacheMap;
static {
cacheMap = new HashMap<>(GoodsTypeEnum.values().length);
for (GoodsTypeEnum value : GoodsTypeEnum.values()) {
cacheMap.put(value.code, value);
}
}
public static final java.util.Map<String, GoodsTypeEnum> valueMap;
static {
valueMap = new HashMap<>(GoodsTypeEnum.values().length);
for (GoodsTypeEnum value : GoodsTypeEnum.values()) {
valueMap.put(value.value, value);
}
}
GoodsTypeEnum(Integer code, String value) {
this.code = code;
this.value = value;
}
/**
* 获取value值
*/
public static String getValue(Integer noticeMethod) {
if (noticeMethod == null) {
return null;
}
GoodsTypeEnum GoodsTypeEnum = cacheMap.get(noticeMethod);
if (GoodsTypeEnum == null) {
return null;
}
return GoodsTypeEnum.value;
}
/**
* 获取code值
*/
public static Integer getCode(String noticeMethod) {
if (noticeMethod == null) {
return -1;
}
GoodsTypeEnum GoodsTypeEnum = valueMap.get(noticeMethod);
if (GoodsTypeEnum == null) {
return -1;
}
return GoodsTypeEnum.code;
}
}

View File

@ -2,11 +2,13 @@ package com.ycwl.basic.exception;
import com.ycwl.basic.enums.BizCodeEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author songminsgong
* @since 2022-11-23
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AppException extends RuntimeException {

View File

@ -2,11 +2,13 @@ package com.ycwl.basic.exception;
import com.ycwl.basic.enums.BizCodeEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author wenshijia
* @date 2021年05月25日 22:41
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BizException extends RuntimeException {

View File

@ -1,10 +1,8 @@
package com.ycwl.basic.exception;
import com.ycwl.basic.aspectj.HttpSaver;
import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.notify.NotifyFactory;
import com.ycwl.basic.notify.entity.NotifyContent;
import com.ycwl.basic.utils.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -12,14 +10,11 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.stream.Collectors;
/**
* @date 2022年09月23日 10:19
@ -58,13 +53,21 @@ public class CustomExceptionHandle {
* 自定义异常统一处理类
*/
@ExceptionHandler(value = BizException.class)
public ApiResponse<String> handle(BizException bizException) {
public ApiResponse<String> handle(HttpServletResponse response, BizException bizException) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return ApiResponse.buildResponse(bizException.getCode(), bizException.getMsg());
}
@ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
public ApiResponse<String> handle(HttpServletRequest request, HttpServletResponse response, MethodArgumentTypeMismatchException exception) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
LOGGER.error("参数错误 -> 请求地址:{},请求方式:{}", request.getRequestURI(), request.getMethod());
return ApiResponse.buildResponse(5000, "参数错误!");
}
@ExceptionHandler(value =IOException.class)
public ApiResponse<String> handle(IOException e) {
LOGGER.error("系统异常 -> {}", e.getMessage(), e);
public ApiResponse<String> handle(HttpServletResponse response, IOException e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
LOGGER.error("IO异常 -> {}", e.getMessage(), e);
return ApiResponse.buildResult(BizCodeEnum.SERVER_UNKONWN_ERROR);
}
@ -72,62 +75,18 @@ public class CustomExceptionHandle {
* 异常统一返回处理
*/
@ExceptionHandler(value = Exception.class)
public ApiResponse<String> handle(Exception e) {
public ApiResponse<String> handle(HttpServletResponse response, Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
LOGGER.error("系统异常 -> {}", e.getMessage(), e);
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
try {
HttpSaver.saveRequestToFile(attributes.getRequest());
} catch (IOException ex) {
LOGGER.error("保存请求信息失败 -> {}", e.getMessage(), e);
}
}
return ApiResponse.buildResult(BizCodeEnum.SERVER_UNKONWN_ERROR);
}
public String getStackTrace(Throwable e) {
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = e.getStackTrace();
sb.append(e.getClass().getName()).append(": ").append(e.getMessage()).append("\r\n");
for (StackTraceElement stackTraceElement : stackTrace) {
sb.append("\tat ").append(stackTraceElement.toString()).append("\r\n");
}
return sb.toString();
}
public String getRequestAsText() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return "---";
}
HttpServletRequest request = attributes.getRequest();
StringBuilder rawReq = new StringBuilder();
rawReq.append(request.getMethod()).append(" ").append(request.getRequestURL());
String queryString = request.getQueryString();
if (queryString != null) {
rawReq.append("?").append(queryString);
}
rawReq.append("\r\n");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
rawReq.append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
}
rawReq.append("\r\n");
// 获取body
try {
rawReq.append(request.getReader().lines().collect(Collectors.joining("\r\n")));
rawReq.append("\r\n");
} catch (IOException ignored) {
}
return rawReq.toString();
}
/**
* 移动端自定义异常统一处理类
*/
@ExceptionHandler(value = AppException.class)
public ApiResponse<String> handle(AppException appException) {
public ApiResponse<String> handle(HttpServletResponse response, AppException appException) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return ApiResponse.buildResponse(appException.getCode(), appException.getMsg());
}
@ -135,7 +94,8 @@ public class CustomExceptionHandle {
* 移动端自定义异常统一处理类
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public ApiResponse<String> handle(HttpMessageNotReadableException httpMessageNotReadableException) {
public ApiResponse<String> handle(HttpServletResponse response, HttpMessageNotReadableException httpMessageNotReadableException) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return ApiResponse.buildResponse(500, "请求参数格式错误");
}

View File

@ -0,0 +1,59 @@
package com.ycwl.basic.facebody;
import com.ycwl.basic.facebody.adapter.AliFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.BceFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import com.ycwl.basic.facebody.exceptions.FaceBodyUnsupportedException;
import com.ycwl.basic.storage.exceptions.StorageConfigException;
import com.ycwl.basic.storage.exceptions.StorageUndefinedException;
import java.util.HashMap;
import java.util.Map;
public class FaceBodyFactory {
public static IFaceBodyAdapter getAdapter(String typeName) {
FaceBodyAdapterType adapterEnum;
try {
adapterEnum = FaceBodyAdapterType.valueOf(typeName);
} catch (Exception e) {
throw new FaceBodyUnsupportedException("不支持的Adapter类型");
}
return getAdapter(adapterEnum);
}
public static IFaceBodyAdapter getAdapter(FaceBodyAdapterType type) {
return switch (type) {
case ALI -> new AliFaceBodyAdapter();
case BCE -> new BceFaceBodyAdapter();
default -> throw new FaceBodyUnsupportedException("不支持的Adapter类型");
};
}
protected static Map<String, IFaceBodyAdapter> namedAdapter = new HashMap<>();
protected static IFaceBodyAdapter defaultAdapter = null;
public static void register(String name, IFaceBodyAdapter adapter) {
namedAdapter.put(name, adapter);
}
public static IFaceBodyAdapter use(String name) {
IFaceBodyAdapter adapter = namedAdapter.get(name);
if (adapter == null) {
throw new StorageUndefinedException("未定义的存储方式:"+name);
}
return adapter;
}
public static IFaceBodyAdapter use() {
if (defaultAdapter == null) {
throw new StorageConfigException("未定义默认存储方式");
}
return defaultAdapter;
}
public static void setDefault(String defaultName) {
FaceBodyFactory.defaultAdapter = use(defaultName);
}
}

View File

@ -0,0 +1,322 @@
package com.ycwl.basic.facebody.adapter;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.facebody.model.v20191230.AddFaceEntityRequest;
import com.aliyuncs.facebody.model.v20191230.AddFaceRequest;
import com.aliyuncs.facebody.model.v20191230.AddFaceResponse;
import com.aliyuncs.facebody.model.v20191230.CreateFaceDbRequest;
import com.aliyuncs.facebody.model.v20191230.DeleteFaceDbRequest;
import com.aliyuncs.facebody.model.v20191230.DeleteFaceEntityRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceDbsRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceDbsResponse;
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesRequest;
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesResponse;
import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
import com.aliyuncs.facebody.model.v20191230.SearchFaceResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.facebody.entity.AliFaceBodyConfig;
import com.ycwl.basic.facebody.entity.SearchFaceResp;
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
import com.ycwl.basic.utils.ratelimiter.FixedRateLimiter;
import com.ycwl.basic.utils.ratelimiter.IRateLimiter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
public class AliFaceBodyAdapter implements IFaceBodyAdapter {
private static final Map<String, IRateLimiter> addEntityLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> addFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> addDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> listDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> listFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> searchFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> deleteDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> deleteEntityLimiters = new ConcurrentHashMap<>();
private AliFaceBodyConfig config;
public boolean setConfig(AliFaceBodyConfig config) {
this.config = config;
return true;
}
@Override
public boolean loadConfig(Map<String, String> _config) {
AliFaceBodyConfig config = new AliFaceBodyConfig();
config.setAccessKeyId(_config.get("accessKeyId"));
config.setAccessKeySecret(_config.get("accessKeySecret"));
config.setRegion(_config.get("region"));
this.config = config;
return true;
}
private IRateLimiter getLimiter(LOCK_TYPE type) {
return switch (type) {
case ADD_DB ->
addDbLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS));
case ADD_ENTITY ->
addEntityLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS));
case ADD_FACE ->
addFaceLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS));
case LIST_DB ->
listDbLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(500, TimeUnit.MILLISECONDS));
case LIST_FACE -> listFaceLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(2));
case SEARCH_FACE ->
searchFaceLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(200, TimeUnit.MILLISECONDS));
case DELETE_DB ->
deleteDbLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS));
case DELETE_ENTITY ->
deleteEntityLimiters.computeIfAbsent(config.getAccessKeyId(), k -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS));
default -> new FixedRateLimiter(600, TimeUnit.MILLISECONDS);
};
}
@Override
public boolean addFaceDb(String dbName) {
IRateLimiter addDbLimiter = getLimiter(LOCK_TYPE.ADD_DB);
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
CreateFaceDbRequest request = new CreateFaceDbRequest();
request.setName(dbName);
try {
addDbLimiter.acquire();
} catch (InterruptedException ignored) {
}
client.getAcsResponse(request);
return true;
} catch (ClientException e) {
log.error("阿里云添加人脸数据库失败!", e);
return false;
}
}
@Override
public boolean deleteFaceDb(String dbName) {
ListFaceEntitiesRequest request = new ListFaceEntitiesRequest();
IRateLimiter deleteEntityLimiter = getLimiter(LOCK_TYPE.DELETE_ENTITY);
IRateLimiter deleteDbLimiter = getLimiter(LOCK_TYPE.DELETE_DB);
request.setDbName(dbName);
request.setOrder("asc");
request.setLimit(200);
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
while (true) {
ListFaceEntitiesResponse response = client.getAcsResponse(request);
if (response.getData().getTotalCount() == 0) {
break;
}
response.getData().getEntities().forEach(entity -> {
DeleteFaceEntityRequest deleteFaceEntityRequest = new DeleteFaceEntityRequest();
deleteFaceEntityRequest.setDbName(entity.getDbName());
deleteFaceEntityRequest.setEntityId(entity.getEntityId());
try {
deleteEntityLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
client.getAcsResponse(deleteFaceEntityRequest);
} catch (ClientException e) {
log.error("删除人脸数据失败!", e);
}
});
}
DeleteFaceDbRequest deleteFaceDbRequest = new DeleteFaceDbRequest();
deleteFaceDbRequest.setName(dbName);
try {
deleteDbLimiter.acquire();
} catch (InterruptedException ignored) {
}
client.getAcsResponse(deleteFaceDbRequest);
} catch (ClientException e) {
log.error("删除人脸数据库失败!", e);
return false;
}
return true;
}
@Override
public List<String> listFaceDb() {
ListFaceDbsRequest request = new ListFaceDbsRequest();
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
ListFaceDbsResponse response = client.getAcsResponse(request);
return response.getData().getDbList().stream().map(ListFaceDbsResponse.Data.DbListItem::getName).collect(Collectors.toList());
} catch (ClientException e) {
log.error("获取人脸数据库失败!", e);
return Collections.emptyList();
}
}
@Override
public AddFaceResp addFace(String dbName, String entityId, String faceUrl, String extData) {
IRateLimiter addEntityLimiter = getLimiter(LOCK_TYPE.ADD_ENTITY);
IRateLimiter addFaceLimiter = getLimiter(LOCK_TYPE.ADD_FACE);
AddFaceEntityRequest request = new AddFaceEntityRequest();
request.setDbName(dbName);
request.setEntityId(entityId);
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
try {
addEntityLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
client.getAcsResponse(request);
} catch (ClientException e) {
log.error("addFaceEntity, {}/{}", dbName, entityId, e);
return null;
}
AddFaceRequest addFaceRequest = new AddFaceRequest();
addFaceRequest.setDbName(dbName);
addFaceRequest.setEntityId(entityId);
addFaceRequest.setImageUrl(faceUrl);
addFaceRequest.setExtraData(extData);
AddFaceResp respVo = new AddFaceResp();
try {
addFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
AddFaceResponse acsResponse = client.getAcsResponse(addFaceRequest);
respVo.setScore(acsResponse.getData().getQualitieScore());
return respVo;
} catch (ClientException e) {
log.error("addFace, {}/{}", dbName, entityId, e);
return null;
}
}
}
@Override
public boolean deleteFace(String dbName, String entityId) {
IRateLimiter deleteEntityLimiter = getLimiter(LOCK_TYPE.DELETE_ENTITY);
DeleteFaceEntityRequest request = new DeleteFaceEntityRequest();
request.setDbName(dbName);
request.setEntityId(entityId);
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
try {
deleteEntityLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
client.getAcsResponse(request);
return true;
} catch (ClientException e) {
log.error("删除人脸数据失败!", e);
return false;
}
}
}
@Override
public List<String> listFace(String dbName, String prefix, Integer offset, Integer size) {
IRateLimiter listFaceLimiter = getLimiter(LOCK_TYPE.LIST_FACE);
ListFaceEntitiesRequest listFaceEntitiesRequest = new ListFaceEntitiesRequest();
listFaceEntitiesRequest.setDbName(dbName);
listFaceEntitiesRequest.setOrder("asc");
if (offset != null) {
listFaceEntitiesRequest.setOffset(offset);
}
listFaceEntitiesRequest.setLimit(Objects.requireNonNullElse(size, 200));
if (StringUtils.isNotEmpty(prefix)) {
listFaceEntitiesRequest.setEntityIdPrefix(prefix);
}
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
try {
listFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
ListFaceEntitiesResponse response = client.getAcsResponse(listFaceEntitiesRequest);
return response.getData().getEntities().stream().map(ListFaceEntitiesResponse.Data.Entity::getEntityId).collect(Collectors.toList());
} catch (ClientException e) {
log.error("获取人脸数据失败!", e);
return Collections.emptyList();
}
}
}
@Override
public SearchFaceResp searchFace(String dbName, String faceUrl) {
SearchFaceResp resp = new SearchFaceResp();
IRateLimiter searchFaceLimiter = getLimiter(LOCK_TYPE.SEARCH_FACE);
try (ClientWrapper clientWrapper = getClient()) {
IAcsClient client = clientWrapper.client();
SearchFaceRequest request = new SearchFaceRequest();
request.setDbName(dbName);
request.setImageUrl(faceUrl);
request.setLimit(100);
try {
searchFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
try {
SearchFaceResponse response = client.getAcsResponse(request);
List<SearchFaceResponse.Data.MatchListItem> matchList = response.getData().getMatchList();
if (matchList.isEmpty()) {
resp.setOriginalFaceScore(0f);
return resp;
}
SearchFaceResponse.Data.MatchListItem matchItem = matchList.getFirst();
resp.setOriginalFaceScore(matchItem.getQualitieScore());
resp.setResult(matchItem.getFaceItems().stream().map(item -> {
SearchFaceResultItem resultItem = new SearchFaceResultItem();
resultItem.setDbName(dbName);
resultItem.setFaceId(item.getFaceId());
resultItem.setExtData(item.getExtraData());
resultItem.setScore(item.getScore());
return resultItem;
}).collect(Collectors.toList()));
if (!resp.getResult().isEmpty()) {
resp.setFirstMatchRate(resp.getResult().getFirst().getScore());
}
return resp;
} catch (ClientException e) {
log.error("搜索人脸失败!", e);
return null;
}
}
}
public ClientWrapper getClient() {
DefaultProfile profile = DefaultProfile.getProfile(
config.getRegion(), config.getAccessKeyId(), config.getAccessKeySecret());
IAcsClient client = new DefaultAcsClient(profile);
return new ClientWrapper(client);
}
public record ClientWrapper(IAcsClient client) implements AutoCloseable {
@Override
public void close() {
if (client == null) {
return;
}
client.shutdown();
}
}
protected enum LOCK_TYPE {
ADD_DB,
ADD_ENTITY,
ADD_FACE,
LIST_DB,
LIST_FACE,
SEARCH_FACE,
DELETE_DB,
DELETE_ENTITY,
}
}

View File

@ -0,0 +1,369 @@
package com.ycwl.basic.facebody.adapter;
import com.baidu.aip.face.AipFace;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.facebody.entity.BceFaceBodyConfig;
import com.ycwl.basic.facebody.entity.SearchFaceResp;
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
import com.ycwl.basic.utils.ratelimiter.FixedRateLimiter;
import com.ycwl.basic.utils.ratelimiter.IRateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class BceFaceBodyAdapter implements IFaceBodyAdapter {
protected static final Map<String, AipFace> clients = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> addEntityLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> addFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> addDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> listDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> listFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> searchFaceLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> deleteDbLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> deleteEntityLimiters = new ConcurrentHashMap<>();
private static final Map<String, IRateLimiter> deleteFaceLimiters = new ConcurrentHashMap<>();
private BceFaceBodyConfig config;
public boolean setConfig(BceFaceBodyConfig config) {
this.config = config;
return true;
}
@Override
public boolean loadConfig(Map<String, String> _config) {
BceFaceBodyConfig config = new BceFaceBodyConfig();
config.setAppId(_config.get("appId"));
config.setApiKey(_config.get("apiKey"));
config.setSecretKey(_config.get("secretKey"));
config.setAddQps(Float.parseFloat(_config.get("addQps")));
config.setSearchQps(Float.parseFloat(_config.get("searchQps")));
this.config = config;
return true;
}
@Override
public boolean addFaceDb(String dbName) {
IRateLimiter addDbLimiter = getLimiter(LOCK_TYPE.ADD_DB);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
try {
addDbLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.groupAdd(dbName, options);
if (response.getInt("error_code") == 0) {
return true;
} else {
log.warn("创建人脸库失败!{}", response);
return false;
}
} catch (Exception e) {
log.error("创建人脸库失败!", e);
return false;
}
}
@Override
public boolean deleteFaceDb(String dbName) {
IRateLimiter deleteDbLimiter = getLimiter(LOCK_TYPE.DELETE_DB);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
try {
deleteDbLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.groupDelete(dbName, options);
if (response.getInt("error_code") == 0) {
return true;
} else {
log.warn("删除人脸库失败!{}", response);
return false;
}
} catch (Exception e) {
log.error("删除人脸库失败!", e);
return false;
}
}
@Override
public List<String> listFaceDb() {
IRateLimiter listDbLimiter = getLimiter(LOCK_TYPE.LIST_DB);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
options.put("start", "0");
options.put("length", "1000");
try {
listDbLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.getGroupList(options);
if (response.getInt("error_code") == 0) {
JSONObject resultObj = response.getJSONObject("result");
if (resultObj != null) {
JSONArray data = resultObj.getJSONArray("group_id_list");
List<String> result = new ArrayList<>();
for (int i = 0; i < data.length(); i++) {
result.add(data.getString(i));
}
return result;
} else {
return Collections.emptyList();
}
} else {
log.warn("获取人脸库列表失败!{}", response);
return Collections.emptyList();
}
} catch (Exception e) {
log.error("获取人脸库列表失败!", e);
return Collections.emptyList();
}
}
@Override
public AddFaceResp addFace(String dbName, String entityId, String faceUrl, String extData) {
IRateLimiter addEntityLimiter = getLimiter(LOCK_TYPE.ADD_FACE);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
options.put("user_info", extData);
// options.put("quality_control", "LOW");
options.put("action_type", "REPLACE");
try {
addEntityLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.addUser(faceUrl, "URL", dbName, entityId, options);
if (response.getInt("error_code") == 0) {
AddFaceResp resp = new AddFaceResp();
resp.setScore(100f);
return resp;
} else {
log.warn("创建人脸失败!{}", response);
return null;
}
} catch (Exception e) {
log.error("创建人脸失败!", e);
return null;
}
}
@Override
public boolean deleteFace(String dbName, String entityId) {
IRateLimiter deleteFaceLimiter = getLimiter(LOCK_TYPE.DELETE_FACE);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
List<String> tokenList = listUserFace(dbName, entityId);
if (tokenList == null) {
return false;
}
AtomicInteger count = new AtomicInteger(0);
tokenList.forEach(faceToken -> {
try {
try {
deleteFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.faceDelete(entityId, dbName, faceToken, options);
if (response.getInt("error_code") != 0) {
log.warn("删除人脸失败!{}", response);
} else {
count.incrementAndGet();
}
} catch (Exception e) {
log.error("删除人脸失败!", e);
}
});
return Integer.valueOf(count.get()).equals(tokenList.size());
} catch (Exception e) {
log.error("删除人脸失败!", e);
return false;
}
}
@Override
public List<String> listFace(String dbName, String prefix, Integer offset, Integer size) {
IRateLimiter listFaceLimiter = getLimiter(LOCK_TYPE.LIST_FACE);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
options.put("start", offset == null ? "0" : offset.toString());
options.put("length", size == null ? "1000" : size.toString());
try {
listFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.getGroupUsers(dbName, options);
if (response.getInt("error_code") == 0) {
JSONObject resultObj = response.getJSONObject("result");
if (resultObj != null) {
JSONArray data = resultObj.getJSONArray("user_id_list");
List<String> result = new ArrayList<>();
for (int i = 0; i < data.length(); i++) {
result.add(data.getString(i));
}
return result;
} else {
return Collections.emptyList();
}
} else {
log.warn("获取人脸列表失败!{}", response);
return Collections.emptyList();
}
} catch (Exception e) {
log.error("获取人脸列表失败!", e);
return Collections.emptyList();
}
}
public List<String> listUserFace(String dbName, String entityId) {
IRateLimiter listFaceLimiter = getLimiter(LOCK_TYPE.LIST_FACE);
try {
AipFace client = getClient();
HashMap<String, String> options = new HashMap<>();
try {
listFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.faceGetlist(entityId, dbName, options);
if (response.getInt("error_code") == 0) {
JSONObject resultObj = response.getJSONObject("result");
if (resultObj != null) {
try {
JSONArray faceList = resultObj.getJSONArray("face_list");
List<String> result = new ArrayList<>();
for (int i = 0; i < faceList.length(); i++) {
JSONObject jsonObject = faceList.getJSONObject(i);
result.add(jsonObject.getString("face_token"));
}
return result;
} catch (Exception e) {
return Collections.emptyList();
}
} else {
return Collections.emptyList();
}
} else if (response.getInt("error_code") == 223103) {
// 用户不存在
return Collections.emptyList();
} else {
log.warn("获取人脸列表失败!{}", response);
return null;
}
} catch (Exception e) {
log.error("获取人脸列表失败!", e);
return null;
}
}
@Override
public SearchFaceResp searchFace(String dbName, String faceUrl) {
IRateLimiter searchFaceLimiter = getLimiter(LOCK_TYPE.SEARCH_FACE);
SearchFaceResp resp = new SearchFaceResp();
try {
AipFace client = getClient();
HashMap<String, Object> options = new HashMap<>();
options.put("quality_control", "LOW");
options.put("max_user_num", "50");
try {
searchFaceLimiter.acquire();
} catch (InterruptedException ignored) {
}
JSONObject response = client.search(faceUrl, "URL", dbName, options);
if (response.getInt("error_code") == 0) {
resp.setOriginalFaceScore(100f);
JSONObject resultObj = response.getJSONObject("result");
if (resultObj == null) {
resp.setFirstMatchRate(0f);
return resp;
}
JSONArray userList = resultObj.getJSONArray("user_list");
List<SearchFaceResultItem> result = new ArrayList<>();
for (int i = 0; i < userList.length(); i++) {
JSONObject user = userList.getJSONObject(i);
SearchFaceResultItem item = new SearchFaceResultItem();
item.setDbName(dbName);
item.setFaceId(user.getString("user_id"));
item.setExtData(user.getString("user_info"));
item.setScore(user.getBigDecimal("score").divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP).floatValue());
result.add(item);
}
resp.setResult(result);
if (!result.isEmpty()) {
resp.setFirstMatchRate(result.getFirst().getScore());
}
return resp;
} else {
resp.setOriginalFaceScore(0f);
return resp;
}
} catch (Exception e) {
log.error("搜索人脸失败!", e);
return null;
}
}
public AipFace getClient() {
if (clients.containsKey(config.getAppId())) {
return clients.get(config.getAppId());
}
synchronized (clients) {
if (clients.containsKey(config.getAppId())) {
return clients.get(config.getAppId());
}
AipFace client = new AipFace(config.getAppId(), config.getApiKey(), config.getSecretKey());
client.setConnectionTimeoutInMillis(5000);
client.setSocketTimeoutInMillis(60000);
clients.put(config.getAppId(), client);
return client;
}
}
private IRateLimiter getLimiter(LOCK_TYPE type) {
return switch (type) {
case ADD_DB ->
addDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
case ADD_FACE ->
addFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(config.getAddQps()));
case LIST_DB ->
listDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
case LIST_FACE ->
listFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
case SEARCH_FACE ->
searchFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(config.getSearchQps()));
case DELETE_DB ->
deleteDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
case DELETE_ENTITY ->
deleteEntityLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
case DELETE_FACE ->
deleteFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
default -> new FixedRateLimiter(500, TimeUnit.MILLISECONDS);
};
}
protected enum LOCK_TYPE {
ADD_DB,
ADD_FACE,
LIST_DB,
LIST_FACE,
SEARCH_FACE,
DELETE_DB,
DELETE_ENTITY,
DELETE_FACE,
}
}

View File

@ -0,0 +1,29 @@
package com.ycwl.basic.facebody.adapter;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.facebody.entity.SearchFaceResp;
import java.util.List;
import java.util.Map;
public interface IFaceBodyAdapter {
boolean loadConfig(Map<String, String> _config);
default boolean assureFaceDb(String dbName) {
List<String> faceDbs = listFaceDb();
return faceDbs.contains(dbName) || addFaceDb(dbName);
}
boolean addFaceDb(String dbName);
boolean deleteFaceDb(String dbName);
List<String> listFaceDb();
AddFaceResp addFace(String dbName, String entityId, String faceUrl, String extData);
boolean deleteFace(String dbName, String entityId);
List<String> listFace(String dbName, String prefix, Integer offset, Integer size);
SearchFaceResp searchFace(String dbName, String faceUrl);
}

View File

@ -0,0 +1,8 @@
package com.ycwl.basic.facebody.entity;
import lombok.Data;
@Data
public class AddFaceResp {
private Float score;
}

View File

@ -0,0 +1,10 @@
package com.ycwl.basic.facebody.entity;
import lombok.Data;
@Data
public class AliFaceBodyConfig {
private String accessKeyId;
private String accessKeySecret;
private String region;
}

View File

@ -0,0 +1,12 @@
package com.ycwl.basic.facebody.entity;
import lombok.Data;
@Data
public class BceFaceBodyConfig {
private String appId;
private String apiKey;
private String secretKey;
private float addQps = 2.0f;
private float searchQps = 2.0f;
}

View File

@ -0,0 +1,13 @@
package com.ycwl.basic.facebody.entity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class SearchFaceResp {
private Float originalFaceScore;
private List<SearchFaceResultItem> result = new ArrayList<>();
private Float firstMatchRate;
}

View File

@ -0,0 +1,12 @@
package com.ycwl.basic.facebody.entity;
import lombok.Data;
@Data
public class SearchFaceResultItem {
private String dbName;
private String faceId;
private String extData;
/** 置信度,0~1 */
private Float score;
}

View File

@ -0,0 +1,18 @@
package com.ycwl.basic.facebody.enums;
import lombok.Getter;
@Getter
public enum FaceBodyAdapterType {
ALI("ALI"),
BCE("BCE"),
;
private final String code;
FaceBodyAdapterType(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.facebody.exceptions;
public class FaceBodyException extends RuntimeException {
public FaceBodyException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.facebody.exceptions;
public class FaceBodyUnsupportedException extends RuntimeException {
public FaceBodyUnsupportedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,32 @@
package com.ycwl.basic.facebody.starter;
import com.ycwl.basic.facebody.FaceBodyFactory;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.starter.config.FaceBodyConfig;
import com.ycwl.basic.facebody.starter.config.OverallFaceBodyConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FaceBodyAutoConfiguration {
private final OverallFaceBodyConfig config;
public FaceBodyAutoConfiguration(OverallFaceBodyConfig config) {
this.config = config;
if (config != null) {
if (config.getConfigs() != null) {
loadConfig();
}
if (StringUtils.isNotBlank(config.getDefaultUse())) {
FaceBodyFactory.setDefault(config.getDefaultUse());
}
}
}
private void loadConfig() {
for (FaceBodyConfig item : config.getConfigs()) {
IFaceBodyAdapter adapter = FaceBodyFactory.getAdapter(item.getType());
adapter.loadConfig(item.getConfig());
FaceBodyFactory.register(item.getName(), adapter);
}
}
}

View File

@ -0,0 +1,13 @@
package com.ycwl.basic.facebody.starter.config;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import lombok.Data;
import java.util.Map;
@Data
public class FaceBodyConfig {
private String name;
private FaceBodyAdapterType type;
private Map<String, String> config;
}

View File

@ -0,0 +1,15 @@
package com.ycwl.basic.facebody.starter.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "facebody")
@Data
public class OverallFaceBodyConfig {
private String defaultUse;
private List<FaceBodyConfig> configs;
}

View File

@ -0,0 +1,4 @@
package com.ycwl.basic.image.util;
public class ImageUtil {
}

View File

@ -0,0 +1,26 @@
package com.ycwl.basic.image.watermark;
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkUnsupportedException;
import com.ycwl.basic.image.watermark.operator.IOperator;
import com.ycwl.basic.image.watermark.operator.DefaultImageWatermarkOperator;
import com.ycwl.basic.image.watermark.operator.LeicaWatermarkOperator;
import com.ycwl.basic.image.watermark.operator.NormalWatermarkOperator;
public class ImageWatermarkFactory {
public static IOperator get(String watermarkType) {
ImageWatermarkOperatorEnum type = ImageWatermarkOperatorEnum.getByCode(watermarkType);
if (type == null) {
throw new ImageWatermarkUnsupportedException(watermarkType);
}
return get(type);
}
public static IOperator get(ImageWatermarkOperatorEnum type) {
return switch (type) {
case WATERMARK -> new DefaultImageWatermarkOperator();
case NORMAL -> new NormalWatermarkOperator();
case LEICA -> new LeicaWatermarkOperator();
default -> throw new ImageWatermarkUnsupportedException("不支持的类型" + type.name());
};
}
}

View File

@ -0,0 +1,38 @@
package com.ycwl.basic.image.watermark.entity;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import java.io.File;
import java.util.Date;
@Data
public class WatermarkInfo {
private File originalFile;
/**
* 输出文件
*/
private File watermarkedFile;
private File qrcodeFile;
private String scenicLine;
private String secondLine;
private String thirdLine;
private String fourthLine;
private Date datetime;
private String dtFormat;
private String datetimeLine;
public String getDatetimeLine() {
if (datetimeLine == null) {
datetimeLine = DateUtil.format(datetime, dtFormat);
}
return datetimeLine;
}
public String getScenicLine() {
if (scenicLine == null) {
scenicLine = "";
}
return scenicLine;
}
}

View File

@ -0,0 +1,27 @@
package com.ycwl.basic.image.watermark.enums;
import lombok.Getter;
@Getter
public enum ImageWatermarkOperatorEnum {
WATERMARK("defW", "jpg"),
LEICA("leica", "png"),
NORMAL("normal", "png");
private final String type;
private final String preferFileType;
ImageWatermarkOperatorEnum(String type, String preferFileType) {
this.type = type;
this.preferFileType = preferFileType;
}
public static ImageWatermarkOperatorEnum getByCode(String type) {
for (ImageWatermarkOperatorEnum imageWatermarkOperatorEnum : ImageWatermarkOperatorEnum.values()) {
if (imageWatermarkOperatorEnum.type.equals(type)) {
return imageWatermarkOperatorEnum;
}
}
return null;
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.image.watermark.exception;
public class ImageWatermarkException extends RuntimeException {
public ImageWatermarkException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.ycwl.basic.image.watermark.exception;
public class ImageWatermarkUnsupportedException extends ImageWatermarkException {
public ImageWatermarkUnsupportedException(String message) {
super(message);
}
}

View File

@ -0,0 +1,76 @@
package com.ycwl.basic.image.watermark.operator;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
import lombok.extern.slf4j.Slf4j;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@Slf4j
public class DefaultImageWatermarkOperator implements IOperator {
@Override
public File process(WatermarkInfo info) throws ImageWatermarkException {
BufferedImage baseImage;
BufferedImage watermarkImage;
InputStream logoInputStream = getClass().getResourceAsStream("/watermark.png");
if (logoInputStream == null) {
throw new ImageWatermarkException("无法找到 watermark.png 资源文件");
}
try {
baseImage = ImageIO.read(info.getOriginalFile());
watermarkImage = ImageIO.read(logoInputStream);
} catch (IOException e) {
throw new ImageWatermarkException("图片打开失败");
}
// 新图像画布
BufferedImage newImage = new BufferedImage(baseImage.getWidth(), baseImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newImage.createGraphics();
g2d.drawImage(baseImage, 0, 0, null);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
g2d.drawImage(watermarkImage, 0, 0, baseImage.getWidth(), baseImage.getHeight(), null);
String fileName = info.getWatermarkedFile().getName();
String formatName = "jpg"; // 默认格式为 jpg
if (fileName.endsWith(".png")) {
formatName = "png";
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
formatName = "jpg";
}
ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
ImageOutputStream ios;
try {
ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
}
writer.setOutput(ios);
try {
// 使用 ImageWriter 设置写入质量
ImageWriteParam writeParam = writer.getDefaultWriteParam();
if (writeParam.canWriteCompressed()) {
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionQuality(0.8f); // 设置写入质量为 80%
}
writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败");
}
finally {
g2d.dispose();
try {
ios.close();
} catch (IOException ignore) {
}
writer.dispose();
}
return info.getWatermarkedFile();
}
}

View File

@ -0,0 +1,10 @@
package com.ycwl.basic.image.watermark.operator;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
import java.io.File;
public interface IOperator {
File process(WatermarkInfo info) throws ImageWatermarkException;
}

View File

@ -0,0 +1,152 @@
package com.ycwl.basic.image.watermark.operator;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
import lombok.extern.slf4j.Slf4j;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* 徕卡水印
*/
@Slf4j
public class LeicaWatermarkOperator implements IOperator {
private static final String FONT_PATH = "/PingFang_SC.ttf";
public static String defaultFontName;
public static float FONT_GLOBAL_OFFSET_PERCENT = 0;
static {
try {
// 加载字体文件流
InputStream fontStream = LeicaWatermarkOperator.class.getResourceAsStream(FONT_PATH);
if (fontStream == null) {
throw new RuntimeException("字体文件未找到!路径:" + FONT_PATH);
}
// 创建字体对象
Font customFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
// 注册字体到系统
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(customFont);
// 更新默认字体名称为新字体的逻辑名称
defaultFontName = customFont.getName(); // 如 "PingFang SC"
FONT_GLOBAL_OFFSET_PERCENT = -0.3f;
} catch (FontFormatException | IOException e) {
log.error("加载字体文件失败", e);
defaultFontName = "宋体";
}
}
public static int EXTRA_BOTTOM_PX = 140;
public static int EXTRA_BORDER_PX = 0;
public static Color BG_COLOR = Color.WHITE;
public static int LOGO_SIZE = 50;
public static int LOGO_EXTRA_BORDER = 20;
public static int LOGO_FONT_SIZE = 38;
public static Color logoTextColor = new Color(0x33, 0x33, 0x33);
public static int QRCODE_SIZE = 80;
public static int QRCODE_OFFSET_X = 5;
public static int OFFSET_X = 80;
public static int OFFSET_Y = 30;
public static int SCENIC_FONT_SIZE = 32;
public static Color scenicColor = new Color(0x33, 0x33, 0x33);
public static int DATETIME_FONT_SIZE = 28;
public static Color datetimeColor = new Color(0x99, 0x99, 0x99);
@Override
public File process(WatermarkInfo info) throws ImageWatermarkException {
BufferedImage baseImage;
BufferedImage qrcodeImage;
BufferedImage logoImage;
// 从类路径加载 zt-logo.png
InputStream logoInputStream = getClass().getResourceAsStream("/zt-logo.png");
if (logoInputStream == null) {
throw new ImageWatermarkException("无法找到 zt-logo.png 资源文件");
}
try {
baseImage = ImageIO.read(info.getOriginalFile());
qrcodeImage = ImageIO.read(info.getQrcodeFile());
logoImage = ImageIO.read(logoInputStream);
logoInputStream.close();
} catch (IOException e) {
throw new ImageWatermarkException("图片打开失败");
}
// 新图像画布
BufferedImage newImage = new BufferedImage(baseImage.getWidth() + 2 * EXTRA_BORDER_PX, baseImage.getHeight() + 2 * EXTRA_BORDER_PX + EXTRA_BOTTOM_PX, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newImage.createGraphics();
g2d.setColor(BG_COLOR);
g2d.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(baseImage, EXTRA_BORDER_PX, EXTRA_BORDER_PX, null);
int logoHeight = LOGO_SIZE;
int logoWidth = (int) (logoHeight * 1.0 / logoImage.getHeight() * logoImage.getWidth());
g2d.drawImage(logoImage, EXTRA_BORDER_PX + OFFSET_X, EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + LOGO_EXTRA_BORDER, logoWidth, logoHeight, null);
Font logoTextFont = new Font(defaultFontName, Font.PLAIN, LOGO_FONT_SIZE);
g2d.setFont(logoTextFont);
g2d.setColor(logoTextColor);
FontMetrics logoFontMetrics = g2d.getFontMetrics(logoTextFont);
int logoTextHeight = logoFontMetrics.getHeight();
int logoTextOffsetY = (LOGO_SIZE - logoHeight) / 2;
g2d.drawString("帧途", EXTRA_BORDER_PX + OFFSET_X + logoWidth + 5, EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + logoTextHeight + LOGO_EXTRA_BORDER + logoTextOffsetY + logoTextHeight * FONT_GLOBAL_OFFSET_PERCENT);
int newQrcodeHeight = QRCODE_SIZE;
int newQrcodeWidth = (int) (newQrcodeHeight * 1.0 / qrcodeImage.getHeight() * qrcodeImage.getWidth());
Font scenicFont = new Font(defaultFontName, Font.PLAIN, SCENIC_FONT_SIZE);
Font datetimeFont = new Font(defaultFontName, Font.PLAIN, DATETIME_FONT_SIZE);
FontMetrics scenicFontMetrics = g2d.getFontMetrics(scenicFont);
FontMetrics datetimeFontMetrics = g2d.getFontMetrics(datetimeFont);
int scenicLineHeight = scenicFontMetrics.getHeight();
int dtLineHeight = datetimeFontMetrics.getHeight();
int scenicLineWidth = scenicFontMetrics.stringWidth(info.getScenicLine());
int datetimeLineWidth = scenicFontMetrics.stringWidth(info.getDatetimeLine());
g2d.drawImage(qrcodeImage, newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - newQrcodeWidth - QRCODE_OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y, newQrcodeWidth, newQrcodeHeight, null);
g2d.setFont(scenicFont);
g2d.setColor(scenicColor);
g2d.drawString(info.getScenicLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + scenicLineHeight + scenicLineHeight * FONT_GLOBAL_OFFSET_PERCENT);
g2d.setFont(datetimeFont);
g2d.setColor(datetimeColor);
g2d.drawString(info.getDatetimeLine(), newImage.getWidth() + EXTRA_BORDER_PX - OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth), EXTRA_BORDER_PX + baseImage.getHeight() + OFFSET_Y + scenicLineHeight + dtLineHeight + dtLineHeight * FONT_GLOBAL_OFFSET_PERCENT);
String fileName = info.getWatermarkedFile().getName();
String formatName = "jpg"; // 默认格式为 jpg
if (fileName.endsWith(".png")) {
formatName = "png";
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
formatName = "jpg";
}
ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
ImageOutputStream ios;
try {
ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
}
writer.setOutput(ios);
try {
// 使用 ImageWriter 设置写入质量
ImageWriteParam writeParam = writer.getDefaultWriteParam();
if (writeParam.canWriteCompressed()) {
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
}
writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败");
}
finally {
g2d.dispose();
try {
ios.close();
} catch (IOException ignore) {
}
writer.dispose();
}
return info.getWatermarkedFile();
}
}

View File

@ -0,0 +1,128 @@
package com.ycwl.basic.image.watermark.operator;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
import lombok.extern.slf4j.Slf4j;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@Slf4j
public class NormalWatermarkOperator implements IOperator {
private static final String FONT_PATH = "/PingFang_SC.ttf";
public static String defaultFontName;
public static float FONT_GLOBAL_OFFSET_PERCENT = 0;
static {
try {
// 加载字体文件流
InputStream fontStream = LeicaWatermarkOperator.class.getResourceAsStream(FONT_PATH);
if (fontStream == null) {
throw new RuntimeException("字体文件未找到!路径:" + FONT_PATH);
}
// 创建字体对象
Font customFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);
// 注册字体到系统
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(customFont);
// 更新默认字体名称为新字体的逻辑名称
defaultFontName = customFont.getName(); // 如 "PingFang SC"
FONT_GLOBAL_OFFSET_PERCENT = -0.3f;
} catch (FontFormatException | IOException e) {
log.error("加载字体文件失败", e);
defaultFontName = "宋体";
}
}
public static int EXTRA_BORDER_PX = 0;
public static int OFFSET_Y = 90;
public static Color BG_COLOR = Color.WHITE;
public static int QRCODE_SIZE = 100;
public static int QRCODE_OFFSET_X = 10;
public static int SCENIC_FONT_SIZE = 42;
public static Color scenicColor = Color.white;
public static int DATETIME_FONT_SIZE = 42;
public static Color datetimeColor = Color.white;
@Override
public File process(WatermarkInfo info) throws ImageWatermarkException {
BufferedImage baseImage;
BufferedImage qrcodeImage;
try {
baseImage = ImageIO.read(info.getOriginalFile());
qrcodeImage = ImageIO.read(info.getQrcodeFile());
} catch (IOException e) {
throw new ImageWatermarkException("图片打开失败");
}
// 新图像画布
BufferedImage newImage = new BufferedImage(baseImage.getWidth() + 2 * EXTRA_BORDER_PX, baseImage.getHeight() + 2 * EXTRA_BORDER_PX, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newImage.createGraphics();
g2d.setColor(BG_COLOR);
g2d.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(baseImage, EXTRA_BORDER_PX, EXTRA_BORDER_PX, null);
int newQrcodeHeight = QRCODE_SIZE;
int newQrcodeWidth = (int) (newQrcodeHeight * 1.0 / qrcodeImage.getHeight() * qrcodeImage.getWidth());
Font scenicFont = new Font(defaultFontName, Font.PLAIN, SCENIC_FONT_SIZE);
Font datetimeFont = new Font(defaultFontName, Font.PLAIN, DATETIME_FONT_SIZE);
FontMetrics scenicFontMetrics = g2d.getFontMetrics(scenicFont);
FontMetrics datetimeFontMetrics = g2d.getFontMetrics(datetimeFont);
int scenicLineHeight = scenicFontMetrics.getHeight();
int dtLineHeight = datetimeFontMetrics.getHeight();
int scenicLineWidth = scenicFontMetrics.stringWidth(info.getScenicLine());
int datetimeLineWidth = scenicFontMetrics.stringWidth(info.getDatetimeLine());
int offsetX = (newImage.getWidth() - newQrcodeWidth - QRCODE_OFFSET_X - Math.max(scenicLineWidth, datetimeLineWidth)) / 2;
int offsetY = EXTRA_BORDER_PX + baseImage.getHeight() - OFFSET_Y - newQrcodeHeight;
g2d.drawImage(qrcodeImage, offsetX, offsetY, newQrcodeWidth, newQrcodeHeight, null);
g2d.setFont(scenicFont);
g2d.setColor(scenicColor);
g2d.drawString(info.getScenicLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, offsetY + scenicLineHeight + FONT_GLOBAL_OFFSET_PERCENT * scenicLineHeight);
g2d.setFont(datetimeFont);
g2d.setColor(datetimeColor);
g2d.drawString(info.getDatetimeLine(), offsetX + newQrcodeWidth + QRCODE_OFFSET_X, offsetY + scenicLineHeight + dtLineHeight + FONT_GLOBAL_OFFSET_PERCENT * dtLineHeight);
String fileName = info.getWatermarkedFile().getName();
String formatName = "jpg"; // 默认格式为 jpg
if (fileName.endsWith(".png")) {
formatName = "png";
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
formatName = "jpg";
}
ImageWriter writer = ImageIO.getImageWritersByFormatName(formatName).next();
ImageOutputStream ios;
try {
ios = ImageIO.createImageOutputStream(info.getWatermarkedFile());
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败,目标文件无法写入");
}
writer.setOutput(ios);
try {
// 使用 ImageWriter 设置写入质量
ImageWriteParam writeParam = writer.getDefaultWriteParam();
if (writeParam.canWriteCompressed()) {
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionQuality(0.95f); // 设置写入质量为 95%
}
writer.write(null, new javax.imageio.IIOImage(newImage, null, null), writeParam);
} catch (IOException e) {
throw new ImageWatermarkException("图片保存失败");
}
finally {
g2d.dispose();
try {
ios.close();
} catch (IOException ignore) {
}
writer.dispose();
}
return info.getWatermarkedFile();
}
}

View File

@ -8,7 +8,6 @@ import com.ycwl.basic.constant.RequestConstant;
import com.ycwl.basic.exception.CheckTokenException;
import com.ycwl.basic.exception.MissTokenException;
import com.ycwl.basic.exception.PermissionException;
import com.ycwl.basic.exception.TokenExpireException;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
@ -17,42 +16,36 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
@Slf4j
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Autowired
JwtTokenUtil jwtTokenUtil;
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return super.preHandle(request, response, handler);
if (!(handler instanceof HandlerMethod handlerMethod)) {
return true;
}
String requestURI = request.getRequestURI();
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取类上面的注解
IgnoreToken ignoreClassToken = handlerMethod.getBeanType().getAnnotation(IgnoreToken.class);
// 获取方法上的注解
IgnoreToken ignoreMethodToken = handlerMethod.getMethodAnnotation(IgnoreToken.class);
if (ignoreClassToken != null || ignoreMethodToken != null) {
// 放行
return super.preHandle(request, response, handler);
return true;
}
// 放行白名单
@ -120,7 +113,6 @@ public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
BaseContextHandler.remove();
super.afterCompletion(request, response, handler, ex);
}
public String getToken(HttpServletRequest request) {

View File

@ -0,0 +1,17 @@
package com.ycwl.basic.mapper;
import com.ycwl.basic.model.pc.coupon.entity.CouponEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycwl.basic.model.pc.coupon.req.CouponQueryReq;
import com.ycwl.basic.model.pc.coupon.resp.CouponRespVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CouponMapper extends BaseMapper<CouponEntity> {
List<CouponRespVO> selectByQuery(CouponQueryReq query);
int updateStatus(Integer id);
CouponEntity getById(Integer couponId);
}

View File

@ -0,0 +1,12 @@
package com.ycwl.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycwl.basic.model.pc.couponRecord.entity.CouponRecordEntity;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CouponRecordMapper extends BaseMapper<CouponRecordEntity> {
List<CouponRecordEntity> queryByUserWithGoodsId(Long scenicId, Long memberId, String goodsId);
}

View File

@ -30,7 +30,7 @@ public interface DeviceMapper {
DeviceEntity getByDeviceId(Long deviceId);
List<DeviceRespVO> listByScenicIdWithWVP(Long scenicId);
ScenicDeviceCountVO deviceCountByScenicId(@Param("scenicId") Long scenicId,@Param("userId") Long userId);
ScenicDeviceCountVO deviceCountByScenicId(@Param("scenicId") Long scenicId);
DeviceConfigEntity getConfigByDeviceId(Long deviceId);
int addConfig(DeviceConfigEntity deviceConfigEntity);

View File

@ -6,6 +6,7 @@ import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
@ -16,11 +17,13 @@ import java.util.List;
@Mapper
public interface FaceMapper {
List<FaceRespVO> list(FaceReqQuery faceReqQuery);
List<FaceRespVO> test();
List<FaceRespVO> listByScenicIdAndNotFinished(Long scenicId);
FaceRespVO getById(Long id);
FaceEntity get(Long id);
int add(FaceEntity face);
int deleteById(Long id);
int forceDeleteById(Long id);
int deleteByIds(@Param("list") List<Long> ids);
int update(FaceEntity face);
@ -32,4 +35,6 @@ public interface FaceMapper {
FaceRespVO findLastFaceByScenicAndUserId(Long scenicId, Long userId);
List<FaceRespVO> listByScenicAndUserId(String scenicId, Long userId);
List<FaceEntity> listUnpaidEntityBeforeDate(Long scenicId, Date endDate);
}

View File

@ -3,7 +3,6 @@ package com.ycwl.basic.mapper;
import com.ycwl.basic.model.pc.member.entity.MemberEntity;
import com.ycwl.basic.model.pc.member.req.MemberReqQuery;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.utils.ApiResponse;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

View File

@ -49,5 +49,10 @@ public interface OrderMapper {
OrderItemEntity getOrderItem(Long orderItemId);
int updateOrderPrice(OrderEntity updateEntity);
int updateOrder(OrderEntity updateEntity);
OrderEntity queryTypeOrder(Long userId, Long scenicId, int orderType, Integer priceConfigId);
OrderEntity getUserOrderItem(Long userId, Long scenicId, int orderType, Long configId, Integer goodsType, Long goodsId);
}

View File

@ -0,0 +1,15 @@
package com.ycwl.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycwl.basic.model.pc.permission.entity.PermissionEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface PermissionMapper extends BaseMapper<PermissionEntity> {
// 新增用户ID查询方法
PermissionEntity selectByUserId(@Param("userId") Long userId);
void insertPermission(PermissionEntity entity);
void updatePermission(PermissionEntity entity);
}

View File

@ -17,4 +17,6 @@ public interface PriceConfigMapper extends BaseMapper<PriceConfigEntity> {
List<PriceConfigRespVO> listByCondition(@Param("req") PriceConfigListReq req);
PriceConfigEntity getPriceByScenicTypeGoods(Long scenicId, Integer type, String goodsId);
int updateStatus(Integer id);
}

View File

@ -0,0 +1,10 @@
package com.ycwl.basic.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ycwl.basic.model.pc.printer.entity.PrintTaskEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PrintTaskMapper extends BaseMapper<PrintTaskEntity> {
int insertTask(PrintTaskEntity entity);
}

Some files were not shown because too many files have changed in this diff Show More