You've already forked FrameTour-BE
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 |
src/main
java
com
ycwl
basic
annotation
aspectj
config
controller
mobile
pc
proxy
task
viid
vpt
wvp
enums
exception
facebody
filter
interceptor
mapper
model
mobile
pc
price
renderWorker
entity
scenic
pay
PayFactory.java
adapter
entity
CancelOrderRequest.javaCreateOrderRequest.javaCreateOrderResponse.javaPayResponse.javaRefundOrderRequest.javaRefundOrderResponse.javaRefundResponse.javaWxMpPayConfig.java
enums
exceptions
starter
printer
ticket
service
stats
biz
controller
dto
entity
interceptor
mapper
service
util
storage
adapters
AStorageAdapter.javaAliOssAdapter.javaAwsOssAdapter.javaIStorageAdapter.javaLocalStorageAdapter.java
entity
task
utils
CustomBigDecimalUtils.javaHttpServiceUtil.javaImageUtils.javaObjectConvertUtils.javaRedisCacheOperationUtils.javaSslUtil.javaVideoReUploader.javaWXPayUtil.javaWxMpUtil.java
xss
resources
@ -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
Reference in New Issue
Block a user