Compare commits
24 Commits
79ea08898b
...
da20a44049
Author | SHA1 | Date | |
---|---|---|---|
da20a44049 | |||
877f37b6f9 | |||
f6f847e41c | |||
8ac386242d | |||
3f11aadd75 | |||
d620bde5fa | |||
5a7c39429e | |||
7234e08616 | |||
45409ba1ab | |||
b5b9064f30 | |||
d0d4e37526 | |||
73d393b436 | |||
2835346447 | |||
75eb3732fc | |||
692df3a1a2 | |||
fe0397af8e | |||
f17e2364b6 | |||
59978b6be5 | |||
20d78cb487 | |||
4e9d6807d6 | |||
8af8bd6bcf | |||
248c06a30c | |||
dabdde33a6 | |||
c9a4116ed6 |
@ -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 {
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package com.ycwl.basic.aspectj;
|
||||
|
||||
import com.ycwl.basic.annotation.RequestToFile;
|
||||
import com.ycwl.basic.config.CachedBodyHttpServletRequest;
|
||||
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.BufferedReader;
|
||||
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 {
|
||||
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.append(request.getMethod()).append(" ").append(request.getRequestURL());
|
||||
String queryString = request.getQueryString();
|
||||
if (queryString != null) {
|
||||
writer.append("?").append(queryString);
|
||||
}
|
||||
writer.append("\r\n");
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement();
|
||||
writer.append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
|
||||
}
|
||||
writer.append("\r\n");
|
||||
// 获取body
|
||||
CachedBodyHttpServletRequest cachedRequest = (CachedBodyHttpServletRequest) request;
|
||||
writer.append(new String(cachedRequest.getCachedBody()));
|
||||
writer.append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package com.ycwl.basic.config;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.*;
|
||||
|
||||
public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
|
||||
private final byte[] cachedBody;
|
||||
|
||||
public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
|
||||
super(request);
|
||||
// 缓存请求体内容
|
||||
InputStream requestInputStream = request.getInputStream();
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = requestInputStream.read(buffer)) != -1) {
|
||||
byteArrayOutputStream.write(buffer, 0, read);
|
||||
}
|
||||
cachedBody = byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() {
|
||||
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cachedBody);
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
return byteArrayInputStream.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
// 不需要实现
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() {
|
||||
return new BufferedReader(new InputStreamReader(this.getInputStream()));
|
||||
}
|
||||
|
||||
public byte[] getCachedBody() {
|
||||
return cachedBody;
|
||||
}
|
||||
}
|
@ -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/**");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
||||
}
|
@ -6,7 +6,6 @@ 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;
|
||||
@ -14,12 +13,7 @@ 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.repository.PriceRepository;
|
||||
import com.ycwl.basic.service.mobile.GoodsService;
|
||||
import com.ycwl.basic.service.pc.OrderService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.JwtTokenUtil;
|
||||
@ -28,6 +22,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
|
||||
@ -62,7 +58,7 @@ 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);
|
||||
}
|
||||
@ -70,7 +66,7 @@ public class AppOrderController {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
|
||||
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;
|
||||
@ -51,9 +52,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("查询景区设备总数和拍到用户的机位数量")
|
||||
|
@ -2,8 +2,6 @@ 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;
|
||||
@ -12,6 +10,7 @@ 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.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -35,12 +34,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
|
||||
@ -48,29 +41,19 @@ public class AppWxPayController {
|
||||
wxPayService.payNotify(request);
|
||||
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);
|
||||
@PostMapping("/{scenicId}/payNotify")
|
||||
@IgnoreToken
|
||||
public ApiResponse<?> payNotifyByScenicId(@PathVariable Long scenicId, HttpServletRequest request) {
|
||||
wxPayService.payNotify(scenicId, request);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ 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;
|
||||
@ -131,7 +130,7 @@ public class BrokerController {
|
||||
try {
|
||||
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
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;
|
||||
@ -35,6 +37,8 @@ public class ScenicController {
|
||||
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
@Autowired
|
||||
private AppStatisticsService appStatisticsService;
|
||||
|
||||
@ApiOperation("分页查询景区")
|
||||
@PostMapping("/page")
|
||||
@ -117,7 +121,7 @@ public class ScenicController {
|
||||
try {
|
||||
WxMpUtil.generateWXAQRCode(appId, appSecret, appState, path, filePath);
|
||||
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);
|
||||
@ -125,4 +129,25 @@ public class ScenicController {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
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 javax.servlet.http.HttpServletRequest;
|
||||
import javax.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;
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,8 +17,6 @@ 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 = "渲染端对接接口")
|
||||
|
@ -1,14 +1,11 @@
|
||||
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.aspectj.HttpSaver;
|
||||
import com.ycwl.basic.facebody.FaceBodyFactory;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
import com.ycwl.basic.facebody.entity.AddFaceResp;
|
||||
import com.ycwl.basic.mapper.DeviceMapper;
|
||||
@ -17,14 +14,11 @@ 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;
|
||||
import com.ycwl.basic.model.viid.entity.FaceObject;
|
||||
import com.ycwl.basic.model.viid.entity.FacePositionObject;
|
||||
import com.ycwl.basic.model.viid.entity.ImageListObject;
|
||||
import com.ycwl.basic.model.viid.entity.ImageObject;
|
||||
import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
|
||||
import com.ycwl.basic.model.viid.entity.SubImageInfoObject;
|
||||
import com.ycwl.basic.model.viid.entity.SubImageList;
|
||||
@ -69,12 +63,12 @@ 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.service.task.impl.TaskFaceServiceImpl.generateEntityId;
|
||||
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
@ -93,17 +87,20 @@ public class ViidController {
|
||||
private ScenicRepository scenicRepository;
|
||||
@Autowired
|
||||
private TaskFaceService taskFaceService;
|
||||
private final Map<String, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
|
||||
private final Map<Long, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
private ThreadPoolExecutor getExecutor(String deviceId) {
|
||||
ThreadPoolExecutor executor = executors.get(deviceId);
|
||||
if (executor == null) {
|
||||
executor = new ThreadPoolExecutor(4, 4096, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(4096));
|
||||
executors.put(deviceId, executor);
|
||||
}
|
||||
return executor;
|
||||
private ThreadPoolExecutor getExecutor(Long scenicId) {
|
||||
return executors.computeIfAbsent(scenicId, k -> {
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNamePrefix("VIID-" + scenicId + "-t")
|
||||
.build();
|
||||
return new ThreadPoolExecutor(
|
||||
4, 4096, 0L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(4096),
|
||||
threadFactory);
|
||||
});
|
||||
}
|
||||
|
||||
// region 注册注销基础接口
|
||||
@ -310,11 +307,11 @@ public class ViidController {
|
||||
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
ThreadPoolExecutor executor = getExecutor(device.getId().toString());
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
if (faceBodyAdapter != null) {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), generateEntityId(faceSample), url, newFaceSampleId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.update(faceSample);
|
||||
@ -372,11 +369,11 @@ public class ViidController {
|
||||
faceSample.setFaceUrl(url);
|
||||
faceSampleMapper.add(faceSample);
|
||||
DynamicTaskGenerator.addTask(faceSample.getId());
|
||||
ThreadPoolExecutor executor = getExecutor(device.getId().toString());
|
||||
ThreadPoolExecutor executor = getExecutor(scenicId);
|
||||
executor.execute(() -> {
|
||||
if (faceBodyAdapter != null) {
|
||||
taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), generateEntityId(faceSample), url, newFaceSampleId.toString());
|
||||
AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
|
||||
if (addFaceResp != null) {
|
||||
faceSample.setScore(addFaceResp.getScore());
|
||||
faceSampleMapper.update(faceSample);
|
||||
@ -402,8 +399,6 @@ public class ViidController {
|
||||
@RequestMapping(value = "/Images", method = RequestMethod.POST)
|
||||
@IgnoreLogReq
|
||||
public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
|
||||
// log.info("Images:{}", req);
|
||||
HttpSaver.saveRequestToFile(request);
|
||||
return new VIIDBaseResp(
|
||||
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
|
||||
);
|
||||
|
@ -1,25 +1,18 @@
|
||||
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.facebody.adapter.IFaceBodyAdapter;
|
||||
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.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.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;
|
||||
@ -29,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@IgnoreToken
|
||||
@ -48,7 +40,7 @@ public class VptController {
|
||||
}
|
||||
@PostMapping("/scenic/{scenicId}/{taskId}/uploadUrl")
|
||||
public String uploadUrl(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId) {
|
||||
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(scenicId);
|
||||
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");
|
||||
@ -56,7 +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 = scenicService.getScenicStorageAdapter(scenicId);
|
||||
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);
|
||||
|
@ -1,24 +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.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.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;
|
||||
@ -28,7 +23,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@IgnoreToken
|
||||
@ -51,7 +45,7 @@ public class WvpController {
|
||||
|
||||
@PostMapping("/scenic/{scenicId}/{taskId}/uploadUrl")
|
||||
public String uploadUrl(@PathVariable("scenicId") Long scenicId, @PathVariable("taskId") Long taskId) {
|
||||
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(scenicId);
|
||||
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");
|
||||
@ -59,7 +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 = scenicService.getScenicStorageAdapter(scenicId);
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
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 org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
|
||||
import org.slf4j.Logger;
|
||||
@ -12,14 +9,9 @@ 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 java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @date 2022年09月23日 10:19
|
||||
|
@ -249,7 +249,7 @@ public class AliFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
return response.getData().getEntities().stream().map(ListFaceEntitiesResponse.Data.Entity::getEntityId).collect(Collectors.toList());
|
||||
} catch (ClientException e) {
|
||||
log.error("获取人脸数据失败!", e);
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,9 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
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 {
|
||||
@ -232,9 +235,14 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
}
|
||||
|
||||
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");
|
||||
@ -249,13 +257,16 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else if (response.getInt("error_code") == 223103) {
|
||||
// 用户不存在
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
log.warn("获取人脸列表失败!{}", response);
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取人脸列表失败!", e);
|
||||
return Collections.emptyList();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,21 +336,21 @@ public class BceFaceBodyAdapter implements IFaceBodyAdapter {
|
||||
private IRateLimiter getLimiter(LOCK_TYPE type) {
|
||||
switch (type) {
|
||||
case ADD_DB:
|
||||
return addDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return addDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
case ADD_FACE:
|
||||
return addFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(config.getAddQps()));
|
||||
case LIST_DB:
|
||||
return listDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return listDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
case LIST_FACE:
|
||||
return listFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return listFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
case SEARCH_FACE:
|
||||
return searchFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(config.getSearchQps()));
|
||||
case DELETE_DB:
|
||||
return deleteDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return deleteDbLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
case DELETE_ENTITY:
|
||||
return deleteEntityLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return deleteEntityLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
case DELETE_FACE:
|
||||
return deleteFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(100, TimeUnit.MILLISECONDS));
|
||||
return deleteFaceLimiters.computeIfAbsent(config.getAppId(), k -> new FixedRateLimiter(105, TimeUnit.MILLISECONDS));
|
||||
default:
|
||||
return new FixedRateLimiter(500, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
package com.ycwl.basic.filter;
|
||||
|
||||
import com.ycwl.basic.config.CachedBodyHttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class RequestCacheFilter implements Filter {
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
// 包装原始请求
|
||||
HttpServletRequestWrapper wrappedRequest = new CachedBodyHttpServletRequest((HttpServletRequest) request);
|
||||
// 继续处理请求链
|
||||
chain.doFilter(wrappedRequest, response);
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@ import com.ycwl.basic.constant.PermissionConstant;
|
||||
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;
|
||||
@ -24,17 +22,12 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.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;
|
||||
|
||||
@Autowired
|
||||
RedisTemplate redisTemplate;
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -54,5 +54,5 @@ public interface TaskMapper {
|
||||
|
||||
List<TaskEntity> listEntity(TaskReqQuery taskReqQuery);
|
||||
|
||||
List<TaskRespVO> selectNotRunningByScenicId(Long scenicOnly);
|
||||
List<TaskRespVO> selectNotRunningByScenicList(String scenicOnly);
|
||||
}
|
||||
|
@ -19,6 +19,12 @@ public class IsBuyBatchRespVO {
|
||||
private BigDecimal slashPrice;
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
if (origPrice == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (couponPrice == null) {
|
||||
return origPrice;
|
||||
}
|
||||
return origPrice.subtract(couponPrice);
|
||||
}
|
||||
public BigDecimal getDiscountPrice() {
|
||||
|
@ -18,6 +18,12 @@ public class IsBuyRespVO {
|
||||
private BigDecimal slashPrice;
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
if (origPrice == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (couponPrice == null) {
|
||||
return origPrice;
|
||||
}
|
||||
return origPrice.subtract(couponPrice);
|
||||
}
|
||||
public BigDecimal getDiscountPrice() {
|
||||
|
@ -33,6 +33,7 @@ public class PriceConfigEntity {
|
||||
* 划线价格
|
||||
*/
|
||||
private BigDecimal slashPrice;
|
||||
private Integer status;
|
||||
private Date createTime;
|
||||
private Date updateTime;
|
||||
}
|
@ -30,5 +30,6 @@ public class PriceConfigRespVO {
|
||||
* 划线价格
|
||||
*/
|
||||
private BigDecimal slashPrice;
|
||||
private Integer status;
|
||||
private Date createTime;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class RenderWorkerEntity {
|
||||
/**
|
||||
* 是否仅用于指定景区,空或0不适用,否则为景区ID
|
||||
*/
|
||||
private Long scenicOnly;
|
||||
private String scenicOnly;
|
||||
/**
|
||||
* 是否仅用于测试,0不是,1是
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
|
||||
import com.ycwl.basic.pay.enums.PayAdapterType;
|
||||
import com.ycwl.basic.storage.enums.StorageType;
|
||||
import lombok.Data;
|
||||
|
||||
@ -71,6 +72,10 @@ public class ScenicConfigEntity {
|
||||
private Float faceScoreThreshold;
|
||||
private StorageType storeType;
|
||||
private String storeConfigJson;
|
||||
private StorageType tmpStoreType;
|
||||
private String tmpStoreConfigJson;
|
||||
private StorageType localStoreType;
|
||||
private String localStoreConfigJson;
|
||||
private BigDecimal brokerDirectRate;
|
||||
private Integer faceDetectHelperThreshold;
|
||||
|
||||
@ -80,4 +85,10 @@ public class ScenicConfigEntity {
|
||||
|
||||
private FaceBodyAdapterType faceType;
|
||||
private String faceConfigJson;
|
||||
|
||||
private PayAdapterType payType;
|
||||
private String payConfigJson;
|
||||
|
||||
private String imageSourcePackHint;
|
||||
private String videoSourcePackHint;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
package com.ycwl.basic.model.pc.scenic.resp;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
|
||||
import com.ycwl.basic.pay.enums.PayAdapterType;
|
||||
import com.ycwl.basic.storage.enums.StorageType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
* @Date:2024/12/2 10:53
|
||||
* 景区配置
|
||||
*/
|
||||
@Data
|
||||
public class ScenicConfigResp {
|
||||
|
||||
/**
|
||||
* 预约流程,1-预约,2-在线,3-全部
|
||||
*/
|
||||
private Integer bookRoutine;
|
||||
private Integer forceFinishTime;
|
||||
private Integer tourTime;
|
||||
/**
|
||||
* 样本保存时间
|
||||
*/
|
||||
private Integer sampleStoreDay;
|
||||
private Integer faceStoreDay;
|
||||
/**
|
||||
* 视频保存时间
|
||||
*/
|
||||
private Integer videoStoreDay;
|
||||
private Integer allFree;
|
||||
private Integer disableSourceVideo;
|
||||
private Integer disableSourceImage;
|
||||
private Integer antiScreenRecordType;
|
||||
private Integer videoSourceStoreDay;
|
||||
private Integer imageSourceStoreDay;
|
||||
private Integer userSourceExpireDay;
|
||||
private BigDecimal brokerDirectRate;
|
||||
|
||||
private String imageSourcePackHint;
|
||||
private String videoSourcePackHint;
|
||||
}
|
58
src/main/java/com/ycwl/basic/pay/PayFactory.java
Normal file
58
src/main/java/com/ycwl/basic/pay/PayFactory.java
Normal file
@ -0,0 +1,58 @@
|
||||
package com.ycwl.basic.pay;
|
||||
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.adapter.WxMpPayAdapter;
|
||||
import com.ycwl.basic.pay.enums.PayAdapterType;
|
||||
import com.ycwl.basic.pay.exceptions.PayUndefinedException;
|
||||
import com.ycwl.basic.pay.exceptions.PayUnsupportedException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PayFactory {
|
||||
|
||||
public static IPayAdapter getAdapter(String typeName) {
|
||||
PayAdapterType adapterEnum;
|
||||
try {
|
||||
adapterEnum = PayAdapterType.valueOf(typeName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new PayUnsupportedException("不支持的Adapter类型");
|
||||
}
|
||||
return getAdapter(adapterEnum);
|
||||
}
|
||||
|
||||
public static IPayAdapter getAdapter(PayAdapterType type) {
|
||||
switch (type) {
|
||||
case WX_MP_PAY:
|
||||
return new WxMpPayAdapter();
|
||||
default:
|
||||
throw new PayUnsupportedException("不支持的Adapter类型");
|
||||
}
|
||||
}
|
||||
|
||||
protected static Map<String, IPayAdapter> namedAdapter = new HashMap<>();
|
||||
protected static IPayAdapter defaultAdapter = null;
|
||||
|
||||
public static void register(String name, IPayAdapter adapter) {
|
||||
namedAdapter.put(name, adapter);
|
||||
}
|
||||
|
||||
public static IPayAdapter use(String name) {
|
||||
IPayAdapter adapter = namedAdapter.get(name);
|
||||
if (adapter == null) {
|
||||
throw new PayUndefinedException("未定义的支付方式:"+name);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public static IPayAdapter use() {
|
||||
if (defaultAdapter == null) {
|
||||
throw new PayUndefinedException("未定义默认的支付方式");
|
||||
}
|
||||
return defaultAdapter;
|
||||
}
|
||||
|
||||
public static void setDefault(String defaultName) {
|
||||
PayFactory.defaultAdapter = use(defaultName);
|
||||
}
|
||||
}
|
42
src/main/java/com/ycwl/basic/pay/adapter/IPayAdapter.java
Normal file
42
src/main/java/com/ycwl/basic/pay/adapter/IPayAdapter.java
Normal file
@ -0,0 +1,42 @@
|
||||
package com.ycwl.basic.pay.adapter;
|
||||
|
||||
// 假设request对象所在的包,可根据实际情况修改
|
||||
import com.ycwl.basic.pay.entity.CancelOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderResponse;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderResponse;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
// 将接口改为抽象类
|
||||
public interface IPayAdapter {
|
||||
// 下单方法
|
||||
CreateOrderResponse createOrder(CreateOrderRequest request);
|
||||
|
||||
// 获取支付参数方法
|
||||
Map<String, Object> getPaymentParams(CreateOrderResponse response);
|
||||
|
||||
// 处理回调信息方法
|
||||
PayResponse handleCallback(HttpServletRequest request) throws IOException;
|
||||
|
||||
// 查询订单状态方法
|
||||
PayResponse queryOrder(String orderNo);
|
||||
|
||||
// 退款方法
|
||||
RefundOrderResponse refund(RefundOrderRequest request);
|
||||
|
||||
// 处理退款回调方法
|
||||
RefundResponse handleRefundCallback(HttpServletRequest request) throws IOException;
|
||||
|
||||
// 查询退款订单状态方法
|
||||
RefundResponse checkRefundStatus(String refundNo);
|
||||
|
||||
void loadConfig(Map<String, String> config);
|
||||
|
||||
void cancelOrder(CancelOrderRequest request);
|
||||
}
|
353
src/main/java/com/ycwl/basic/pay/adapter/WxMpPayAdapter.java
Normal file
353
src/main/java/com/ycwl/basic/pay/adapter/WxMpPayAdapter.java
Normal file
@ -0,0 +1,353 @@
|
||||
package com.ycwl.basic.pay.adapter;
|
||||
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.core.util.PemUtil;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
|
||||
import com.wechat.pay.java.service.payments.model.Transaction;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
|
||||
import com.wechat.pay.java.service.refund.model.Refund;
|
||||
import com.wechat.pay.java.service.refund.model.RefundNotification;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.pay.entity.CancelOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderResponse;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderResponse;
|
||||
import com.ycwl.basic.pay.entity.WxMpPayConfig;
|
||||
import com.ycwl.basic.pay.exceptions.PayWrongConfigException;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_NONCE;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SERIAL;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_SIGNATURE;
|
||||
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_TIMESTAMP;
|
||||
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
|
||||
|
||||
public class WxMpPayAdapter implements IPayAdapter {
|
||||
private WxMpPayConfig config;
|
||||
public static final String WECHAT_PAY_SIGNATURE_TYPE = "Wechatpay-Signature-Type";
|
||||
public WxMpPayAdapter() {
|
||||
|
||||
}
|
||||
public WxMpPayAdapter(WxMpPayConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
@Override
|
||||
public void loadConfig(Map<String, String> _config) {
|
||||
this.config = new WxMpPayConfig();
|
||||
if (_config != null) {
|
||||
this.config.setMerchantId(_config.get("merchantId"));
|
||||
this.config.setAppId(_config.get("appId"));
|
||||
this.config.setPrivateKey(_config.get("privateKey"));
|
||||
this.config.setSerialNumber(_config.get("serialNumber"));
|
||||
this.config.setApiV3Key(_config.get("apiV3Key"));
|
||||
}
|
||||
}
|
||||
|
||||
private Config clientConfig;
|
||||
|
||||
private Config getConfig() {
|
||||
if (clientConfig == null) {
|
||||
clientConfig = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(config.getMerchantId())
|
||||
.privateKey(config.getPrivateKey())
|
||||
.merchantSerialNumber(config.getSerialNumber())
|
||||
.apiV3Key(config.getApiV3Key())
|
||||
.build();
|
||||
}
|
||||
return clientConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateOrderResponse createOrder(CreateOrderRequest request) {
|
||||
CreateOrderResponse resp = new CreateOrderResponse();
|
||||
if (request.getPrice() <= 0) {
|
||||
resp.setSkipPay(true);
|
||||
return resp;
|
||||
}
|
||||
Config wxConfig = getConfig();
|
||||
JsapiService service = new JsapiService.Builder().config(wxConfig).build();
|
||||
PrepayRequest prepayRequest = new PrepayRequest();
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(request.getPrice());
|
||||
prepayRequest.setAmount(amount);
|
||||
prepayRequest.setAppid(config.getAppId());
|
||||
prepayRequest.setMchid(config.getMerchantId());
|
||||
prepayRequest.setDescription(request.getDescription());
|
||||
prepayRequest.setNotifyUrl(request.getNotifyUrl());
|
||||
prepayRequest.setOutTradeNo(request.getOrderNo());
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(request.getUserIdentify());
|
||||
prepayRequest.setPayer(payer);
|
||||
PrepayResponse response = service.prepay(prepayRequest);
|
||||
resp.setSuccess(true);
|
||||
resp.setSkipPay(false);
|
||||
resp.setOrderNo(response.getPrepayId());
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPaymentParams(CreateOrderResponse response) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (response.isSkipPay()) {
|
||||
return params;
|
||||
}
|
||||
Long timeStamp = System.currentTimeMillis() / NumberConstant.THOUSAND;
|
||||
params.put("appId", config.getAppId());
|
||||
params.put("timeStamp", timeStamp);
|
||||
String nonce = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
|
||||
params.put("nonceStr", nonce);
|
||||
String signStr = Stream.of(config.getAppId(), String.valueOf(timeStamp), nonce, "prepay_id=" + response.getOrderNo())
|
||||
.collect(Collectors.joining("\n", "", "\n"));
|
||||
String sign;
|
||||
try {
|
||||
sign = getSign(signStr, config.getPrivateKey());
|
||||
} catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException e) {
|
||||
throw new PayWrongConfigException("配置错误");
|
||||
}
|
||||
params.put("paySign", sign);
|
||||
params.put("signType", "RSA-SHA256");
|
||||
params.put("prepayId", "prepay_id=" + response.getOrderNo());
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayResponse handleCallback(HttpServletRequest request) throws IOException {
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
StringBuffer body = new StringBuffer();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s;
|
||||
// 读取回调请求体
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
body.append(s);
|
||||
}
|
||||
PayResponse resp = new PayResponse();
|
||||
|
||||
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||
String signType = request.getHeader(WECHAT_PAY_SIGNATURE_TYPE);
|
||||
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
|
||||
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||
NotificationConfig config = (NotificationConfig) getConfig();
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(serialNo)
|
||||
.nonce(nonce)
|
||||
.signature(signature)
|
||||
.timestamp(timestamp)
|
||||
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(signType)
|
||||
.body(body.toString())
|
||||
.build();
|
||||
Transaction parse = parser.parse(requestParam, Transaction.class);
|
||||
resp.setValid(true);
|
||||
resp.setOrderNo(parse.getOutTradeNo());
|
||||
if (parse.getAmount() != null) {
|
||||
resp.setOrderPrice(parse.getAmount().getTotal());
|
||||
resp.setPayPrice(parse.getAmount().getPayerTotal());
|
||||
}
|
||||
switch (parse.getTradeState()) {
|
||||
case SUCCESS:
|
||||
resp.setState(PayResponse.PAY_STATE.SUCCESS);
|
||||
break;
|
||||
case NOTPAY:
|
||||
case CLOSED:
|
||||
case REVOKED:
|
||||
resp.setState(PayResponse.PAY_STATE.FAIL);
|
||||
break;
|
||||
case REFUND:
|
||||
resp.setState(PayResponse.PAY_STATE.REFUND);
|
||||
break;
|
||||
default:
|
||||
resp.setState(PayResponse.PAY_STATE.CANCEL);
|
||||
break;
|
||||
}
|
||||
resp.setPayTime(parse.getSuccessTime());
|
||||
resp.setOriginalResponse(parse);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayResponse queryOrder(String orderNo) {
|
||||
Config wxConfig = getConfig();
|
||||
JsapiService service = new JsapiService.Builder().config(wxConfig).build();
|
||||
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
|
||||
queryRequest.setMchid(config.getMerchantId());
|
||||
queryRequest.setOutTradeNo(orderNo);
|
||||
PayResponse resp = new PayResponse();
|
||||
Transaction result = service.queryOrderByOutTradeNo(queryRequest);
|
||||
resp.setValid(true);
|
||||
resp.setOrderNo(result.getOutTradeNo());
|
||||
if (result.getAmount() != null) {
|
||||
resp.setOrderPrice(result.getAmount().getTotal());
|
||||
resp.setPayPrice(result.getAmount().getPayerTotal());
|
||||
}
|
||||
switch (result.getTradeState()) {
|
||||
case SUCCESS:
|
||||
resp.setState(PayResponse.PAY_STATE.SUCCESS);
|
||||
break;
|
||||
case NOTPAY:
|
||||
case CLOSED:
|
||||
case REVOKED:
|
||||
resp.setState(PayResponse.PAY_STATE.FAIL);
|
||||
break;
|
||||
case REFUND:
|
||||
resp.setState(PayResponse.PAY_STATE.REFUND);
|
||||
break;
|
||||
default:
|
||||
resp.setState(PayResponse.PAY_STATE.CANCEL);
|
||||
break;
|
||||
}
|
||||
resp.setPayTime(result.getSuccessTime());
|
||||
resp.setOriginalResponse(result);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefundOrderResponse refund(RefundOrderRequest request) {
|
||||
RefundOrderResponse resp = new RefundOrderResponse();
|
||||
Config wxConfig = getConfig();
|
||||
RefundService service = new RefundService.Builder().config(wxConfig).build();
|
||||
CreateRequest createRequest = new CreateRequest();
|
||||
createRequest.setOutTradeNo(request.getOrderNo());
|
||||
createRequest.setOutRefundNo(request.getRefundNo());
|
||||
AmountReq amountReq = new AmountReq();
|
||||
amountReq.setTotal(Long.valueOf(request.getPrice()));
|
||||
amountReq.setRefund(Long.valueOf(request.getRefundPrice()));
|
||||
amountReq.setCurrency("CNY");
|
||||
createRequest.setAmount(amountReq);
|
||||
createRequest.setNotifyUrl(request.getNotifyUrl());
|
||||
Refund refund = service.create(createRequest);
|
||||
if (refund.getStatus() == SUCCESS) {
|
||||
resp.setSuccess(true);
|
||||
resp.setRefundNo(refund.getOutRefundNo());
|
||||
} else {
|
||||
resp.setSuccess(false);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefundResponse handleRefundCallback(HttpServletRequest request) throws IOException {
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
StringBuffer body = new StringBuffer();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s;
|
||||
// 读取回调请求体
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
body.append(s);
|
||||
}
|
||||
RefundResponse resp = new RefundResponse();
|
||||
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||
String signType = request.getHeader(WECHAT_PAY_SIGNATURE_TYPE);
|
||||
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
|
||||
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||
NotificationConfig config = (NotificationConfig) getConfig();
|
||||
NotificationParser parser = new NotificationParser(config);RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(serialNo)
|
||||
.nonce(nonce)
|
||||
.signature(signature)
|
||||
.timestamp(timestamp)
|
||||
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(signType)
|
||||
.body(body.toString())
|
||||
.build();
|
||||
RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
|
||||
resp.setValid(true);
|
||||
resp.setOriginalResponse(parse);
|
||||
if (parse.getRefundStatus() == SUCCESS) {
|
||||
//退款成功
|
||||
resp.setSuccess();
|
||||
resp.setRefundTime(parse.getSuccessTime());
|
||||
resp.setOrderNo(parse.getOutTradeNo());
|
||||
resp.setRefundNo(parse.getRefundId());
|
||||
if (parse.getAmount() != null) {
|
||||
resp.setRefundPrice(Math.toIntExact(parse.getAmount().getPayerRefund()));
|
||||
resp.setOrderPrice(Math.toIntExact(parse.getAmount().getTotal()));
|
||||
}
|
||||
} else {
|
||||
//退款失败
|
||||
resp.setFail();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefundResponse checkRefundStatus(String refundNo) {
|
||||
Config wxConfig = getConfig();
|
||||
RefundService service = new RefundService.Builder().config(wxConfig).build();
|
||||
QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
|
||||
request.setOutRefundNo(refundNo);
|
||||
RefundResponse resp = new RefundResponse();
|
||||
Refund result = service.queryByOutRefundNo(request);
|
||||
resp.setValid(true);
|
||||
resp.setOriginalResponse(result);
|
||||
if (result.getStatus() == SUCCESS) {
|
||||
//退款成功
|
||||
resp.setSuccess();
|
||||
resp.setRefundTime(result.getSuccessTime());
|
||||
resp.setOrderNo(result.getOutTradeNo());
|
||||
resp.setRefundNo(result.getRefundId());
|
||||
if (result.getAmount() != null) {
|
||||
resp.setRefundPrice(Math.toIntExact(result.getAmount().getPayerRefund()));
|
||||
resp.setOrderPrice(Math.toIntExact(result.getAmount().getTotal()));
|
||||
}
|
||||
} else {
|
||||
//退款失败
|
||||
resp.setFail();
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOrder(CancelOrderRequest request) {
|
||||
CloseOrderRequest closeOrderRequest = new CloseOrderRequest();
|
||||
closeOrderRequest.setOutTradeNo(request.getOrderNo());
|
||||
closeOrderRequest.setMchid(config.getMerchantId());
|
||||
Config config = getConfig();
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
service.closeOrder(closeOrderRequest);
|
||||
}
|
||||
|
||||
public static String getSign(String signatureStr,String privateKey) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException {
|
||||
String replace = privateKey.replace("\\n", "\n");
|
||||
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromString(replace);
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
sign.initSign(merchantPrivateKey);
|
||||
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64Utils.encodeToString(sign.sign());
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CancelOrderRequest {
|
||||
private String orderNo;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CreateOrderRequest {
|
||||
/**
|
||||
* 价格,单位为分
|
||||
*/
|
||||
private Integer price;
|
||||
private String goodsName;
|
||||
private String orderNo;
|
||||
private String description;
|
||||
private String userIdentify;
|
||||
private String notifyUrl;
|
||||
|
||||
|
||||
public BigDecimal getPriceInYuan() {
|
||||
return new BigDecimal(BigInteger.valueOf(price), 2);
|
||||
}
|
||||
public CreateOrderRequest setPriceInCents(Integer priceInCents) {
|
||||
this.price = priceInCents;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CreateOrderRequest setPriceInYuan(BigDecimal priceInYuan) {
|
||||
this.price = priceInYuan.multiply(new BigDecimal(100)).intValue();
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CreateOrderResponse {
|
||||
private boolean success;
|
||||
private boolean skipPay;
|
||||
private String orderNo;
|
||||
}
|
34
src/main/java/com/ycwl/basic/pay/entity/PayResponse.java
Normal file
34
src/main/java/com/ycwl/basic/pay/entity/PayResponse.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PayResponse {
|
||||
private boolean valid;
|
||||
private String orderNo;
|
||||
private Object originalResponse;
|
||||
private Integer orderPrice;
|
||||
private Integer payPrice;
|
||||
private PAY_STATE state;
|
||||
private String payTime;
|
||||
|
||||
public boolean isPay() {
|
||||
return state == PAY_STATE.SUCCESS;
|
||||
}
|
||||
|
||||
public boolean isCancel() {
|
||||
return state == PAY_STATE.CANCEL;
|
||||
}
|
||||
|
||||
public boolean isRefund() {
|
||||
return state == PAY_STATE.REFUND;
|
||||
}
|
||||
|
||||
public enum PAY_STATE {
|
||||
SUCCESS,
|
||||
CANCEL,
|
||||
REFUND,
|
||||
FAIL,
|
||||
UNKNOWN;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RefundOrderRequest {
|
||||
private Integer price;
|
||||
private Integer refundPrice;
|
||||
private String orderNo;
|
||||
private String refundNo;
|
||||
private String notifyUrl;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RefundOrderResponse {
|
||||
private boolean success;
|
||||
private String refundNo;
|
||||
}
|
28
src/main/java/com/ycwl/basic/pay/entity/RefundResponse.java
Normal file
28
src/main/java/com/ycwl/basic/pay/entity/RefundResponse.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RefundResponse {
|
||||
private boolean valid;
|
||||
private String orderNo;
|
||||
private String refundNo;
|
||||
private Object originalResponse;
|
||||
private Integer orderPrice;
|
||||
private Integer refundPrice;
|
||||
private PAY_STATE state;
|
||||
private String refundTime;
|
||||
|
||||
public void setSuccess() {
|
||||
state = PAY_STATE.SUCCESS;
|
||||
}
|
||||
|
||||
public void setFail() {
|
||||
state = PAY_STATE.FAIL;
|
||||
}
|
||||
|
||||
public enum PAY_STATE {
|
||||
SUCCESS,
|
||||
FAIL
|
||||
}
|
||||
}
|
12
src/main/java/com/ycwl/basic/pay/entity/WxMpPayConfig.java
Normal file
12
src/main/java/com/ycwl/basic/pay/entity/WxMpPayConfig.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.ycwl.basic.pay.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WxMpPayConfig {
|
||||
private String merchantId;
|
||||
private String appId;
|
||||
private String privateKey;
|
||||
private String serialNumber;
|
||||
private String apiV3Key;
|
||||
}
|
20
src/main/java/com/ycwl/basic/pay/enums/PayAdapterType.java
Normal file
20
src/main/java/com/ycwl/basic/pay/enums/PayAdapterType.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.ycwl.basic.pay.enums;
|
||||
|
||||
public enum PayAdapterType {
|
||||
WX_MP_PAY("WX_MP_PAY"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
|
||||
PayAdapterType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.pay.exceptions;
|
||||
|
||||
public class PayException extends RuntimeException {
|
||||
public PayException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.pay.exceptions;
|
||||
|
||||
public class PayUndefinedException extends RuntimeException {
|
||||
public PayUndefinedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.pay.exceptions;
|
||||
|
||||
public class PayUnsupportedException extends PayException {
|
||||
public PayUnsupportedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.pay.exceptions;
|
||||
|
||||
public class PayWrongConfigException extends PayException {
|
||||
public PayWrongConfigException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.ycwl.basic.pay.starter;
|
||||
|
||||
import com.ycwl.basic.pay.PayFactory;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.starter.config.OverallPayConfig;
|
||||
import com.ycwl.basic.pay.starter.config.PayConfigItem;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class PayAutoConfiguration {
|
||||
private final OverallPayConfig config;
|
||||
public PayAutoConfiguration(OverallPayConfig config) {
|
||||
this.config = config;
|
||||
if (config != null) {
|
||||
if (config.getConfigs() != null) {
|
||||
loadConfig();
|
||||
}
|
||||
if (StringUtils.isNotBlank(config.getDefaultUse())) {
|
||||
PayFactory.setDefault(config.getDefaultUse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
for (PayConfigItem item : config.getConfigs()) {
|
||||
IPayAdapter adapter = PayFactory.getAdapter(item.getType());
|
||||
adapter.loadConfig(item.getConfig());
|
||||
PayFactory.register(item.getName(), adapter);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.ycwl.basic.pay.starter.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "pay")
|
||||
@Data
|
||||
public class OverallPayConfig {
|
||||
private String defaultUse;
|
||||
private List<PayConfigItem> configs;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.ycwl.basic.pay.starter.config;
|
||||
|
||||
import com.ycwl.basic.pay.enums.PayAdapterType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class PayConfigItem {
|
||||
private String name;
|
||||
private PayAdapterType type;
|
||||
private Map<String, String> config;
|
||||
}
|
@ -47,12 +47,37 @@ public class FeiETicketPrinter {
|
||||
//根据打印纸张的宽度,自行调整内容的格式,可参考下面的样例格式
|
||||
|
||||
String content;
|
||||
content = "<CB>帧途AI旅拍</CB><BR>";
|
||||
content += "┏━━━━━━━━━━━━━━┓<BR>";
|
||||
content += "┃┉3制67表01符45制89表23符6┉┃<BR>";
|
||||
content += "┣━━★━━♢━━◈━━◉━━┫<BR>";
|
||||
content += "┃123制67表01符45制89表23符678┃<BR>";
|
||||
content += "┗━━━━━━━━━━━━━━┛<BR>";
|
||||
content = "<BR><B>世界再大</B><BR>";
|
||||
content += "<B>你永远是这段旅途</B><BR>";
|
||||
content += "<B>的焦点</B><BR>";
|
||||
content += "━━━━━━━━━━━━━━━━<BR>";
|
||||
content += "<B>正片主演:</B><BR>";
|
||||
content += "旅途中最靓的你(测试名字很长很长故意不换行)<BR><BR>";
|
||||
content += "<B>拍摄地点:</B><BR>";
|
||||
content += "泸定桥<BR><BR>";
|
||||
content += "<B>拍摄日期:</B><BR>";
|
||||
content += "2025年4月4日<BR><BR>";
|
||||
content += "<B>大片内容:</B><BR>";
|
||||
content += "1.打卡泸定桥专属微电影(2部+)<BR>";
|
||||
content += "2.打卡录像集(5条)<BR>";
|
||||
content += "3.打卡照片集(5-10张)<BR>";
|
||||
content += "━━━━━━━━━━━━━━━━<BR>";
|
||||
content += "<C>帧帧皆故事 途途有回忆</C>";
|
||||
content += "<C>扫码即可观赏您的照片及视频</C>";
|
||||
content += "<BR><QR>https://zhentuai.com</QR>";
|
||||
content += "<CB>游后微信扫码查看</CB>";
|
||||
content += "<C>精彩指数:★★★★★</C><BR>";
|
||||
|
||||
// content += "┏━━━━━━━━━━━━━━┓<BR>";
|
||||
// content += "┏━━━━━━━━━━━━━━┓<BR>";
|
||||
// content += "┏━━━━━━━━━━━━━━┓<BR>";
|
||||
// content += "┃┉3制67表01符45制89表23符6┉┃<BR>";
|
||||
// content += "┣━━★━━♢━━◈━━◉━━┫<BR>";
|
||||
// content += "┣━━★━━♢━━◈━━◉━━┫<BR>";
|
||||
// content += "┣━━★━━♢━━◈━━◉━━┫<BR>";
|
||||
// content += "┣━━★━━♢━━◈━━◉━━┫<BR>";
|
||||
// content += "┃123制67表01符45制89表23符678┃<BR>";
|
||||
// content += "┗━━━━━━━━━━━━━━┛<BR>";
|
||||
return doPrint(sn,content,1);
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,26 @@
|
||||
package com.ycwl.basic.service.mobile;
|
||||
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
|
||||
public interface WxPayService {
|
||||
|
||||
/**
|
||||
* 微信预支付
|
||||
*/
|
||||
WxPayRespVO createOrder(WXPayOrderReqVO req) throws Exception;
|
||||
Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) throws Exception;
|
||||
|
||||
/**
|
||||
* 微信支付回调
|
||||
*/
|
||||
void payNotify(HttpServletRequest xml);
|
||||
void payNotify(HttpServletRequest request);
|
||||
|
||||
void payNotify(Long scenicId, HttpServletRequest request);
|
||||
|
||||
|
||||
/**
|
||||
@ -38,7 +40,7 @@ public interface WxPayService {
|
||||
/**
|
||||
* 微信退款回调
|
||||
*/
|
||||
boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException;
|
||||
boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException;
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
@ -46,4 +48,5 @@ public interface WxPayService {
|
||||
* @param orderId 订单id(订单编号)
|
||||
*/
|
||||
void closeOrder(String orderId) ;
|
||||
|
||||
}
|
||||
|
@ -3,11 +3,9 @@ package com.ycwl.basic.service.mobile.impl;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
import com.ycwl.basic.enums.AgreementEnum;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.enums.WechatErrorCodeEnum;
|
||||
import com.ycwl.basic.exception.AppException;
|
||||
@ -137,7 +135,7 @@ public class AppMemberServiceImpl implements AppMemberService {
|
||||
public ApiResponse<?> agreement() {
|
||||
MemberEntity memberEntity = new MemberEntity();
|
||||
memberEntity.setId(Long.parseLong(BaseContextHandler.getUserId()));
|
||||
memberEntity.setAgreement(AgreementEnum.AGREE.getType());
|
||||
memberEntity.setAgreement(1);
|
||||
return ApiResponse.success(memberMapper.update(memberEntity));
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -199,7 +203,20 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsDetailVO.setGoodsType(sourceType);
|
||||
goodsDetailVO.setSourceType(sourceType);
|
||||
goodsDetailVO.setGoodsId(sourceRespVO.getId());
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
if (sourceRespVO.getVideoUrl() != null) {
|
||||
try {
|
||||
URL url = new URL(sourceRespVO.getVideoUrl());
|
||||
if (StringUtils.startsWith(url.getHost(), "100.64.")) {
|
||||
// 内网地址,需要代理
|
||||
goodsDetailVO.setVideoUrl("https://zhentuai.com/proxy?url=" + sourceRespVO.getVideoUrl());
|
||||
} else {
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
log.warn("url地址解析异常:{}", sourceRespVO.getVideoUrl(), e);
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
}
|
||||
goodsDetailVO.setUrl(sourceRespVO.getUrl());
|
||||
goodsDetailVO.setCreateTime(sourceRespVO.getCreateTime());
|
||||
goodsDetailVO.setIsFree(sourceRespVO.getIsFree());
|
||||
@ -378,7 +395,9 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
response.setCount(finishedTask);
|
||||
int faceCutStatus = taskStatusBiz.getFaceCutStatus(faceId);
|
||||
if (Integer.valueOf(0).equals(faceCutStatus)) {
|
||||
response.setTemplateId(notFinishedTasks.get(0).getTemplateId());
|
||||
if (!notFinishedTasks.isEmpty()) {
|
||||
response.setTemplateId(notFinishedTasks.get(0).getTemplateId());
|
||||
}
|
||||
response.setStatus(2);
|
||||
return response;
|
||||
}
|
||||
@ -430,10 +449,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
public ApiResponse<GoodsDetailVO> sourceGoodsInfo(Long sourceId) {
|
||||
SourceRespVO sourceRespVO = sourceMapper.getById(sourceId);
|
||||
if (sourceRespVO == null) {
|
||||
sourceRespVO = sourceMapper.getById(sourceId);
|
||||
if (sourceRespVO == null) {
|
||||
return ApiResponse.fail("该视频不存在");
|
||||
}
|
||||
return ApiResponse.fail("该视频不存在");
|
||||
}
|
||||
GoodsDetailVO goodsDetailVO = new GoodsDetailVO();
|
||||
goodsDetailVO.setGoodsName("原片");
|
||||
@ -441,7 +457,20 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsDetailVO.setScenicName(sourceRespVO.getScenicName());
|
||||
goodsDetailVO.setGoodsType(sourceRespVO.getType());
|
||||
goodsDetailVO.setGoodsId(sourceRespVO.getId());
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
if (sourceRespVO.getVideoUrl() != null) {
|
||||
try {
|
||||
URL url = new URL(sourceRespVO.getVideoUrl());
|
||||
if (StringUtils.startsWith(url.getHost(), "100.64.")) {
|
||||
// 内网地址,需要代理
|
||||
goodsDetailVO.setVideoUrl("https://zhentuai.com/proxy?url=" + sourceRespVO.getVideoUrl());
|
||||
} else {
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
log.warn("url地址解析异常:{}", sourceRespVO.getVideoUrl(), e);
|
||||
goodsDetailVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
}
|
||||
goodsDetailVO.setTemplateCoverUrl(sourceRespVO.getUrl());
|
||||
goodsDetailVO.setCreateTime(sourceRespVO.getCreateTime());
|
||||
return ApiResponse.success(goodsDetailVO);
|
||||
@ -522,7 +551,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
log.error("process error", e);
|
||||
return;
|
||||
}
|
||||
String url = adapter.uploadFile(watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
String url = adapter.uploadFile(null, watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
sourceMapper.addSourceWatermark(item.getGoodsId(), null, ImageWatermarkOperatorEnum.WATERMARK.getType(), url);
|
||||
tmpFile.add(watermarkedFile);
|
||||
@ -634,7 +663,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
log.error("process error", e);
|
||||
return;
|
||||
}
|
||||
String url = adapter.uploadFile(watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
String url = adapter.uploadFile(null, watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
|
||||
sourceMapper.addSourceWatermark(item.getGoodsId(), face.getId(), type.getType(), url);
|
||||
tmpFile.add(watermarkedFile);
|
||||
|
@ -1,28 +1,8 @@
|
||||
package com.ycwl.basic.service.mobile.impl;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.utils.StringUtils;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||
import com.wechat.pay.java.core.exception.ServiceException;
|
||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.core.util.PemUtil;
|
||||
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||
import com.wechat.pay.java.service.payments.jsapi.model.*;
|
||||
import com.wechat.pay.java.service.payments.model.TransactionAmount;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import com.wechat.pay.java.service.refund.model.AmountReq;
|
||||
import com.wechat.pay.java.service.refund.model.CreateRequest;
|
||||
import com.wechat.pay.java.service.refund.model.Refund;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.config.WechatConfig;
|
||||
import com.ycwl.basic.constant.HttpConstant;
|
||||
import com.ycwl.basic.constant.NumberConstant;
|
||||
import com.ycwl.basic.constant.WeiXinConstant;
|
||||
import com.ycwl.basic.enums.BizCodeEnum;
|
||||
import com.ycwl.basic.enums.OrderStateEnum;
|
||||
import com.ycwl.basic.enums.StatisticEnum;
|
||||
@ -35,37 +15,28 @@ import com.ycwl.basic.model.pc.order.entity.OrderEntity;
|
||||
import com.ycwl.basic.model.pc.order.req.OrderUpdateReq;
|
||||
import com.ycwl.basic.model.pc.payment.entity.PaymentEntity;
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.pay.entity.CancelOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.CreateOrderResponse;
|
||||
import com.ycwl.basic.pay.entity.PayResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundResponse;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderRequest;
|
||||
import com.ycwl.basic.pay.entity.RefundOrderResponse;
|
||||
import com.ycwl.basic.repository.OrderRepository;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
import com.ycwl.basic.service.pc.ScenicService;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.WXPayUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.wechat.pay.java.core.http.Constant.*;
|
||||
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
|
||||
import static com.ycwl.basic.constant.WeiXinConstant.*;
|
||||
|
||||
/**
|
||||
* @Author: songmingsong
|
||||
@ -77,8 +48,6 @@ import static com.ycwl.basic.constant.WeiXinConstant.*;
|
||||
@Service
|
||||
public class WxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Autowired
|
||||
private WechatConfig wechatConfig;
|
||||
@Autowired
|
||||
private PaymentMapper paymentMapper;
|
||||
@Autowired
|
||||
@ -89,116 +58,50 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
private OrderBiz orderBiz;
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
@Override
|
||||
public WxPayRespVO createOrder(WXPayOrderReqVO req) {
|
||||
public Map<String, Object> createOrder(Long scenicId, WXPayOrderReqVO req) {
|
||||
PaymentEntity entity = new PaymentEntity();
|
||||
entity.setOrderId(req.getOrderSn());
|
||||
entity.setMemberId(req.getMemberId());
|
||||
entity.setPayPrice(new BigDecimal(BigInteger.valueOf(req.getTotalPrice()), 2));
|
||||
Long entityId = paymentMapper.addGetId(entity);
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
// 使用自动更新平台证书的RSA配置
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
|
||||
// request.setXxx(val)设置所需参数,具体参数可见Request定义
|
||||
PrepayRequest request = new PrepayRequest();
|
||||
Amount amount = new Amount();
|
||||
amount.setTotal(req.getTotalPrice());
|
||||
request.setAmount(amount);
|
||||
request.setAppid(wechatConfig.getMiniProgramAppId());
|
||||
request.setMchid(wechatConfig.getMchId());
|
||||
request.setDescription(req.getGoodsName());
|
||||
request.setNotifyUrl(wechatConfig.getPayNotifyUrl());
|
||||
request.setOutTradeNo(req.getOrderSn().toString());
|
||||
request.setDescription(req.getDescription());
|
||||
|
||||
Payer payer = new Payer();
|
||||
payer.setOpenid(req.getOpenId());
|
||||
request.setPayer(payer);
|
||||
// SettleInfo settleInfo = new SettleInfo();
|
||||
// settleInfo.setProfitSharing(true);
|
||||
// request.setSettleInfo(settleInfo);
|
||||
|
||||
// 调用下单方法,得到应答
|
||||
PrepayResponse response = service.prepay(request);
|
||||
WxPayRespVO vo = new WxPayRespVO();
|
||||
Long timeStamp = System.currentTimeMillis() / NumberConstant.THOUSAND;
|
||||
vo.setTimeStamp(timeStamp);
|
||||
String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
|
||||
vo.setNonceStr(substring);
|
||||
String signatureStr = Stream.of(wechatConfig.getMiniProgramAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId())
|
||||
.collect(Collectors.joining("\n", "", "\n"));
|
||||
String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath());
|
||||
vo.setPaySign(sign);
|
||||
vo.setSignType("RSA-SHA256");
|
||||
vo.setPrepayId("prepay_id=" + response.getPrepayId());
|
||||
return vo;
|
||||
} catch (ServiceException e) {
|
||||
JSONObject parse = JSONObject.parseObject(e.getResponseBody());
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, parse.getString(HttpConstant.Message));
|
||||
CreateOrderRequest request = new CreateOrderRequest()
|
||||
.setOrderNo(String.valueOf(req.getOrderSn()))
|
||||
.setPriceInCents(req.getTotalPrice())
|
||||
.setDescription(req.getDescription())
|
||||
.setGoodsName(req.getGoodsName())
|
||||
.setUserIdentify(req.getOpenId())
|
||||
.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+scenicId+"/payNotify");
|
||||
CreateOrderResponse order = scenicPayAdapter.createOrder(request);
|
||||
Map<String, Object> paymentParams = scenicPayAdapter.getPaymentParams(order);
|
||||
paymentParams.put("needPay", !order.isSkipPay());
|
||||
return paymentParams;
|
||||
} catch (Exception e) {
|
||||
throw new AppException(BizCodeEnum.ADVANCE_PAYMENT_FAILED, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payNotify(HttpServletRequest request) {
|
||||
public void payNotify(Long scenicId, HttpServletRequest request) {
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
// 读取请求体的信息
|
||||
ServletInputStream inputStream = request.getInputStream();
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String s;
|
||||
// 读取回调请求体
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
stringBuffer.append(s);
|
||||
}
|
||||
String s1 = stringBuffer.toString();
|
||||
log.warn("微信支付回调:{}", s1);
|
||||
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
|
||||
String nonce = request.getHeader(WECHAT_PAY_NONCE);
|
||||
String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE);
|
||||
String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
|
||||
String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
|
||||
|
||||
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
// 初始化 NotificationParser
|
||||
NotificationParser parser = new NotificationParser(config);
|
||||
RequestParam requestParam = new RequestParam.Builder()
|
||||
.serialNumber(serialNo)
|
||||
.nonce(nonce)
|
||||
.signature(signature)
|
||||
.timestamp(timestamp)
|
||||
// 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
|
||||
.signType(signType)
|
||||
.body(s1)
|
||||
.build();
|
||||
Transaction parse = parser.parse(requestParam, Transaction.class);
|
||||
log.info("[微信支付]parse = {}", parse);
|
||||
PayResponse callbackResponse = scenicPayAdapter.handleCallback(request);
|
||||
log.info("[微信支付]parse = {}", callbackResponse);
|
||||
|
||||
// 更新订单信息
|
||||
new Thread(() -> {
|
||||
long orderId = Long.parseLong(parse.getOutTradeNo());
|
||||
switch (parse.getTradeState()) {
|
||||
case SUCCESS:
|
||||
orderBiz.paidOrder(orderId);
|
||||
break;
|
||||
case NOTPAY:
|
||||
case CLOSED:
|
||||
case REVOKED:
|
||||
orderBiz.cancelOrder(orderId);
|
||||
break;
|
||||
case REFUND:
|
||||
orderBiz.refundOrder(orderId);
|
||||
break;
|
||||
long orderId = Long.parseLong(callbackResponse.getOrderNo());
|
||||
if (callbackResponse.isPay()) {
|
||||
orderBiz.paidOrder(orderId);
|
||||
} else if (callbackResponse.isCancel()) {
|
||||
orderBiz.cancelOrder(orderId);
|
||||
} else if (callbackResponse.isRefund()) {
|
||||
orderBiz.refundOrder(orderId);
|
||||
}
|
||||
}).start();
|
||||
} catch (Exception e) {
|
||||
@ -207,59 +110,29 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxchatCallbackSuccessData queryPay(Long orderId) {
|
||||
WxchatCallbackSuccessData wxchatCallbackSuccessData = new WxchatCallbackSuccessData();
|
||||
QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
|
||||
queryRequest.setMchid(wechatConfig.getMchId());
|
||||
queryRequest.setOutTradeNo(orderId.toString());
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
try {
|
||||
com.wechat.pay.java.service.payments.model.Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
|
||||
String successTime = transaction.getSuccessTime();
|
||||
public void payNotify(HttpServletRequest request) {
|
||||
payNotify(0L, request);
|
||||
}
|
||||
|
||||
wxchatCallbackSuccessData.setOrderId(orderId.toString());
|
||||
wxchatCallbackSuccessData.setSuccessTime(successTime);
|
||||
wxchatCallbackSuccessData.setTradetype(WeiXinConstant.getDescriptionType(transaction.getTradeType()));
|
||||
wxchatCallbackSuccessData.setTradestate(WeiXinConstant.getDescriptionState(transaction.getTradeState()));
|
||||
TransactionAmount amount = transaction.getAmount();
|
||||
Integer total = amount.getTotal();
|
||||
wxchatCallbackSuccessData.setTotalMoney(new BigDecimal(total).movePointLeft(2));
|
||||
} catch (ServiceException e) {
|
||||
// API返回失败, 例如ORDER_NOT_EXISTS
|
||||
log.error("[微信退款] code={}, message={}", e.getErrorCode(), e.getErrorMessage());
|
||||
log.error("[微信退款] Response_body={}", e.getResponseBody());
|
||||
}
|
||||
return wxchatCallbackSuccessData;
|
||||
@Override
|
||||
public WxchatCallbackSuccessData queryPay(Long orderId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean refundOrder(String orderId) {
|
||||
OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
|
||||
BigDecimal payPrice = order.getPayPrice();
|
||||
long priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).longValue(); // 转换为分(int)
|
||||
|
||||
Config config =
|
||||
new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
RefundService service = new RefundService.Builder().config(config).build();
|
||||
CreateRequest request = new CreateRequest();
|
||||
request.setNotifyUrl(wechatConfig.getRefundNotifyUrl());
|
||||
AmountReq amountReq = new AmountReq();
|
||||
amountReq.setTotal(priceInCents);
|
||||
amountReq.setRefund(priceInCents);
|
||||
amountReq.setCurrency(WECHATPAY_CURRENCY_CNY);
|
||||
request.setAmount(amountReq);
|
||||
request.setOutTradeNo(orderId);
|
||||
request.setOutRefundNo(SnowFlakeUtil.getId());
|
||||
Refund refundResult = service.create(request);
|
||||
if (refundResult.getStatus() == SUCCESS) {
|
||||
int priceInCents = payPrice.multiply(new BigDecimal(NumberConstant.HUNDRED)).intValue(); // 转换为分(int)
|
||||
RefundOrderRequest request = new RefundOrderRequest()
|
||||
.setOrderNo(orderId)
|
||||
.setPrice(priceInCents)
|
||||
.setRefundNo(SnowFlakeUtil.getId())
|
||||
.setRefundPrice(priceInCents)
|
||||
.setNotifyUrl("https://zhentuai.com/api/mobile/wx/pay/v1/"+order.getScenicId()+"/refundNotify");
|
||||
RefundOrderResponse response = scenicPayAdapter.refund(request);
|
||||
if (response.isSuccess()) {
|
||||
OrderUpdateReq orderUpdateReq = new OrderUpdateReq();
|
||||
orderUpdateReq.setId(Long.parseLong(orderId));
|
||||
orderUpdateReq.setRefundStatus(OrderStateEnum.REFUNDED.getType());
|
||||
@ -272,31 +145,14 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean refundNotify(String refundResult) throws IOException, GeneralSecurityException {
|
||||
// 转为map格式
|
||||
Map<String, String> jsonMap = JSONObject.parseObject(refundResult, Map.class);
|
||||
public boolean refundNotify(Long scenicId, HttpServletRequest request) throws IOException {
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(scenicId);
|
||||
try {
|
||||
RefundResponse callbackResponse = scenicPayAdapter.handleRefundCallback(request);
|
||||
log.info("[微信支付]parse = {}", callbackResponse);
|
||||
|
||||
/*
|
||||
* 退款成功后返回一个加密字段resource,以下为解密
|
||||
* 解密需要从resource参数中,获取到ciphertext,nonce,associated_data这三个参数进行解密
|
||||
*/
|
||||
String resource = JSONObject.toJSONString(jsonMap.get(REFUNDS_RESOURCE));
|
||||
JSONObject object = JSONObject.parseObject(resource);
|
||||
|
||||
String ciphertext = String.valueOf(object.get(REFUNDS_CIPHERTEXT));
|
||||
String nonce = String.valueOf(object.get(REFUNDS_NONCE));
|
||||
String associated_data = String.valueOf(object.get(REFUNDS_ASSOCIATED_DATA));
|
||||
|
||||
String resultStr = decryptToString(associated_data.getBytes(String.valueOf(StandardCharsets.UTF_8)),
|
||||
nonce.getBytes(String.valueOf(StandardCharsets.UTF_8)),
|
||||
ciphertext);
|
||||
Map<String, String> reqInfo = JSONObject.parseObject(resultStr, Map.class);
|
||||
|
||||
String refund_status = reqInfo.get(REFUNDS_REFUND_STATUS);// 退款状态
|
||||
String out_trade_no = reqInfo.get(WECHATPAY_OUT_TRADE_NO); // 订单号
|
||||
|
||||
if (!StringUtils.isEmpty(refund_status) && WECHATPAY_SUCCESS.equals(refund_status)) {
|
||||
long orderId = Long.parseLong(out_trade_no);
|
||||
// 更新订单信息
|
||||
long orderId = Long.parseLong(callbackResponse.getOrderNo());
|
||||
orderBiz.refundOrder(orderId);
|
||||
|
||||
OrderEntity order = orderRepository.getOrder(orderId);
|
||||
@ -306,117 +162,19 @@ public class WxPayServiceImpl implements WxPayService {
|
||||
statisticsRecordAddReq.setScenicId(order.getScenicId());
|
||||
statisticsRecordAddReq.setMorphId(orderId);
|
||||
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
|
||||
|
||||
log.info("[微信退款回调]退款成功");
|
||||
return true;
|
||||
} else {
|
||||
log.error("[微信退款回调]退款失败");
|
||||
} catch (Exception e) {
|
||||
log.error("微信退款回调失败!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOrder(String orderId) {
|
||||
CloseOrderRequest closeOrderRequest = new CloseOrderRequest();
|
||||
closeOrderRequest.setOutTradeNo(orderId);
|
||||
closeOrderRequest.setMchid(wechatConfig.getMchId());
|
||||
Config config = getInstance(wechatConfig);
|
||||
// 构建service
|
||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||
service.closeOrder(closeOrderRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 退款回调 解密数据
|
||||
*
|
||||
* @param associatedData
|
||||
* @param nonce
|
||||
* @param ciphertext
|
||||
* @return
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
SecretKeySpec key = new SecretKeySpec(wechatConfig.getApiV3().getBytes(), "AES");
|
||||
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, spec);
|
||||
cipher.updateAAD(associatedData);
|
||||
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成退款请求token
|
||||
*
|
||||
* @param method
|
||||
* @param orderId
|
||||
* @param body
|
||||
* @return
|
||||
* @throws InvalidKeyException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws UnsupportedEncodingException
|
||||
* @throws SignatureException
|
||||
*/
|
||||
public String getToken(String method, String orderId, String body) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, SignatureException {
|
||||
String nonceStr = WXPayUtil.generateNonceStr();
|
||||
long timestamp = System.currentTimeMillis() / NumberConstant.THOUSAND; // 生成时间戳
|
||||
|
||||
String parameter = method + "\n"
|
||||
+ REFUNDS_URi + orderId + "\n"
|
||||
+ timestamp + "\n"
|
||||
+ nonceStr + "\n"
|
||||
+ body + "\n";
|
||||
|
||||
// 对参数进行加密
|
||||
byte[] bytes = parameter.getBytes(String.valueOf(StandardCharsets.UTF_8));
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
PrivateKey privateKey = PemUtil.loadPrivateKeyFromString(wechatConfig.getKeyPath()); // privateKeyPath是商户证书密钥的位置apiclient_key.pem
|
||||
sign.initSign(privateKey); // 商户密钥文件路径
|
||||
sign.update(bytes);
|
||||
String signature = Base64.getEncoder().encodeToString(sign.sign());
|
||||
|
||||
// 获取token
|
||||
String token = "mchid=\"" + wechatConfig.getMchId() + "\"," // 商户号
|
||||
+ "nonce_str=\"" + nonceStr + "\","
|
||||
+ "timestamp=\"" + timestamp + "\","
|
||||
+ "serial_no=\"" + wechatConfig.getMchSerialNo() + "\"," // merchantSerialNumber是微信支付中申请的证书序列号
|
||||
+ "signature=\"" + signature + "\"";
|
||||
|
||||
return REFUNDS_SCHEMA + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
|
||||
*/
|
||||
private static class Holder {
|
||||
private static volatile Config instance;
|
||||
|
||||
static void init(WechatConfig wechatConfig) {
|
||||
instance = new RSAAutoCertificateConfig.Builder()
|
||||
.merchantId(wechatConfig.getMchId())
|
||||
.privateKey(wechatConfig.getKeyPath())
|
||||
.merchantSerialNumber(wechatConfig.getMchSerialNo())
|
||||
.apiV3Key(wechatConfig.getApiV3())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public static Config getInstance(WechatConfig wechatConfig) {
|
||||
if (Holder.instance == null) {
|
||||
synchronized (Holder.class) {
|
||||
if (Holder.instance == null) {
|
||||
Holder.init(wechatConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Holder.instance;
|
||||
OrderEntity order = orderRepository.getOrder(Long.parseLong(orderId));
|
||||
IPayAdapter scenicPayAdapter = scenicService.getScenicPayAdapter(order.getScenicId());
|
||||
CancelOrderRequest request = new CancelOrderRequest()
|
||||
.setOrderNo(orderId);
|
||||
scenicPayAdapter.cancelOrder(request);
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,13 @@ import com.ycwl.basic.model.pc.order.entity.OrderEntity;
|
||||
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.OrderUpdateReq;
|
||||
import com.ycwl.basic.model.pc.order.req.OrderAddReq;
|
||||
import com.ycwl.basic.model.pc.order.req.OrderReqQuery;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
|
||||
import com.ycwl.basic.model.pc.order.resp.OrderRespVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author:longbinbin
|
||||
@ -63,7 +62,7 @@ public interface OrderService {
|
||||
|
||||
ApiResponse<PageInfo<OrderRespVO>> refundPageQuery(OrderReqQuery query);
|
||||
|
||||
ApiResponse<WxPayRespVO> createOrder(Long userId, CreateOrderReqVO orderAddReq) throws Exception;
|
||||
ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO orderAddReq) throws Exception;
|
||||
|
||||
ApiResponse<WxPayRespVO> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception;
|
||||
ApiResponse<Map<String, Object>> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception;
|
||||
}
|
||||
|
@ -19,4 +19,6 @@ public interface PriceConfigService extends IService<PriceConfigEntity> {
|
||||
void fillGoodsName(List<PriceConfigRespVO> result);
|
||||
|
||||
void fillGoodsName(PriceConfigRespVO config);
|
||||
|
||||
void updateStatus(Integer id);
|
||||
}
|
@ -6,6 +6,7 @@ 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.pay.adapter.IPayAdapter;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
|
||||
@ -36,5 +37,11 @@ public interface ScenicService {
|
||||
|
||||
IStorageAdapter getScenicStorageAdapter(Long scenicId);
|
||||
|
||||
IStorageAdapter getScenicTmpStorageAdapter(Long scenicId);
|
||||
|
||||
IStorageAdapter getScenicLocalStorageAdapter(Long scenicId);
|
||||
|
||||
IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId);
|
||||
|
||||
IPayAdapter getScenicPayAdapter(Long scenicId);
|
||||
}
|
||||
|
@ -136,14 +136,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
String faceUrl = adapter.uploadFile(file, filePath, fileName);
|
||||
Long newFaceId = SnowFlakeUtil.getLongId();
|
||||
Long oldFaceId = null;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
IFaceBodyAdapter faceBodyAdapter;
|
||||
if (scenicConfig != null && scenicConfig.getFaceType() != null) {
|
||||
faceBodyAdapter = FaceBodyFactory.getAdapter(scenicConfig.getFaceType());
|
||||
faceBodyAdapter.loadConfig(JSONObject.parseObject(scenicConfig.getFaceConfigJson(), Map.class));
|
||||
} else {
|
||||
faceBodyAdapter = FaceBodyFactory.use();
|
||||
}
|
||||
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
|
||||
faceService.assureFaceDb(faceBodyAdapter, USER_FACE_DB_NAME+scenicId);
|
||||
SearchFaceRespVo userDbSearchResult = faceService.searchFace(faceBodyAdapter, USER_FACE_DB_NAME+scenicId, faceUrl, "判断是否为用户上传过的人脸");
|
||||
float strictScore = 0.6F;
|
||||
@ -225,13 +218,7 @@ public class FaceServiceImpl implements FaceService {
|
||||
return null;
|
||||
}
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
|
||||
IFaceBodyAdapter faceBodyAdapter;
|
||||
if (scenicConfig != null && scenicConfig.getFaceType() != null) {
|
||||
faceBodyAdapter = FaceBodyFactory.getAdapter(scenicConfig.getFaceType());
|
||||
faceBodyAdapter.loadConfig(JSONObject.parseObject(scenicConfig.getFaceConfigJson(), Map.class));
|
||||
} else {
|
||||
faceBodyAdapter = FaceBodyFactory.use();
|
||||
}
|
||||
IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(face.getScenicId());
|
||||
SearchFaceRespVo scenicDbSearchResult = faceService.searchFace(faceBodyAdapter, String.valueOf(face.getScenicId()), face.getFaceUrl(), "人脸识别");
|
||||
if (scenicDbSearchResult == null) {
|
||||
throw new BaseException("人脸识别失败,请换一张试试把~");
|
||||
@ -244,7 +231,10 @@ public class FaceServiceImpl implements FaceService {
|
||||
FaceSampleEntity faceSample = faceRepository.getFaceSample(resultItem);
|
||||
if (faceSample != null) {
|
||||
// 以这个结果为人脸库的匹配结果
|
||||
scenicDbSearchResult = faceService.searchFace(faceBodyAdapter, String.valueOf(face.getScenicId()), faceSample.getFaceUrl(), "人脸补救措施1");
|
||||
SearchFaceRespVo tmpResult = faceService.searchFace(faceBodyAdapter, String.valueOf(face.getScenicId()), faceSample.getFaceUrl(), "人脸补救措施1");
|
||||
if (tmpResult != null && tmpResult.getSampleListIds() != null && !tmpResult.getSampleListIds().isEmpty()) {
|
||||
scenicDbSearchResult = tmpResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
|
||||
import com.ycwl.basic.model.wx.WxPayRespVO;
|
||||
import com.ycwl.basic.repository.FaceRepository;
|
||||
import com.ycwl.basic.repository.PriceRepository;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
@ -52,7 +51,9 @@ import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -167,11 +168,12 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
/**
|
||||
* 发起支付
|
||||
* @param order 订单
|
||||
*
|
||||
* @param order 订单
|
||||
* @param orderItems 商品详情
|
||||
* @return 支付请求结果
|
||||
*/
|
||||
private WxPayRespVO initiatePayment(OrderEntity order, List<OrderItemEntity> orderItems) throws Exception {
|
||||
private Map<String, Object> initiatePayment(OrderEntity order, List<OrderItemEntity> orderItems) throws Exception {
|
||||
WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO();
|
||||
String goodsName = null;
|
||||
if (orderItems.size() > 1) {
|
||||
@ -186,12 +188,6 @@ public class OrderServiceImpl implements OrderService {
|
||||
goodsName = "景区照片包";
|
||||
}
|
||||
}
|
||||
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
// 0元支付
|
||||
WxPayRespVO wxPayRespVO = new WxPayRespVO();
|
||||
wxPayRespVO.setNeedPay(false);
|
||||
return wxPayRespVO;
|
||||
}
|
||||
wxPayOrderReqVO.setOpenId(order.getOpenId())
|
||||
.setMemberId(order.getMemberId())
|
||||
.setOrderSn(order.getId())
|
||||
@ -199,7 +195,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
.setGoodsName(goodsName)
|
||||
.setDescription(goodsName);
|
||||
|
||||
return wxPayService.createOrder(wxPayOrderReqVO);
|
||||
return wxPayService.createOrder(order.getScenicId(), wxPayOrderReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -360,7 +356,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResponse<WxPayRespVO> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception {
|
||||
public ApiResponse<Map<String, Object>> createOrder(Long userId, CreateOrderReqVO createOrderReqVO) throws Exception {
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(userId, createOrderReqVO.getScenicId(), createOrderReqVO.getGoodsType(), createOrderReqVO.getGoodsId());
|
||||
if (isBuy.isBuy()) {
|
||||
return ApiResponse.fail("您已购买此内容,无需重复购买!");
|
||||
@ -442,16 +438,18 @@ public class OrderServiceImpl implements OrderService {
|
||||
}
|
||||
if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
orderBiz.paidOrder(order.getId());
|
||||
return ApiResponse.success(new WxPayRespVO());
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("needPay", false);
|
||||
return ApiResponse.success(data);
|
||||
} else {
|
||||
WxPayRespVO wxPayRespVO = initiatePayment(order, orderItems);
|
||||
Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
|
||||
return ApiResponse.success(wxPayRespVO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ApiResponse<WxPayRespVO> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
|
||||
public ApiResponse<Map<String, Object>> createBatchOrder(Long userId, CreateBatchOrderReqVO batchOrderReqVO) throws Exception {
|
||||
PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(batchOrderReqVO.getScenicId(), batchOrderReqVO.getType(), batchOrderReqVO.getGoodsId());
|
||||
if (priceConfig == null) {
|
||||
return ApiResponse.fail("该套餐暂未开放购买");
|
||||
@ -504,9 +502,11 @@ public class OrderServiceImpl implements OrderService {
|
||||
}
|
||||
if (order.getPayPrice().equals(BigDecimal.ZERO)) {
|
||||
orderBiz.paidOrder(order.getId());
|
||||
return ApiResponse.success(new WxPayRespVO());
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("needPay", false);
|
||||
return ApiResponse.success(data);
|
||||
} else {
|
||||
WxPayRespVO wxPayRespVO = initiatePayment(order, orderItems);
|
||||
Map<String, Object> wxPayRespVO = initiatePayment(order, orderItems);
|
||||
return ApiResponse.success(wxPayRespVO);
|
||||
}
|
||||
}
|
||||
|
@ -74,4 +74,9 @@ public class PriceConfigServiceImpl extends ServiceImpl<PriceConfigMapper, Price
|
||||
item.setGoodsNames(StringUtils.join(goodsNames, ","));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(Integer id) {
|
||||
baseMapper.updateStatus(id);
|
||||
}
|
||||
}
|
@ -12,11 +12,14 @@ 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.pay.PayFactory;
|
||||
import com.ycwl.basic.pay.adapter.IPayAdapter;
|
||||
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;
|
||||
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -105,6 +108,7 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
scenicRepository.clearCache(id);
|
||||
scenicFaceBodyAdapterMap.remove(id);
|
||||
scenicStorageAdapterMap.remove(id);
|
||||
scenicPayAdapterMap.remove(id);
|
||||
return ApiResponse.success(true);
|
||||
}else {
|
||||
return ApiResponse.fail("景区删除失败");
|
||||
@ -197,6 +201,9 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
scenicRepository.clearCache(config.getScenicId());
|
||||
scenicFaceBodyAdapterMap.remove(config.getScenicId());
|
||||
scenicStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicTmpStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicLocalStorageAdapterMap.remove(config.getScenicId());
|
||||
scenicPayAdapterMap.remove(config.getScenicId());
|
||||
}
|
||||
|
||||
|
||||
@ -207,14 +214,57 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
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));
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getStoreType());
|
||||
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return StorageFactory.use("video");
|
||||
}
|
||||
} else {
|
||||
adapter = StorageFactory.use("video");
|
||||
}
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
private static final Map<Long, IStorageAdapter> scenicTmpStorageAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IStorageAdapter getScenicTmpStorageAdapter(Long scenicId) {
|
||||
return scenicTmpStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
IStorageAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getTmpStoreType() != null) {
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getTmpStoreType());
|
||||
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getTmpStoreConfigJson(), Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
} else {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
private static final Map<Long, IStorageAdapter> scenicLocalStorageAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IStorageAdapter getScenicLocalStorageAdapter(Long scenicId) {
|
||||
return scenicLocalStorageAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
IStorageAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getLocalStoreType() != null) {
|
||||
try {
|
||||
adapter = StorageFactory.get(scenicConfig.getLocalStoreType());
|
||||
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getLocalStoreConfigJson(), Map.class));
|
||||
} catch (StorageUnsupportedException ignored) {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
} else {
|
||||
return getScenicStorageAdapter(scenicId);
|
||||
}
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
|
||||
private static final Map<Long, IFaceBodyAdapter> scenicFaceBodyAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IFaceBodyAdapter getScenicFaceBodyAdapter(Long scenicId) {
|
||||
@ -230,4 +280,20 @@ public class ScenicServiceImpl implements ScenicService {
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
|
||||
private static final Map<Long, IPayAdapter> scenicPayAdapterMap = new ConcurrentHashMap<>();
|
||||
@Override
|
||||
public IPayAdapter getScenicPayAdapter(Long scenicId) {
|
||||
return scenicPayAdapterMap.computeIfAbsent(scenicId, (key) -> {
|
||||
IPayAdapter adapter;
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
if (scenicConfig != null && scenicConfig.getPayType() != null) {
|
||||
adapter = PayFactory.getAdapter(scenicConfig.getPayType());
|
||||
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getPayConfigJson(), Map.class));
|
||||
} else {
|
||||
adapter = PayFactory.use();
|
||||
}
|
||||
return adapter;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,12 @@ import com.ycwl.basic.service.pc.SourceService;
|
||||
import com.ycwl.basic.task.VideoPieceGetter;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -32,18 +35,63 @@ public class SourceServiceImpl implements SourceService {
|
||||
public ApiResponse<PageInfo<SourceRespVO>> pageQuery(SourceReqQuery sourceReqQuery) {
|
||||
PageHelper.startPage(sourceReqQuery.getPageNum(), sourceReqQuery.getPageSize());
|
||||
List<SourceRespVO> list = sourceMapper.list(sourceReqQuery);
|
||||
list.forEach(sourceRespVO -> {
|
||||
if (sourceRespVO.getVideoUrl() != null) {
|
||||
try {
|
||||
URL url = new URL(sourceRespVO.getVideoUrl());
|
||||
if (StringUtils.startsWith(url.getHost(), "100.64.")) {
|
||||
// 内网地址,需要代理
|
||||
sourceRespVO.setVideoUrl("https://zhentuai.com/proxy?url=" + sourceRespVO.getVideoUrl());
|
||||
} else {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
}
|
||||
});
|
||||
PageInfo<SourceRespVO> pageInfo = new PageInfo<>(list);
|
||||
return ApiResponse.success(pageInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<List<SourceRespVO>> list(SourceReqQuery sourceReqQuery) {
|
||||
return ApiResponse.success(sourceMapper.list(sourceReqQuery));
|
||||
List<SourceRespVO> list = sourceMapper.list(sourceReqQuery);
|
||||
list.forEach(sourceRespVO -> {
|
||||
if (sourceRespVO.getVideoUrl() != null) {
|
||||
try {
|
||||
URL url = new URL(sourceRespVO.getVideoUrl());
|
||||
if (StringUtils.startsWith(url.getHost(), "100.64.")) {
|
||||
// 内网地址,需要代理
|
||||
sourceRespVO.setVideoUrl("https://zhentuai.com/proxy?url=" + sourceRespVO.getVideoUrl());
|
||||
} else {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
}
|
||||
});
|
||||
return ApiResponse.success(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResponse<SourceRespVO> getById(Long id, Long userId) {
|
||||
return ApiResponse.success(sourceMapper.userGetById(id, userId));
|
||||
SourceRespVO sourceRespVO = sourceMapper.userGetById(id, userId);
|
||||
if (sourceRespVO.getVideoUrl() != null) {
|
||||
try {
|
||||
URL url = new URL(sourceRespVO.getVideoUrl());
|
||||
if (StringUtils.startsWith(url.getHost(), "100.64.")) {
|
||||
// 内网地址,需要代理
|
||||
sourceRespVO.setVideoUrl("https://zhentuai.com/proxy?url=" + sourceRespVO.getVideoUrl());
|
||||
} else {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
sourceRespVO.setVideoUrl(sourceRespVO.getVideoUrl());
|
||||
}
|
||||
}
|
||||
return ApiResponse.success(sourceRespVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,8 +10,6 @@ public interface TaskFaceService {
|
||||
|
||||
SearchFaceRespVo searchFace(IFaceBodyAdapter adapter, String dbName, String faceUrl, String reason);
|
||||
|
||||
String uploadFile(MultipartFile file, Long userId);
|
||||
|
||||
boolean deleteFaceSample(Long scenicId, String dbName, String entityId);
|
||||
|
||||
boolean assureFaceDb(IFaceBodyAdapter faceBodyAdapter, String dbName);
|
||||
|
@ -3,8 +3,6 @@ package com.ycwl.basic.service.task.impl;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesRequest;
|
||||
import com.aliyuncs.facebody.model.v20191230.ListFaceEntitiesResponse;
|
||||
import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.constant.FaceConstant;
|
||||
@ -17,7 +15,6 @@ import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
|
||||
import com.ycwl.basic.mapper.FaceDetectLogMapper;
|
||||
import com.ycwl.basic.mapper.FaceMapper;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.ScenicMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
@ -27,7 +24,6 @@ import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
|
||||
import com.ycwl.basic.model.pc.faceDetectLog.resp.MatchLocalRecord;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
@ -42,8 +38,6 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.task.VideoPieceGetter;
|
||||
import com.ycwl.basic.utils.DateUtils;
|
||||
import com.ycwl.basic.utils.ratelimiter.FixedRateLimiter;
|
||||
import com.ycwl.basic.utils.ratelimiter.IRateLimiter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -55,18 +49,13 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||
@ -239,30 +228,27 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
List<FaceSampleEntity> allFaceSampleList = new ArrayList<>();
|
||||
if (StringUtils.isNumeric(dbName)) { // 景区
|
||||
allFaceSampleList = faceSampleMapper.listByIds(allFaceSampleIds);
|
||||
Long firstFaceSampleId = acceptFaceSampleIds.get(0);
|
||||
Optional<FaceSampleEntity> firstFaceSample = allFaceSampleList.stream().filter(faceSample -> faceSample.getId().equals(firstFaceSampleId)).findAny();
|
||||
if (firstFaceSample.isPresent()) {
|
||||
if (tourMinutes > 0) {
|
||||
List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptFaceSampleIds);
|
||||
Date startDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), -tourMinutes/2);
|
||||
Date endDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), tourMinutes/2);
|
||||
acceptFaceSampleIds = acceptFaceSampleList.stream()
|
||||
.filter(faceSample -> faceSample.getCreateAt().after(startDate) && faceSample.getCreateAt().before(endDate))
|
||||
.map(FaceSampleEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
log.info("时间范围逻辑:最高匹配:{},时间范围需要在:{}~{}间", firstFaceSample, startDate, endDate);
|
||||
if (!acceptFaceSampleIds.isEmpty()) {
|
||||
Long firstFaceSampleId = acceptFaceSampleIds.get(0);
|
||||
Optional<FaceSampleEntity> firstFaceSample = allFaceSampleList.stream().filter(faceSample -> faceSample.getId().equals(firstFaceSampleId)).findAny();
|
||||
if (firstFaceSample.isPresent()) {
|
||||
if (tourMinutes > 0) {
|
||||
List<FaceSampleEntity> acceptFaceSampleList = faceSampleMapper.listByIds(acceptFaceSampleIds);
|
||||
Date startDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), -tourMinutes/2);
|
||||
Date endDate = DateUtil.offsetMinute(firstFaceSample.get().getCreateAt(), tourMinutes/2);
|
||||
acceptFaceSampleIds = acceptFaceSampleList.stream()
|
||||
.filter(faceSample -> faceSample.getCreateAt().after(startDate) && faceSample.getCreateAt().before(endDate))
|
||||
.map(FaceSampleEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
log.info("时间范围逻辑:最高匹配:{},时间范围需要在:{}~{}间", firstFaceSample, startDate, endDate);
|
||||
} else {
|
||||
log.info("时间范围逻辑:景区未限制");
|
||||
}
|
||||
} else {
|
||||
log.info("时间范围逻辑:景区未限制");
|
||||
log.info("时间范围逻辑:最高匹配ID:{},未找到", firstFaceSampleId);
|
||||
}
|
||||
} else {
|
||||
log.info("时间范围逻辑:最高匹配ID:{},未找到", firstFaceSampleId);
|
||||
}
|
||||
}
|
||||
if (acceptFaceSampleIds.isEmpty()) {
|
||||
respVo.setFirstMatchRate(0f);
|
||||
respVo.setSampleListIds(Collections.emptyList());
|
||||
return respVo;
|
||||
}
|
||||
List<MatchLocalRecord> collect = new ArrayList<>();
|
||||
for (SearchFaceResultItem item : records) {
|
||||
MatchLocalRecord record = new MatchLocalRecord();
|
||||
@ -286,6 +272,11 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
record.setMatched(item.getScore() > _threshold);
|
||||
collect.add(record);
|
||||
}
|
||||
if (acceptFaceSampleIds.isEmpty()) {
|
||||
respVo.setFirstMatchRate(0f);
|
||||
respVo.setSampleListIds(Collections.emptyList());
|
||||
return respVo;
|
||||
}
|
||||
logEntity.setMatchLocalRecord(JSONObject.toJSONString(collect));
|
||||
respVo.setFirstMatchRate(response.getFirstMatchRate());
|
||||
respVo.setSampleListIds(acceptFaceSampleIds);
|
||||
@ -298,30 +289,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(MultipartFile file, Long userId) {
|
||||
if (file.isEmpty()) {
|
||||
throw new RuntimeException("文件不存在!");
|
||||
}
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
//获取文件名后缀
|
||||
String suffix = originalFilename.split("\\.")[1];
|
||||
if ("Jpeg".equals(suffix)) {
|
||||
suffix = "jpg";
|
||||
}
|
||||
//文件储存路径
|
||||
String filePath = StorageUtil.joinPath("user-faces", DateUtils.format(new Date(),"yyyy-MM-dd"));
|
||||
// 生成文件名
|
||||
String fileName= userId + "." + suffix;
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
try {
|
||||
return adapter.uploadFile(file.getInputStream(), filePath, fileName);
|
||||
} catch (IOException e) {
|
||||
log.error("文件上传失败!", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteFaceSample(Long scenicId, String dbName, String entityId) {
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
|
||||
@ -368,22 +335,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
|
||||
return redisTemplate.delete(FaceConstant.FACE_DB_NAME_PFX + "*");
|
||||
}
|
||||
|
||||
|
||||
private static final String DATE_FORMAT="yyyyMMddHHmmss";
|
||||
|
||||
public static String generateEntityId(FaceSampleEntity entity) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
|
||||
Random random = new Random();
|
||||
int randomNumber = random.nextInt(900) + 100;
|
||||
return entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt()) + randomNumber;
|
||||
}
|
||||
public static String generateEntityId(FaceSampleRespVO entity) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
|
||||
Random random = new Random();
|
||||
int randomNumber = random.nextInt(900) + 100;
|
||||
return entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt()) + randomNumber;
|
||||
}
|
||||
|
||||
public String getFaceUrl(Long faceId) {
|
||||
if (faceId == null) {
|
||||
return null;
|
||||
|
@ -58,6 +58,7 @@ import com.ycwl.basic.storage.utils.StorageUtil;
|
||||
import com.ycwl.basic.task.VideoPieceGetter;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.VideoReUploader;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -117,8 +118,6 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
@Autowired
|
||||
private VideoRepository videoRepository;
|
||||
@Autowired
|
||||
private OrderRepository orderRepository;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
@ -126,7 +125,8 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
private TaskStatusBiz taskStatusBiz;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 1024, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1024));
|
||||
@Autowired
|
||||
private VideoReUploader videoReUploader;
|
||||
|
||||
|
||||
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
|
||||
@ -191,7 +191,7 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
try {
|
||||
List<TaskRespVO> taskList;
|
||||
if (worker.getScenicOnly() != null) {
|
||||
taskList = taskMapper.selectNotRunningByScenicId(worker.getScenicOnly());
|
||||
taskList = taskMapper.selectNotRunningByScenicList(worker.getScenicOnly());
|
||||
} else {
|
||||
taskList = taskMapper.selectNotRunning();
|
||||
}
|
||||
@ -590,9 +590,10 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
videoMapper.add(video);
|
||||
}
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(task.getScenicId());
|
||||
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(task.getScenicId());
|
||||
IStorageAdapter adapter = scenicService.getScenicTmpStorageAdapter(task.getScenicId());
|
||||
String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getId() + "_" + task.getScenicId() + ".mp4");
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, filename);
|
||||
videoReUploader.addVideoTask(task.getVideoUrl(), video.getId());
|
||||
int isBuy = 0;
|
||||
FaceEntity face = faceRepository.getFace(task.getFaceId());
|
||||
if (face != null) {
|
||||
@ -619,9 +620,9 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
}
|
||||
}
|
||||
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId(), isBuy);
|
||||
executor.execute(() -> {
|
||||
new Thread(() -> {
|
||||
sendVideoGeneratedServiceNotification(taskId);
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -649,7 +650,7 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
if (task == null) {
|
||||
return null;
|
||||
}
|
||||
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(task.getScenicId());
|
||||
IStorageAdapter adapter = scenicService.getScenicTmpStorageAdapter(task.getScenicId());
|
||||
String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getId() + "_" + task.getScenicId() + ".mp4");
|
||||
if (StringUtils.isBlank(task.getVideoUrl())) {
|
||||
// 生成
|
||||
|
7
src/main/java/com/ycwl/basic/stats/biz/StatsBiz.java
Normal file
7
src/main/java/com/ycwl/basic/stats/biz/StatsBiz.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.stats.biz;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class StatsBiz {
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.ycwl.basic.stats.controller;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.stats.dto.AddTraceReq;
|
||||
import com.ycwl.basic.stats.service.StatsService;
|
||||
import com.ycwl.basic.stats.util.StatsUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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 javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/trace/v1")
|
||||
public class TraceController {
|
||||
@Autowired
|
||||
private StatsService statsService;
|
||||
@IgnoreToken
|
||||
@PostMapping("/start")
|
||||
public void startTrace(HttpServletRequest request, HttpServletResponse response) {
|
||||
String traceId = request.getHeader("traceId");
|
||||
if (traceId == null || traceId.isEmpty()) {
|
||||
traceId = StatsUtil.createUuid();
|
||||
response.setHeader("Set-TraceId", traceId);
|
||||
}
|
||||
statsService.addStats(traceId, null);
|
||||
}
|
||||
|
||||
@IgnoreToken
|
||||
@PostMapping("/add")
|
||||
public void addTrace(HttpServletRequest request, HttpServletResponse response, @RequestBody AddTraceReq req) {
|
||||
String traceId = request.getHeader("traceId");
|
||||
if (traceId == null || traceId.isEmpty()) {
|
||||
traceId = StatsUtil.createUuid();
|
||||
response.setHeader("Set-TraceId", traceId);
|
||||
}
|
||||
statsService.addRecord(traceId, req.getAction(), req.getIdentifier(), req.getParams());
|
||||
}
|
||||
}
|
10
src/main/java/com/ycwl/basic/stats/dto/AddTraceReq.java
Normal file
10
src/main/java/com/ycwl/basic/stats/dto/AddTraceReq.java
Normal file
@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.stats.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AddTraceReq {
|
||||
private String action;
|
||||
private String identifier;
|
||||
private String params;
|
||||
}
|
18
src/main/java/com/ycwl/basic/stats/entity/StatsEntity.java
Normal file
18
src/main/java/com/ycwl/basic/stats/entity/StatsEntity.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.ycwl.basic.stats.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("t_stats")
|
||||
public class StatsEntity {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String traceId;
|
||||
private Long memberId;
|
||||
private Date createTime;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.ycwl.basic.stats.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("t_stats_record")
|
||||
public class StatsRecordEntity {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String traceId;
|
||||
private String action;
|
||||
private String identifier;
|
||||
private String params;
|
||||
private Date createTime;
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.ycwl.basic.stats.interceptor;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreLogReq;
|
||||
import com.ycwl.basic.constant.BaseContextHandler;
|
||||
import com.ycwl.basic.stats.service.StatsService;
|
||||
import com.ycwl.basic.stats.util.StatsUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Component
|
||||
public class StatsInterceptor implements HandlerInterceptor {
|
||||
@Autowired
|
||||
private StatsService statsService;
|
||||
|
||||
// 在请求处理前执行
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
if (!(handler instanceof HandlerMethod)) {
|
||||
return true;
|
||||
}
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
request.setAttribute("startTime", System.currentTimeMillis());
|
||||
String requestURI = request.getRequestURI();
|
||||
String method = request.getMethod();
|
||||
String traceId = request.getHeader("traceId");
|
||||
if (StringUtils.isEmpty(traceId)) {
|
||||
return true;
|
||||
// traceId = StatsUtil.createUuid();
|
||||
// response.setHeader("Set-TraceId", traceId);
|
||||
// statsService.addStats(traceId, null);
|
||||
}
|
||||
if (handlerMethod.getMethodAnnotation(IgnoreLogReq.class) == null) {
|
||||
statsService.addRecord(traceId, "REQUEST",method + " " + requestURI, null);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(BaseContextHandler.getUserId())) {
|
||||
statsService.updateStats(traceId, Long.valueOf(BaseContextHandler.getUserId()));
|
||||
}
|
||||
// 返回 true 继续后续流程,false 终止请求
|
||||
return true;
|
||||
}
|
||||
|
||||
// 控制器方法执行后,渲染视图前
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||
}
|
||||
|
||||
// 请求完全完成后执行(无论是否异常)
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
// long startTime = (Long) request.getAttribute("startTime");
|
||||
// long endTime = System.currentTimeMillis();
|
||||
// System.out.println("【AfterCompletion】请求结束,耗时:" + (endTime - startTime) + "ms");
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.stats.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ycwl.basic.stats.entity.StatsEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface StatsMapper extends BaseMapper<StatsEntity> {
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.stats.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ycwl.basic.stats.entity.StatsRecordEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface StatsRecordMapper extends BaseMapper<StatsRecordEntity> {
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.stats.service;
|
||||
|
||||
public interface StatsService {
|
||||
void addStats(String traceId, Long memberId);
|
||||
|
||||
void updateStats(String traceId, Long memberId);
|
||||
|
||||
void addRecord(String traceId, String action, String identifier, String params);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.ycwl.basic.stats.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ycwl.basic.stats.entity.StatsEntity;
|
||||
import com.ycwl.basic.stats.entity.StatsRecordEntity;
|
||||
import com.ycwl.basic.stats.mapper.StatsMapper;
|
||||
import com.ycwl.basic.stats.mapper.StatsRecordMapper;
|
||||
import com.ycwl.basic.stats.service.StatsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class StatsServiceImpl implements StatsService {
|
||||
@Autowired
|
||||
private StatsMapper statsMapper;
|
||||
|
||||
@Autowired
|
||||
private StatsRecordMapper statsRecordMapper;
|
||||
|
||||
@Override
|
||||
public void addStats(String traceId, Long memberId) {
|
||||
StatsEntity entity = new StatsEntity();
|
||||
entity.setTraceId(traceId);
|
||||
entity.setMemberId(memberId);
|
||||
entity.setCreateTime(new Date());
|
||||
statsMapper.insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStats(String traceId, Long memberId) {
|
||||
StatsEntity entity = new StatsEntity();
|
||||
entity.setMemberId(memberId);
|
||||
LambdaQueryWrapper<StatsEntity> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(StatsEntity::getTraceId, traceId);
|
||||
statsMapper.update(entity, queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRecord(String traceId, String action, String identifier, String params) {
|
||||
StatsRecordEntity entity = new StatsRecordEntity();
|
||||
entity.setTraceId(traceId);
|
||||
entity.setAction(action);
|
||||
entity.setIdentifier(identifier);
|
||||
entity.setParams(params);
|
||||
entity.setCreateTime(new Date());
|
||||
statsRecordMapper.insert(entity);
|
||||
}
|
||||
}
|
9
src/main/java/com/ycwl/basic/stats/util/StatsUtil.java
Normal file
9
src/main/java/com/ycwl/basic/stats/util/StatsUtil.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.stats.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class StatsUtil {
|
||||
public static String createUuid() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.ycwl.basic.storage.adapters;
|
||||
|
||||
import com.ycwl.basic.storage.exceptions.UploadFileFailedException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
@ -9,16 +10,17 @@ import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AStorageAdapter implements IStorageAdapter {
|
||||
|
||||
@Override
|
||||
public String uploadFile(File file, String ...path) {
|
||||
public String uploadFile(String contentType, File file, String ...path) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
return uploadFile(inputStream, path);
|
||||
return uploadFile(contentType, inputStream, path);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new UploadFileFailedException("文件不存在");
|
||||
}
|
||||
@ -31,8 +33,9 @@ public abstract class AStorageAdapter implements IStorageAdapter {
|
||||
}
|
||||
try {
|
||||
InputStream inputStream = file.getInputStream();
|
||||
return uploadFile(inputStream, path);
|
||||
return uploadFile(file.getContentType(), inputStream, path);
|
||||
} catch (Exception e) {
|
||||
log.warn("文件上传失败", e);
|
||||
throw new UploadFileFailedException("文件上传失败");
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(InputStream inputStream, String ...path) {
|
||||
public String uploadFile(String contentType, InputStream inputStream, String ...path) {
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
@ -71,6 +71,9 @@ final public class AliOssAdapter extends AStorageAdapter {
|
||||
OSS ossClient = wrapper.getOSSClient();
|
||||
ObjectMetadata metadata = new ObjectMetadata();
|
||||
metadata.setContentLength(inputStream.available());
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
metadata.setContentType(contentType);
|
||||
}
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream);
|
||||
ossClient.putObject(putObjectRequest);
|
||||
return getUrl(path);
|
||||
|
@ -55,7 +55,7 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(InputStream inputStream, String... path) {
|
||||
public String uploadFile(String contentType, InputStream inputStream, String... path) {
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
@ -64,6 +64,9 @@ public class AwsOssAdapter extends AStorageAdapter {
|
||||
AmazonS3Client s3Client = wrapper.getS3Client();
|
||||
ObjectMetadata metadata = new ObjectMetadata();
|
||||
metadata.setContentLength(inputStream.available());
|
||||
if (StringUtils.isNotBlank(contentType)) {
|
||||
metadata.setContentType(contentType);
|
||||
}
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), fullPath, inputStream, metadata);
|
||||
putObjectRequest.withCannedAcl(CannedAccessControlList.PublicRead); // 设置访问权限,让所有用户都允许访问
|
||||
s3Client.putObject(putObjectRequest);
|
||||
|
@ -14,8 +14,8 @@ import java.util.Map;
|
||||
public interface IStorageAdapter {
|
||||
void loadConfig(Map<String, String> config);
|
||||
void setConfig(StorageConfig config);
|
||||
String uploadFile(InputStream inputStream, String ...path);
|
||||
String uploadFile(File file, String ...path);
|
||||
String uploadFile(String contentType, InputStream inputStream, String ...path);
|
||||
String uploadFile(String contentType, File file, String ...path);
|
||||
String uploadFile(MultipartFile file, String ...path);
|
||||
boolean deleteFile(String ...path);
|
||||
String getUrl(String ...path);
|
||||
|
@ -22,7 +22,7 @@ public class LocalStorageAdapter extends AStorageAdapter{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(InputStream inputStream, String... path) {
|
||||
public String uploadFile(String contentType, InputStream inputStream, String... path) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,15 @@ package com.ycwl.basic.storage.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class StorageFileObject {
|
||||
private String path;
|
||||
private String name;
|
||||
private Long size;
|
||||
private Object rawObject;
|
||||
private Date modifyTime;
|
||||
|
||||
public String getFullPath() {
|
||||
return path + "/" + name;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.ycwl.basic.task;
|
||||
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
|
||||
@ -37,7 +38,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
|
||||
import static com.ycwl.basic.service.task.impl.TaskFaceServiceImpl.generateEntityId;
|
||||
|
||||
@Component
|
||||
@EnableScheduling
|
||||
@ -79,7 +79,7 @@ public class FaceCleaner {
|
||||
return;
|
||||
}
|
||||
faceSampleList.forEach(faceSample -> {
|
||||
boolean success = adapter.deleteFace(String.valueOf(scenic.getId()), generateEntityId(faceSample));
|
||||
boolean success = adapter.deleteFace(String.valueOf(scenic.getId()), faceSample.getId().toString());
|
||||
if (success) {
|
||||
log.info("当前景区{},人脸样本ID{},删除成功", scenic.getId(), faceSample.getId());
|
||||
faceSampleMapper.deleteById(faceSample.getId());
|
||||
@ -140,7 +140,7 @@ public class FaceCleaner {
|
||||
});
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 3 * * ?")
|
||||
@Scheduled(cron = "0 15 3 * * ?")
|
||||
public void deleteNotBuyVideos(){
|
||||
ScenicReqQuery scenicQuery = new ScenicReqQuery();
|
||||
List<ScenicRespVO> scenicList = scenicMapper.list(scenicQuery);
|
||||
@ -212,6 +212,12 @@ public class FaceCleaner {
|
||||
IStorageAdapter adapter = StorageFactory.use("faces");
|
||||
List<StorageFileObject> fileObjectList = adapter.listDir("user-face");
|
||||
fileObjectList.parallelStream().forEach(fileObject -> {
|
||||
if (fileObject.getModifyTime() != null) {
|
||||
// 如果是一天以内修改的,则跳过
|
||||
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) < 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(faceSampleRespVOS.parallelStream().noneMatch(faceSampleRespVO -> faceSampleRespVO.getFaceUrl().contains(fileObject.getFullPath()))){
|
||||
log.info("删除人脸文件:{}", fileObject);
|
||||
adapter.deleteFile(fileObject.getFullPath());
|
||||
@ -226,6 +232,12 @@ public class FaceCleaner {
|
||||
log.info("开始清理视频文件");
|
||||
List<StorageFileObject> fileObjectList = adapter.listDir(StorageConstant.VIDEO_PIECE_PATH);
|
||||
fileObjectList.parallelStream().forEach(fileObject -> {
|
||||
if (fileObject.getModifyTime() != null) {
|
||||
// 如果是一天以内修改的,则跳过
|
||||
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (list.parallelStream().filter(videoRespVO -> Objects.nonNull(videoRespVO.getVideoUrl())).noneMatch(videoRespVO -> videoRespVO.getVideoUrl().contains(fileObject.getFullPath()))){
|
||||
log.info("删除文件:{}", fileObject);
|
||||
adapter.deleteFile(fileObject.getFullPath());
|
||||
@ -236,6 +248,12 @@ public class FaceCleaner {
|
||||
log.info("开始清理图片文件");
|
||||
fileObjectList = adapter.listDir(StorageConstant.PHOTO_PATH);
|
||||
fileObjectList.parallelStream().forEach(fileObject -> {
|
||||
if (fileObject.getModifyTime() != null) {
|
||||
// 如果是一天以内修改的,则跳过
|
||||
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (list.parallelStream().filter(videoRespVO -> Objects.nonNull(videoRespVO.getUrl())).noneMatch(videoRespVO -> videoRespVO.getUrl().contains(fileObject.getFullPath()))){
|
||||
log.info("删除文件:{}", fileObject);
|
||||
adapter.deleteFile(fileObject.getFullPath());
|
||||
@ -253,6 +271,12 @@ public class FaceCleaner {
|
||||
log.info("开始清理视频文件");
|
||||
List<StorageFileObject> fileObjectList = adapter.listDir(StorageConstant.VLOG_PATH);
|
||||
fileObjectList.parallelStream().forEach(fileObject -> {
|
||||
if (fileObject.getModifyTime() != null) {
|
||||
// 如果是一天以内修改的,则跳过
|
||||
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (list.parallelStream().filter(videoRespVO -> Objects.nonNull(videoRespVO.getVideoUrl())).noneMatch(videoRespVO -> videoRespVO.getVideoUrl().contains(fileObject.getFullPath()))){
|
||||
log.info("删除文件:{}", fileObject);
|
||||
adapter.deleteFile(fileObject.getFullPath());
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.ycwl.basic.task;
|
||||
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import com.ycwl.basic.biz.OrderBiz;
|
||||
import com.ycwl.basic.biz.TaskStatusBiz;
|
||||
import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.device.DeviceFactory;
|
||||
import com.ycwl.basic.device.entity.common.FileObject;
|
||||
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.mapper.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
@ -19,9 +20,9 @@ import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import com.ycwl.basic.utils.VideoReUploader;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@ -41,6 +42,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -63,6 +65,8 @@ public class VideoPieceGetter {
|
||||
private TemplateRepository templateRepository;
|
||||
@Autowired
|
||||
private TaskStatusBiz taskStatusBiz;
|
||||
@Autowired
|
||||
private VideoReUploader videoReUploader;
|
||||
|
||||
@Data
|
||||
public static class Task {
|
||||
@ -118,7 +122,13 @@ public class VideoPieceGetter {
|
||||
// taskStatusBiz.setFaceCutStatus(task.faceId, 0);
|
||||
// }
|
||||
AtomicBoolean invoke = new AtomicBoolean(false);
|
||||
final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 512, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(512));
|
||||
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNamePrefix("VPG-" + task.faceId + "-t")
|
||||
.build();
|
||||
final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 512, 0L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(512),
|
||||
threadFactory
|
||||
);
|
||||
List<String> currentPlaceholder = new ArrayList<>();
|
||||
List<FaceSampleEntity> list = faceSampleMapper.listByIds(task.getFaceSampleIds());
|
||||
Map<Long, Long> pairDeviceMap = new ConcurrentHashMap<>();
|
||||
@ -277,7 +287,7 @@ public class VideoPieceGetter {
|
||||
}
|
||||
log.info("视频裁切成功");
|
||||
IStorageAdapter adapter = StorageFactory.use("assets");
|
||||
url = adapter.uploadFile(outFile, "video-source", outFile.getName());
|
||||
url = adapter.uploadFile("video/mp4", outFile, StorageConstant.VIDEO_PIECE_PATH, outFile.getName());
|
||||
// 上传成功后删除文件
|
||||
outFile.delete();
|
||||
}
|
||||
@ -312,6 +322,7 @@ public class VideoPieceGetter {
|
||||
sourceMapper.addRelation(videoSource);
|
||||
}
|
||||
sourceMapper.add(sourceEntity);
|
||||
videoReUploader.addTask(sourceEntity.getVideoUrl(), sourceEntity.getId());
|
||||
} else {
|
||||
// 有原视频
|
||||
if (task.memberId != null && task.faceId != null) {
|
||||
|
@ -15,6 +15,7 @@ import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
|
||||
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.repository.TemplateRepository;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.service.task.TaskFaceService;
|
||||
import com.ycwl.basic.service.task.impl.TaskTaskServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -47,8 +48,8 @@ public class VideoTaskGenerator {
|
||||
private ScenicMapper scenicMapper;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
// TODO: 可配置,现在赶时间暂时写死
|
||||
@Autowired
|
||||
private FaceService faceService;
|
||||
|
||||
@Scheduled(cron = "0 0 * * * *")
|
||||
public void generateVideoTask() {
|
||||
@ -84,7 +85,7 @@ public class VideoTaskGenerator {
|
||||
query.setEndTime(DateUtil.endOfDay(new Date()));
|
||||
List<FaceRespVO> list = faceMapper.list(query);
|
||||
list.stream().parallel().forEach(face -> {
|
||||
taskFaceService.searchFace(face.getId());
|
||||
faceService.matchFaceId(face.getId(), false);
|
||||
if (Integer.valueOf(3).equals(scenicConfig.getBookRoutine())) {
|
||||
// 全部生成
|
||||
contentList.forEach(content -> {
|
||||
|
@ -1,202 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @date 2022年06月02日 13:40
|
||||
* 自定义的BigDecimal计算工具类
|
||||
*/
|
||||
public class CustomBigDecimalUtils {
|
||||
|
||||
public static final BigDecimal HUNDRED_BIG_DECIMAL = new BigDecimal("100");
|
||||
|
||||
/**
|
||||
* 除法
|
||||
*
|
||||
* @param divisor 除数
|
||||
* @param dividend 被除数
|
||||
* @param scale 保留的小数位数
|
||||
* @param roundingMode 舍入模式:比如四舍五入
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:43
|
||||
*/
|
||||
public static BigDecimal divide(BigDecimal divisor,
|
||||
BigDecimal dividend,
|
||||
int scale,
|
||||
RoundingMode roundingMode) {
|
||||
if (divisor == null || dividend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
if (Double.compare(divisor.doubleValue(), BigDecimal.ZERO.doubleValue()) == 0 ||
|
||||
Double.compare(dividend.doubleValue(), BigDecimal.ZERO.doubleValue()) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return divisor.divide(dividend, scale, roundingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除法
|
||||
*
|
||||
* @param divisor 除数
|
||||
* @param dividend 被除数
|
||||
* @param scale 保留的小数位数
|
||||
* @param roundingMode 舍入模式:比如四舍五入
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:43
|
||||
*/
|
||||
public static BigDecimal divide(Integer divisor,
|
||||
Integer dividend,
|
||||
int scale,
|
||||
RoundingMode roundingMode) {
|
||||
if (divisor == null || dividend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
if (divisor == 0 || dividend == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return new BigDecimal(divisor).divide(new BigDecimal(dividend), scale, roundingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除法
|
||||
*
|
||||
* @param divisor 除数
|
||||
* @param dividend 被除数
|
||||
* @param scale 保留的小数位数
|
||||
* @param roundingMode 舍入模式:比如四舍五入
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:43
|
||||
*/
|
||||
public static BigDecimal divide(Double divisor,
|
||||
Double dividend,
|
||||
int scale,
|
||||
RoundingMode roundingMode) {
|
||||
if (divisor == null || dividend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
if (Double.compare(divisor, BigDecimal.ZERO.doubleValue()) == 0 ||
|
||||
Double.compare(dividend, BigDecimal.ZERO.doubleValue()) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return new BigDecimal(String.valueOf(divisor)).divide(new BigDecimal(String.valueOf(dividend)),
|
||||
scale, roundingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除法
|
||||
*
|
||||
* @param divisor 除数
|
||||
* @param dividend 被除数
|
||||
* @param scale 保留的小数位数
|
||||
* @param roundingMode 舍入模式:比如四舍五入
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:43
|
||||
*/
|
||||
public static BigDecimal divide(Double divisor,
|
||||
Integer dividend,
|
||||
int scale,
|
||||
RoundingMode roundingMode) {
|
||||
if (divisor == null || dividend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
if (Double.compare(divisor, BigDecimal.ZERO.doubleValue()) == 0 ||
|
||||
Double.compare(dividend, BigDecimal.ZERO.doubleValue()) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return new BigDecimal(String.valueOf(divisor)).divide(new BigDecimal(String.valueOf(dividend)),
|
||||
scale, roundingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减法
|
||||
*
|
||||
* @param subtraction 减数
|
||||
* @param minuend 被减数
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:53
|
||||
*/
|
||||
public static BigDecimal subtract(BigDecimal subtraction,
|
||||
BigDecimal minuend) {
|
||||
if (subtraction == null || minuend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
return subtraction.subtract(minuend);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减法
|
||||
*
|
||||
* @param subtraction 减数
|
||||
* @param minuend 被减数
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:53
|
||||
*/
|
||||
public static BigDecimal subtract(Double subtraction,
|
||||
Double minuend) {
|
||||
if (subtraction == null || minuend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
return new BigDecimal(String.valueOf(subtraction)).subtract(new BigDecimal(String.valueOf(minuend)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 减法
|
||||
*
|
||||
* @param subtraction 减数
|
||||
* @param minuend 被减数
|
||||
* @return java.math.BigDecimal
|
||||
* @date 2022/6/2 13:53
|
||||
*/
|
||||
public static BigDecimal subtract(BigDecimal subtraction,
|
||||
Double minuend) {
|
||||
if (subtraction == null || minuend == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
return subtraction.subtract(new BigDecimal(minuend));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加法
|
||||
* @date 2022/6/7 17:31
|
||||
* @param addend 加数
|
||||
* @param summand 被加数
|
||||
* @return java.lang.Double
|
||||
*/
|
||||
public static Double add(Double addend,
|
||||
Double summand) {
|
||||
if (addend == null || summand == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
return new BigDecimal(addend.toString()).add(new BigDecimal(summand.toString())).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加法
|
||||
* @date 2022/6/7 17:31
|
||||
* @param addend 加数
|
||||
* @param summand 被加数
|
||||
* @return java.lang.Double
|
||||
*/
|
||||
public static Double add(BigDecimal addend,
|
||||
BigDecimal summand) {
|
||||
if (addend == null || summand == null) {
|
||||
throw new NullPointerException("传入的数据不能为空");
|
||||
}
|
||||
|
||||
return addend.add(summand).doubleValue();
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import org.apache.http.StatusLine;
|
||||
|
||||
/**
|
||||
* Http服务工具类
|
||||
* @author songmingsong
|
||||
*/
|
||||
public class HttpServiceUtil {
|
||||
/**
|
||||
* 请求OK代码
|
||||
*/
|
||||
public static final int REQUEST_OK_CODE=200;
|
||||
/**
|
||||
* 无响应内容
|
||||
*/
|
||||
public static final String REQUEST_NO_RESULT="No_Result";
|
||||
|
||||
|
||||
/**
|
||||
* 是否响应成功
|
||||
* @param status 响应状态
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean success(StatusLine status) {
|
||||
return status.getStatusCode() == REQUEST_OK_CODE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -45,8 +45,7 @@ public class ImageUtils {
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
// TODO - implementation depends on your requirements
|
||||
return header.split(":")[0];
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,180 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @date 2022年07月14日 14:12
|
||||
* 数据格式转换工具类
|
||||
*/
|
||||
public class ObjectConvertUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ObjectConvertUtils.class);
|
||||
|
||||
/**
|
||||
* 浅克隆
|
||||
*
|
||||
* @param source 原对象
|
||||
* @param clazz 目标对象
|
||||
* @return T
|
||||
* @date 2022/4/6 13:45
|
||||
*/
|
||||
public static <T> T clone(Object source, Class<T> clazz) {
|
||||
return clone(source, clazz, true);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @date 2022/7/18 16:36
|
||||
* @param source 原对象
|
||||
* @param clazz 目标对象
|
||||
* @param whetherAssignNull 是否赋值空值:true是 false否
|
||||
* @return T
|
||||
*/
|
||||
public static <T> T clone(Object source, Class<T> clazz, Boolean whetherAssignNull) {
|
||||
T target;
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
target = clazz.newInstance();
|
||||
if (whetherAssignNull) {
|
||||
BeanUtils.copyProperties(source, target);
|
||||
} else {
|
||||
BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
|
||||
}
|
||||
return target;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("数据转换异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象与对象之间的数据转换
|
||||
*
|
||||
* @param source 转换的数据对象
|
||||
* @param target 需要转换数据的对象
|
||||
* @date 2022/7/14 17:24
|
||||
*/
|
||||
public static void clone(Object source, Object target) {
|
||||
clone(source, target, true);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @date 2022/7/18 16:39
|
||||
* @param source 转换的数据对象
|
||||
* @param target 需要转换数据的对象
|
||||
* @param whetherAssignNull 是否赋值空值:true是 false否
|
||||
*/
|
||||
public static void clone(Object source, Object target, Boolean whetherAssignNull) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (whetherAssignNull) {
|
||||
BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
|
||||
} else {
|
||||
BeanUtils.copyProperties(source, target);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("数据转换异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象与对象之间的数据转换
|
||||
*
|
||||
* @param source 转换的数据对象
|
||||
* @param target 需要转换数据的对象
|
||||
* @date 2022/7/15 9:11
|
||||
*/
|
||||
public static void cglibBeanCopierCloneObject(Object source, Object target) {
|
||||
BeanCopierUtils.copyProperties(source, target);
|
||||
}
|
||||
/**
|
||||
* 对象与对象之间的数据转换
|
||||
*
|
||||
* @param source 转换的数据对象
|
||||
* @param target 需要转换数据的对象
|
||||
* @date 2022/7/15 9:11
|
||||
*/
|
||||
public static <T> T cglibBeanCopierCloneObject(Object source, Class<T> target) {
|
||||
T t;
|
||||
try {
|
||||
t = target.newInstance();
|
||||
BeanCopierUtils.copyProperties(source, t);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list集合转换为传入的对象的数据集合
|
||||
*
|
||||
* @param sourceList 原数据集合
|
||||
* @param clazz 需要转换的集合数据对象
|
||||
* @return java.util.List<T>
|
||||
* @date 2022/4/6 13:49
|
||||
*/
|
||||
public static <T> List<T> cloneList(List<?> sourceList, Class<T> clazz) {
|
||||
return cloneList(sourceList, clazz, true);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @date 2022/7/18 16:41
|
||||
* @param sourceList 原数据集合
|
||||
* @param clazz 需要转换的集合数据对象
|
||||
* @param whetherAssignNull 是否赋值空值:true是 false否
|
||||
* @return java.util.List<T>
|
||||
*/
|
||||
public static <T> List<T> cloneList(List<?> sourceList, Class<T> clazz, Boolean whetherAssignNull) {
|
||||
try {
|
||||
List<T> targetList = new ArrayList<>(sourceList.size());
|
||||
for (Object source : sourceList) {
|
||||
if (whetherAssignNull) {
|
||||
targetList.add(clone(source, clazz));
|
||||
} else {
|
||||
targetList.add(clone(source, clazz, false));
|
||||
}
|
||||
}
|
||||
|
||||
return targetList;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("数据转换异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取需要忽略的属性
|
||||
*/
|
||||
public static String[] getNullPropertyNames(Object source) {
|
||||
final BeanWrapper src = new BeanWrapperImpl(source);
|
||||
PropertyDescriptor[] pds = src.getPropertyDescriptors();
|
||||
|
||||
Set<String> emptyNames = new HashSet<>();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
Object srcValue = src.getPropertyValue(pd.getName());
|
||||
// 此处判断可根据需求修改
|
||||
if (srcValue == null) {
|
||||
emptyNames.add(pd.getName());
|
||||
}
|
||||
}
|
||||
String[] result = new String[emptyNames.size()];
|
||||
return emptyNames.toArray(result);
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @date 2022年08月08日 16:06
|
||||
* redis缓存操作行为工具类
|
||||
*/
|
||||
@Component
|
||||
public class RedisCacheOperationUtils {
|
||||
|
||||
/**
|
||||
* string类型的redis操作类
|
||||
*/
|
||||
private static StringRedisTemplate stringRedisTemplate;
|
||||
/**
|
||||
* 通用的redis操作类
|
||||
*/
|
||||
private static RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 创建string类型的操作对象
|
||||
*/
|
||||
public static BoundValueOperations<String, String> createValueOperations(String cacheKey) {
|
||||
return stringRedisTemplate.boundValueOps(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 创建list类型的操作对象
|
||||
*/
|
||||
public static BoundListOperations<String, List<String>> createListOperations(String cacheKey) {
|
||||
return redisTemplate.boundListOps(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 创建hash类型的操作对象
|
||||
*/
|
||||
public static BoundHashOperations createHashOperations(String cacheKey) {
|
||||
return redisTemplate.boundHashOps(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 创建set类型的操作对象
|
||||
*/
|
||||
public static BoundSetOperations createSetOperations(String cacheKey) {
|
||||
return redisTemplate.boundSetOps(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 创建zset类型的操作对象
|
||||
*/
|
||||
public static BoundZSetOperations createZSetOperations(String cacheKey) {
|
||||
return redisTemplate.boundZSetOps(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 判断缓存key值是否存在
|
||||
*/
|
||||
public static Boolean hasKey(String cacheKey) {
|
||||
return redisTemplate.hasKey(cacheKey);
|
||||
}
|
||||
/**
|
||||
* 删除缓存的redis缓存key
|
||||
*/
|
||||
public static Boolean delete(String cacheKey) {
|
||||
return redisTemplate.delete(cacheKey);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
|
||||
RedisCacheOperationUtils.stringRedisTemplate = stringRedisTemplate;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setRedisTemplate(RedisTemplate redisTemplate) {
|
||||
RedisCacheOperationUtils.redisTemplate = redisTemplate;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* SSL工具类
|
||||
*
|
||||
* @author songmingsong
|
||||
*/
|
||||
@Slf4j
|
||||
public class SslUtil {
|
||||
/**
|
||||
* 获取HtttpClient对象
|
||||
*
|
||||
* @return CloseableHttpClient
|
||||
*/
|
||||
public static CloseableHttpClient sslHttpClientBuild() {
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry =
|
||||
RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE)
|
||||
.register("https", trustAllHttpsCertificates()).build();
|
||||
// 创建ConnectionManager,添加Connection配置信息
|
||||
PoolingHttpClientConnectionManager connectionManager =
|
||||
new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* 信任所有Http证书
|
||||
*
|
||||
* @return SSLConnectionSocketFactory
|
||||
*/
|
||||
private static SSLConnectionSocketFactory trustAllHttpsCertificates() {
|
||||
SSLConnectionSocketFactory socketFactory = null;
|
||||
TrustManager[] trustAllCerts = new TrustManager[1];
|
||||
TrustManager tm = new X509TrustManager() {
|
||||
|
||||
@Override
|
||||
// 返回受信任的X509证书数组。
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
// 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。
|
||||
// 在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
try {
|
||||
if (chain!=null&&chain.length>0) {
|
||||
chain[0].checkValidity();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("checkServerTrusted",e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// 该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,
|
||||
// 因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
try {
|
||||
if (chain!=null&&chain.length>0) {
|
||||
chain[0].checkValidity();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("checkClientTrusted",e);
|
||||
}
|
||||
}
|
||||
};
|
||||
trustAllCerts[0] = tm;
|
||||
SSLContext sc = null;
|
||||
try {
|
||||
sc = SSLContext.getInstance("TLSv1.2");
|
||||
sc.init(null, trustAllCerts, null);
|
||||
socketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);
|
||||
// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
||||
} catch (Exception e) {
|
||||
log.error("trustAllHttpsCertificates", e);
|
||||
}
|
||||
return socketFactory;
|
||||
}
|
||||
|
||||
}
|
149
src/main/java/com/ycwl/basic/utils/VideoReUploader.java
Normal file
149
src/main/java/com/ycwl/basic/utils/VideoReUploader.java
Normal file
@ -0,0 +1,149 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import cn.hutool.core.thread.ThreadFactoryBuilder;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.ycwl.basic.constant.StorageConstant;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.mapper.VideoMapper;
|
||||
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
|
||||
import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.repository.VideoRepository;
|
||||
import com.ycwl.basic.repository.VideoTaskRepository;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class VideoReUploader {
|
||||
private static final ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setNamePrefix("Vid-ReUp-")
|
||||
.build();
|
||||
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 1024, 0L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1024),
|
||||
threadFactory
|
||||
);
|
||||
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private ScenicService scenicService;
|
||||
@Autowired
|
||||
private VideoMapper videoMapper;
|
||||
@Autowired
|
||||
private VideoRepository videoRepository;
|
||||
@Autowired
|
||||
private ScenicRepository scenicRepository;
|
||||
|
||||
public void addTask(String url, Long sourceId) {
|
||||
SourceEntity entity = sourceMapper.getEntity(sourceId);
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (entity.getScenicId() == null) {
|
||||
return;
|
||||
}
|
||||
if (entity.getType() != 1) {
|
||||
return;
|
||||
}
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(entity.getScenicId());
|
||||
if (scenicConfig == null || scenicConfig.getLocalStoreType() == null || scenicConfig.getLocalStoreConfigJson() == null) {
|
||||
return;
|
||||
}
|
||||
final String dstFilePath = StorageUtil.joinPath(StorageConstant.VIDEO_PIECE_PATH, entity.getId().toString() + ".mp4");
|
||||
final IStorageAdapter adapter = scenicService.getScenicStorageAdapter(entity.getScenicId());
|
||||
if (StringUtils.equals(url, adapter.getUrl(dstFilePath))) {
|
||||
return;
|
||||
}
|
||||
String tmpFilePath = UUID.randomUUID().toString();
|
||||
executor.execute(() -> {
|
||||
// 先下载,后上传
|
||||
File dstFile = new File(tmpFilePath);
|
||||
log.info("下载视频:{};sourceId:{}", url, sourceId);
|
||||
long size = HttpUtil.downloadFile(url, dstFile);
|
||||
log.info("下载视频完成:{};大小:{};sourceId:{}", url, size, sourceId);
|
||||
try {
|
||||
log.info("开始上传:{};sourceId:{}", dstFilePath, sourceId);
|
||||
String newUrl = adapter.uploadFile("video/mp4", dstFile, dstFilePath);
|
||||
log.info("上传成功:{};sourceId:{}", newUrl, sourceId);
|
||||
SourceEntity updateEntity = new SourceEntity();
|
||||
updateEntity.setId(sourceId);
|
||||
updateEntity.setVideoUrl(newUrl);
|
||||
sourceMapper.update(updateEntity);
|
||||
} catch (Exception e) {
|
||||
log.info("上传失败:{};sourceId:{}", dstFilePath, sourceId, e);
|
||||
} finally {
|
||||
try {
|
||||
dstFile.delete();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
public void addVideoTask(String url, Long videoId) {
|
||||
VideoEntity entity = videoMapper.getEntity(videoId);
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (entity.getScenicId() == null) {
|
||||
return;
|
||||
}
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(entity.getScenicId());
|
||||
if (scenicConfig == null || scenicConfig.getTmpStoreType() == null || scenicConfig.getTmpStoreConfigJson() == null) {
|
||||
return;
|
||||
}
|
||||
final String dstFilePath = StorageUtil.joinPath(StorageConstant.VLOG_PATH, entity.getTaskId() + "_" + entity.getScenicId() + ".mp4");
|
||||
final IStorageAdapter adapter = scenicService.getScenicStorageAdapter(entity.getScenicId());
|
||||
if (StringUtils.equals(url, adapter.getUrl(dstFilePath))) {
|
||||
return;
|
||||
}
|
||||
String tmpFilePath = UUID.randomUUID().toString();
|
||||
executor.execute(() -> {
|
||||
// 先下载,后上传
|
||||
File dstFile = new File(tmpFilePath);
|
||||
log.info("下载视频:{};videoId:{}", url, videoId);
|
||||
long size = HttpUtil.downloadFile(url, dstFile);
|
||||
log.info("下载视频完成:{};大小:{};videoId:{}", url, size, videoId);
|
||||
try {
|
||||
log.info("开始上传:{};videoId:{}", dstFilePath, videoId);
|
||||
String newUrl = adapter.uploadFile("video/mp4", dstFile, dstFilePath);
|
||||
adapter.setAcl(StorageAcl.PUBLIC_READ, dstFilePath);
|
||||
log.info("上传成功:{};videoId:{}", newUrl, videoId);
|
||||
VideoEntity updateEntity = new VideoEntity();
|
||||
updateEntity.setId(videoId);
|
||||
updateEntity.setVideoUrl(newUrl);
|
||||
videoMapper.update(updateEntity);
|
||||
} catch (Exception e) {
|
||||
log.info("上传失败:{};videoId:{}", dstFilePath, videoId, e);
|
||||
} finally {
|
||||
videoRepository.clearVideoCache(videoId);
|
||||
try {
|
||||
dstFile.delete();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import com.wechat.pay.java.core.util.PemUtil;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.*;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @Author: songmingsong
|
||||
* @CreateTime: 2024-12-05
|
||||
* @Description: 微信支付
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class WXPayUtil {
|
||||
|
||||
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
|
||||
|
||||
public static String getSign(String signatureStr,String privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IOException, URISyntaxException {
|
||||
//replace 根据实际情况,不一定都需要
|
||||
String replace = privateKey.replace("\\n", "\n");
|
||||
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromString(replace);
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
sign.initSign(merchantPrivateKey);
|
||||
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64Utils.encodeToString(sign.sign());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机字符串 Nonce Str
|
||||
*
|
||||
* @return String 随机字符串
|
||||
*/
|
||||
public static String generateNonceStr() {
|
||||
char[] nonceChars = new char[32];
|
||||
for (int index = 0; index < nonceChars.length; ++index) {
|
||||
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
|
||||
}
|
||||
return new String(nonceChars);
|
||||
}
|
||||
|
||||
public static Map<String, Object> xmlToMap(String xmlData) {
|
||||
return XmlUtil.xmlToMap(xmlData);
|
||||
}
|
||||
}
|
@ -6,26 +6,34 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class WxMpUtil {
|
||||
private static final String GET_WXA_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%s";
|
||||
private static final String GET_URL_LICK_URL = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s";
|
||||
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
|
||||
private static String ACCESS_TOKEN = "";
|
||||
private static Date expireTime = new Date();
|
||||
private static final Map<String, String> tokens = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Date> expireTimes = new ConcurrentHashMap<>();
|
||||
|
||||
private static String getAccessToken(String appId, String appSecret) {
|
||||
if (ACCESS_TOKEN != null && !ACCESS_TOKEN.isEmpty()) {
|
||||
if (expireTime.getTime() > System.currentTimeMillis()) {
|
||||
return ACCESS_TOKEN;
|
||||
if (expireTimes.containsKey(appId)) {
|
||||
Date expireTime = expireTimes.get(appId);
|
||||
if (expireTime.getTime() < System.currentTimeMillis()) {
|
||||
tokens.remove(appId);
|
||||
}
|
||||
} else {
|
||||
tokens.remove(appId);
|
||||
}
|
||||
String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
ACCESS_TOKEN = jsonObject.getString("access_token");
|
||||
expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
|
||||
return ACCESS_TOKEN;
|
||||
return tokens.computeIfAbsent(appId, (k) -> {
|
||||
String url = String.format(ACCESS_TOKEN_URL, appId, appSecret);
|
||||
String response = HttpUtil.get(url);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
String token = jsonObject.getString("access_token");
|
||||
Date expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
|
||||
expireTimes.put(appId, expireTime);
|
||||
return token;
|
||||
});
|
||||
}
|
||||
|
||||
public static void generateWXAQRCode(String appId, String appSecret, String envVersion, String path, String filePath) throws Exception {
|
||||
|
@ -1,17 +0,0 @@
|
||||
package com.ycwl.basic.xss;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public class XssJacksonDeserializer extends JsonDeserializer<String> {
|
||||
@Override
|
||||
public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
return StringEscapeUtils.escapeHtml4(jp.getText());
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package com.ycwl.basic.xss;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import java.io.IOException;
|
||||
|
||||
public class XssJacksonSerializer extends JsonSerializer<String>{
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(StringEscapeUtils.escapeHtml4(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -49,60 +49,6 @@ mybatis-plus:
|
||||
# 指定使用的日志配置文件
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
# 微信小程序相关配置
|
||||
wx:
|
||||
# 公众号的appId
|
||||
appId: fix
|
||||
# 公众号的密钥
|
||||
appSecret: fix
|
||||
# 小程序的AppId
|
||||
miniProgramAppId: wxe7ff26af70bfc37c
|
||||
# 小程序的secret
|
||||
miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695
|
||||
# 申请openid授权
|
||||
grandType: authorization_code
|
||||
# 推送模板
|
||||
push:
|
||||
templateId: 5b8vTm7kvwYubqDxb3dxBqFIhc3Swt5l7QHSK5r-ZRI
|
||||
# 商户号
|
||||
mchId: 1700540331
|
||||
# 商户证书序列号
|
||||
mchSerialNo: 2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0
|
||||
# 支付回调接口地址
|
||||
payNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/payNotify
|
||||
# 退款回调接口地址
|
||||
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
|
||||
# 商户API私钥路径
|
||||
keyPath: "-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
|
||||
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
|
||||
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
|
||||
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
|
||||
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
|
||||
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
|
||||
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
|
||||
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
|
||||
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
|
||||
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
|
||||
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
|
||||
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
|
||||
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
|
||||
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
|
||||
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
|
||||
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
|
||||
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
|
||||
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
|
||||
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
|
||||
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
|
||||
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
|
||||
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
|
||||
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
|
||||
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
|
||||
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
|
||||
YfkdFNxtYLdVAwuylMoV3fKI
|
||||
-----END PRIVATE KEY-----"
|
||||
# 商户APIV3密钥
|
||||
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai
|
||||
|
||||
# 存储
|
||||
storage:
|
||||
@ -168,7 +114,45 @@ facebody:
|
||||
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
|
||||
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
|
||||
region: "cn-shanghai"
|
||||
|
||||
#支付
|
||||
pay:
|
||||
default-use: zt
|
||||
configs:
|
||||
- name: zt
|
||||
type: WX_MP_PAY
|
||||
config:
|
||||
merchantId: "1700540331"
|
||||
appId: "wxe7ff26af70bfc37c"
|
||||
privateKey: "-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
|
||||
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
|
||||
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
|
||||
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
|
||||
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
|
||||
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
|
||||
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
|
||||
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
|
||||
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
|
||||
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
|
||||
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
|
||||
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
|
||||
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
|
||||
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
|
||||
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
|
||||
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
|
||||
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
|
||||
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
|
||||
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
|
||||
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
|
||||
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
|
||||
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
|
||||
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
|
||||
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
|
||||
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
|
||||
YfkdFNxtYLdVAwuylMoV3fKI
|
||||
-----END PRIVATE KEY-----"
|
||||
serialNumber: "2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0"
|
||||
apiV3Key: ZHENTUAIzhentuaiZHENTUAIzhentuai
|
||||
notify:
|
||||
defaultUse: ""
|
||||
configs:
|
||||
|
@ -54,57 +54,6 @@ mybatis-plus:
|
||||
# 指定使用的日志配置文件
|
||||
logging:
|
||||
config: classpath:logback-spring-prod.xml
|
||||
# 微信小程序相关配置
|
||||
wx:
|
||||
# 公众号的appId
|
||||
appId: fix
|
||||
# 公众号的密钥
|
||||
appSecret: fix
|
||||
# 小程序的AppId
|
||||
miniProgramAppId: wxe7ff26af70bfc37c
|
||||
# 小程序的secret
|
||||
miniProgramSecret: 5252fbbc68513bc77b7cc0052b9f9695
|
||||
# 申请openid授权
|
||||
grandType: authorization_code
|
||||
# 商户号
|
||||
mchId: 1700540331
|
||||
# 商户证书序列号
|
||||
mchSerialNo: 2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0
|
||||
# 支付回调接口地址
|
||||
payNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/payNotify
|
||||
# 退款回调接口地址
|
||||
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
|
||||
# 商户API私钥路径
|
||||
keyPath: "-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
|
||||
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
|
||||
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
|
||||
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
|
||||
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
|
||||
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
|
||||
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
|
||||
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
|
||||
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
|
||||
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
|
||||
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
|
||||
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
|
||||
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
|
||||
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
|
||||
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
|
||||
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
|
||||
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
|
||||
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
|
||||
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
|
||||
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
|
||||
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
|
||||
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
|
||||
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
|
||||
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
|
||||
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
|
||||
YfkdFNxtYLdVAwuylMoV3fKI
|
||||
-----END PRIVATE KEY-----"
|
||||
# 商户APIV3密钥
|
||||
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai
|
||||
|
||||
# 存储
|
||||
storage:
|
||||
@ -171,7 +120,45 @@ facebody:
|
||||
accessKeyId: "LTAI5tMwrmxVcUEKoH5QzLHx"
|
||||
accessKeySecret: "ZCIP8aKx1jwX1wkeYIPQEDZ8fPtN1c"
|
||||
region: "cn-shanghai"
|
||||
|
||||
#支付
|
||||
pay:
|
||||
default-use: zt
|
||||
configs:
|
||||
- name: zt
|
||||
type: WX_MP_PAY
|
||||
config:
|
||||
merchantId: "1700540331"
|
||||
appId: "wxe7ff26af70bfc37c"
|
||||
privateKey: "-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
|
||||
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
|
||||
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
|
||||
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
|
||||
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
|
||||
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
|
||||
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
|
||||
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
|
||||
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
|
||||
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
|
||||
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
|
||||
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
|
||||
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
|
||||
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
|
||||
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
|
||||
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
|
||||
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
|
||||
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
|
||||
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
|
||||
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
|
||||
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
|
||||
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
|
||||
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
|
||||
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
|
||||
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
|
||||
YfkdFNxtYLdVAwuylMoV3fKI
|
||||
-----END PRIVATE KEY-----"
|
||||
serialNumber: "2AD248A1D15F0056D6AEC20B4EEF53F3C32CBFF0"
|
||||
apiV3Key: ZHENTUAIzhentuaiZHENTUAIzhentuai
|
||||
# 通知到人
|
||||
notify:
|
||||
defaultUse: "developer"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user