This commit is contained in:
Jerry Yan 2025-03-08 15:46:24 +08:00
parent 50927481d2
commit c2ebbd71e2
35 changed files with 303 additions and 314 deletions

View File

@ -1,6 +1,7 @@
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;
@ -12,6 +13,7 @@ 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;
@ -37,27 +39,8 @@ public class HttpSaver {
}
public static void saveRequestToFile(HttpServletRequest request) throws IOException {
StringBuilder rawReq = new StringBuilder();
rawReq.append(request.getMethod()).append(" ").append(request.getRequestURL());
String queryString = request.getQueryString();
if (queryString != null) {
rawReq.append("?").append(queryString);
}
rawReq.append("\r\n");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
rawReq.append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
}
rawReq.append("\r\n");
// 获取body
try {
rawReq.append(request.getReader().lines().collect(Collectors.joining("\r\n")));
rawReq.append("\r\n");
} catch (IOException ignore) {
}
// 写入文件
File file = new File("./request/"+System.currentTimeMillis()+".http");
// 写入文件
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
@ -65,7 +48,22 @@ public class HttpSaver {
file.createNewFile();
}
try (java.io.FileWriter writer = new java.io.FileWriter(file, true)) {
writer.write(rawReq.toString());
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");
}
}
}

View File

@ -124,6 +124,18 @@ public class OrderBiz {
return priceObj;
}
public OrderEntity hasTypeOrder(Long userId, Long scenicId, int orderType, Integer configId) {
OrderEntity orderEntity = orderMapper.queryTypeOrder(userId, scenicId, orderType, configId);
if (orderEntity == null) {
return null;
}
if (Integer.valueOf(1).equals(orderEntity.getStatus())) {
return orderEntity;
} else {
return null;
}
}
public IsBuyRespVO isBuy(Long userId, Long scenicId, int goodsType, Long goodsId) {
IsBuyRespVO respVO = new IsBuyRespVO();
boolean isBuy = orderRepository.checkUserBuyItem(userId, goodsType, goodsId);

View File

@ -1,5 +1,8 @@
package com.ycwl.basic.biz;
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.price.entity.PriceConfigEntity;
import com.ycwl.basic.model.pc.price.resp.GoodsListRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
@ -11,6 +14,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -24,6 +28,8 @@ public class PriceBiz {
private ScenicRepository scenicRepository;
@Autowired
private PriceRepository priceRepository;
@Autowired
private OrderBiz orderBiz;
public List<GoodsListRespVO> listGoodsByScenic(Long scenicId) {
List<GoodsListRespVO> goodsList = new ArrayList<>();
@ -66,4 +72,38 @@ public class PriceBiz {
return false;
}).collect(Collectors.toList());
}
public IsBuyBatchRespVO isBuy(Long userId, Long scenicId, Integer type, String goodsIds) {
IsBuyBatchRespVO respVO = new IsBuyBatchRespVO();
PriceConfigEntity priceConfig = priceRepository.getPriceConfigByScenicTypeGoods(scenicId, type, goodsIds);
if (priceConfig == null) {
throw new RuntimeException("该套餐暂未开放购买");
}
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(scenicId);
if (scenicConfig != null) {
if (Integer.valueOf(1).equals(scenicConfig.getAllFree())) {
// 景区全免
respVO.setFree(true);
respVO.setPrice(BigDecimal.ZERO);
respVO.setSlashPrice(BigDecimal.ZERO);
return respVO;
}
}
respVO.setConfigId(priceConfig.getId());
respVO.setGoodsIds(goodsIds);
respVO.setType(type);
respVO.setPrice(priceConfig.getPrice());
respVO.setSlashPrice(priceConfig.getSlashPrice());
// 查询用户是否有此类订单
respVO.setBuy(false);
if (userId != null) {
OrderEntity orderEntity = orderBiz.hasTypeOrder(userId, scenicId, type, priceConfig.getId());
if (orderEntity != null) {
respVO.setOrderId(orderEntity.getId());
respVO.setBuy(Integer.valueOf(1).equals(orderEntity.getStatus()));
}
}
return respVO;
}
}

View File

@ -0,0 +1,59 @@
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() throws IOException {
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() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public byte[] getCachedBody() {
return cachedBody;
}
}

View File

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

View File

@ -12,7 +12,7 @@ public class SchedulerConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(256);
scheduler.setPoolSize(128);
scheduler.setThreadNamePrefix("Scheduler-");
return scheduler;
}

View File

@ -2,9 +2,11 @@ package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.PriceBiz;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.GoodsPriceQueryReq;
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.OrderAppPageReq;
import com.ycwl.basic.model.mobile.order.RefundOrderReq;
@ -14,6 +16,7 @@ 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;
@ -38,6 +41,10 @@ public class AppOrderController {
private OrderRepository orderRepository;
@Autowired
private OrderBiz orderBiz;
@Autowired
private PriceBiz priceBiz;
@Autowired
private PriceRepository priceRepository;
@ApiOperation("用户端订单列表查询")
@PostMapping("/page")
@ -88,4 +95,10 @@ public class AppOrderController {
Long userId = Long.parseLong(BaseContextHandler.getUserId());
return ApiResponse.success(orderBiz.isBuy(userId, scenicId, type, goodsId));
}
@GetMapping("/scenic/{scenicId}/queryBatchPrice")
public ApiResponse<IsBuyBatchRespVO> queryPrice(@PathVariable("scenicId") Long scenicId, @RequestParam("type") Integer type, @RequestParam(value = "goodsIds", required = false) String goodsIds) {
Long userId = Long.parseLong(BaseContextHandler.getUserId());
return ApiResponse.success(priceBiz.isBuy(userId, scenicId, type, goodsIds));
}
}

View File

@ -1,20 +1,14 @@
package com.ycwl.basic.controller.mobile;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.model.wx.WechatMessageSubscribeForm;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.WxNotifyService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -31,8 +25,6 @@ import java.util.List;
@RequestMapping("/api/mobile/wx/notify/v1")
@Api(tags = "微信消息模板通知")
public class AppWxNotifyController {
@Autowired
private WxNotifyService wxNotifyService;
@Autowired
private ScenicRepository scenicRepository;
//

View File

@ -7,6 +7,7 @@ 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.mapper.DeviceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
@ -19,6 +20,8 @@ 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;
@ -52,6 +55,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -59,6 +63,9 @@ import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
@ -79,6 +86,8 @@ public class ViidController {
@Autowired
private ScenicRepository scenicRepository;
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 1024, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1024));
// region 注册注销基础接口
/**
* 注册接口
@ -220,10 +229,6 @@ public class ViidController {
if (device == null) {
continue;
}
if (!Integer.valueOf(1).equals(device.getStatus())) {
log.info("设备状态为关闭跳过该设备。deviceId:{}", deviceID);
continue;
}
DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
int viidMode = 0;
if (deviceConfig != null && deviceConfig.getViidType() != null) {
@ -284,22 +289,25 @@ public class ViidController {
// Type=11 人脸
if (subImage.getType().equals("11")) {
// 上传oss
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
new Thread(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
}).start();
if (Integer.valueOf(1).equals(device.getStatus())) {
FaceSampleEntity faceSample = new FaceSampleEntity();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
executor.execute(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
});
}
for (SubImageInfoObject _subImage : type14ImageList) {
facePosition.setImgHeight(_subImage.getHeight());
facePosition.setImgWidth(_subImage.getWidth());
@ -334,24 +342,26 @@ public class ViidController {
// Type=14 人脸有这么传的嘛
if (subImage.getType().equals("14")) {
// 上传oss
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
DynamicTaskGenerator.addTask(faceSample.getId());
new Thread(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
}).start();
log.info("模式1人脸信息入库成功设备ID{}", deviceID);
if (Integer.valueOf(1).equals(device.getStatus())) {
FaceSampleEntity faceSample = new FaceSampleEntity();
Long newFaceSampleId = SnowFlakeUtil.getLongId();
faceSample.setId(newFaceSampleId);
faceSample.setScenicId(scenicId);
faceSample.setDeviceId(device.getId());
faceSample.setStatus(0);
faceSample.setCreateAt(shotTime);
String url = adapter.uploadFile(file, "user-face", UUID.randomUUID() + "." + ext);
faceSample.setFaceUrl(url);
faceSampleMapper.add(faceSample);
DynamicTaskGenerator.addTask(faceSample.getId());
executor.execute(() -> {
taskFaceService.addFaceSample(faceSample.getId());
if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
DynamicTaskGenerator.addTask(faceSample.getId());
}
});
log.info("模式1人脸信息入库成功设备ID{}", deviceID);
}
}
}
}
@ -365,8 +375,9 @@ public class ViidController {
@RequestMapping(value = "/Images", method = RequestMethod.POST)
@IgnoreLogReq
public VIIDBaseResp images(@RequestBody ImageUploadReq req) {
log.info("Images:{}", req);
public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
// log.info("Images:{}", req);
HttpSaver.saveRequestToFile(request);
return new VIIDBaseResp(
new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
);

View File

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

View File

@ -81,7 +81,7 @@ public class VptPassiveStorageOperator extends ADeviceStorageOperator {
log.info("任务{}获取视频开始!共{}", task.taskId, taskList.size());
Date taskStartTime = new Date();
while (true) {
if (new Date().getTime() - taskStartTime.getTime() > 80000L) {
if (new Date().getTime() - taskStartTime.getTime() > 60000L) {
log.info("任务{}获取视频超时!", task.taskId);
fileListMap.remove(task.taskId);
return Collections.emptyList();

View File

@ -75,7 +75,7 @@ public class WvpPassiveStorageOperator extends ADeviceStorageOperator {
taskList.add(task);
Date taskStartTime = new Date();
while (true) {
if (new Date().getTime() - taskStartTime.getTime() > 80000L) {
if (new Date().getTime() - taskStartTime.getTime() > 60000L) {
log.info("任务{}获取视频超时!", task.taskId);
fileListMap.remove(task.taskId);
return Collections.emptyList();

View File

@ -0,0 +1,21 @@
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);
}
}

View File

@ -16,6 +16,7 @@ import java.util.List;
@Mapper
public interface FaceMapper {
List<FaceRespVO> list(FaceReqQuery faceReqQuery);
List<FaceRespVO> test();
List<FaceRespVO> listByScenicIdAndNotFinished(Long scenicId);
FaceRespVO getById(Long id);
FaceEntity get(Long id);

View File

@ -50,4 +50,6 @@ public interface OrderMapper {
OrderItemEntity getOrderItem(Long orderItemId);
int updateOrder(OrderEntity updateEntity);
OrderEntity queryTypeOrder(Long userId, Long scenicId, int orderType, Integer priceConfigId);
}

View File

@ -0,0 +1,17 @@
package com.ycwl.basic.model.mobile.order;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class IsBuyBatchRespVO {
private boolean buy;
private boolean free;
private Long orderId;
private Integer configId;
private int type;
private String goodsIds;
private BigDecimal price;
private BigDecimal slashPrice;
}

View File

@ -31,6 +31,7 @@ public class DeviceRespVO {
private Integer status;
@ApiModelProperty("是否在线0不在线1在线")
private Integer online;
private String coverUrl;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

View File

@ -111,7 +111,7 @@ public class DeviceRepository {
device.setOnline(online);
device.setKeepaliveAt(keepaliveAt);
device.setIpAddr(ipAddr);
redisTemplate.opsForValue().set(String.format(DEVICE_ONLINE_CACHE_KEY, deviceId), JSONObject.toJSONString(device), 60L, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(String.format(DEVICE_ONLINE_CACHE_KEY, deviceId), JSONObject.toJSONString(device), 2, TimeUnit.DAYS);
// deviceMapper.updateOnlineStatus(deviceId, ipAddr, online, keepaliveAt);
updateDeviceCache(device);
}

View File

@ -161,8 +161,8 @@ public class AppScenicServiceImpl implements AppScenicService {
sourceImageContent.setGoodsType(2);
sourceVideoContent.setContentType(2);
sourceImageContent.setContentType(2);
sourceVideoContent.setLockType(1);
sourceImageContent.setLockType(1);
sourceVideoContent.setLockType(-1);
sourceImageContent.setLockType(-1);
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, faceRespVO.getScenicId(), 2, faceId);
@ -188,10 +188,10 @@ public class AppScenicServiceImpl implements AppScenicService {
}
sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).forEach((type, list) -> {
if (type == 1) {
sourceVideoContent.setLockType(0);
sourceVideoContent.setLockType(-1);
sourceVideoContent.setTemplateCoverUrl(list.get(0).getUrl());
} else {
sourceImageContent.setLockType(0);
sourceImageContent.setLockType(-1);
sourceImageContent.setTemplateCoverUrl(list.get(0).getUrl());
}
});

View File

@ -1,164 +0,0 @@
package com.ycwl.basic.service.impl.mobile;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.config.WechatConfig;
import com.ycwl.basic.constant.NumberConstant;
import com.ycwl.basic.constant.WeiXinConstant;
import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.enums.StatisticEnum;
import com.ycwl.basic.exception.AppException;
import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.MessageRecordMapper;
import com.ycwl.basic.mapper.ScenicMapper;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.model.mobile.messageRecord.MessageRecordEntity;
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
import com.ycwl.basic.model.wx.WechatAccessTokenVO;
import com.ycwl.basic.model.wx.WechatMessageSubscribeForm;
import com.ycwl.basic.model.wx.WechatMssVO;
import com.ycwl.basic.service.mobile.WxNotifyService;
import com.ycwl.basic.utils.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import static com.ycwl.basic.constant.WeiXinConstant.*;
/**
* @Author: songmingsong
* @CreateTime: 2024-12-06
* @Description: 微信消息通知实现
* @Version: 1.0
*/
@Slf4j
@Service
public class WxNotifyServiceImpl implements WxNotifyService {
private final RestTemplate restTemplate = new RestTemplate();
@Autowired
private WechatConfig wechatConfig;
@Autowired
private MessageRecordMapper messageRecordMapper;
@Autowired
private StatisticsMapper statisticsMapper;
@Autowired
private MemberMapper memberMapper;
/**
* 缓存accessToken
*/
private final Map<String, AccessTokenCacheEntity> cacheAccessTokenMap = new ConcurrentHashMap<>();
@Override
public String getAccessToken() {
String cacheKey = wechatConfig.getMiniProgramAppId() + wechatConfig.getMiniProgramSecret();
AccessTokenCacheEntity accessTokenCacheEntity = cacheAccessTokenMap.get(cacheKey);
if (accessTokenCacheEntity != null && accessTokenCacheEntity.expireDate.getTime() > System.currentTimeMillis()) {
return accessTokenCacheEntity.accessToken;
}
String url = String.format(WeiXinConstant.ACCESS_TOKEN_WITH_PARAM, wechatConfig.getMiniProgramAppId(), wechatConfig.getMiniProgramSecret());
ResponseEntity<WechatAccessTokenVO> responseEntity = restTemplate.getForEntity(url, WechatAccessTokenVO.class);
if (HttpStatus.OK == responseEntity.getStatusCode()) {
WechatAccessTokenVO accessTokenVO = responseEntity.getBody();
if (accessTokenVO.isSuccess()) {
accessTokenCacheEntity = new AccessTokenCacheEntity();
accessTokenCacheEntity.accessToken = accessTokenVO.getAccess_token();
// 设置过期时间减100秒防止网络延迟失效
accessTokenCacheEntity.expireDate = new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(accessTokenVO.getExpires_in() - NumberConstant.HUNDRED));
// 缓存一份有效期内避免重复请求
cacheAccessTokenMap.put(cacheKey, accessTokenCacheEntity);
return accessTokenVO.getAccess_token();
} else {
log.error("[微信token]请求AccessToken出现异常错误信息为{}{}", accessTokenVO.getErrcode(), accessTokenVO.getErrmsg());
throw new AppException(BizCodeEnum.REQUEST_WECHAT_FAIL);
}
}
throw new AppException(BizCodeEnum.REQUEST_WECHAT_FAIL);
}
/**
* 给用户发送通知
*
* @param info
* @return
*/
@Override
public JSONObject pushMessage(WechatMessageSubscribeForm info) {
Integer scenicServiceNoticeStatus = memberMapper.getScenicServiceNoticeStatus(info.getScenicId(), info.getMemberId());
if (scenicServiceNoticeStatus == NumberConstant.ZERO) {
log.info("用户已关闭通知");
return null;
}else {
// 发送通知
RestTemplate restTemplate = new RestTemplate();
String url = MESSAGE_SEND_URL + getAccessToken();
// 拼接推送的模板
WechatMssVO wxMssVO = new WechatMssVO();
wxMssVO.setTouser(info.getOpenId()); // 用户的openId
wxMssVO.setTemplate_id(info.getTemplateId()); // 订阅消息模板id
wxMssVO.setLang(info.getLang()); // 语言类型
wxMssVO.setMiniprogram_state(info.getMiniprogram_state()); // 跳转小程序类型
wxMssVO.setPage(info.getPage());
// // TODO: 推送的内容
// Map<String, WechatTemplateData> map = new HashMap<>();
// map.put("msg", new WechatTemplateData("发消息了"));
wxMssVO.setData(info.getData());
// 发送
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, wxMssVO, String.class);
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(responseEntity.getBody()));
Integer errcode = jsonObject.getInteger(WECHAT_ERRCODE);
String errmsg = jsonObject.getString(WECHAT_ERRMSG);
if (errcode != NumberConstant.ZERO) {
throw new AppException(errcode, errmsg);
}
// 记录消息记录
MessageRecordEntity messageRecord = new MessageRecordEntity();
messageRecord.setId(SnowFlakeUtil.getLongId());
messageRecord.setMemberId(info.getMemberId());
messageRecord.setScenicId(info.getScenicId());
messageRecord.setTemplateId(info.getTemplateId());
messageRecord.setContent(info.getData().toString());
messageRecordMapper.insertMessageRecord(messageRecord);
// 统计消息记录
StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
statisticsRecordAddReq.setScenicId(info.getScenicId());
statisticsRecordAddReq.setMemberId(info.getMemberId());
statisticsRecordAddReq.setType(StatisticEnum.MESSAGE_PUSH.code);
statisticsRecordAddReq.setMorphId(messageRecord.getId());
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
return JSONObject.parseObject(JSONObject.toJSONString(responseEntity.getBody()));
}
}
private class AccessTokenCacheEntity {
/**
* token
*/
private String accessToken;
/**
* 有效期到
*/
private Date expireDate;
}
}

View File

@ -18,6 +18,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@ -39,8 +40,12 @@ public class DeviceServiceImpl implements DeviceService {
for (DeviceRespVO deviceRespVO : list) {
DeviceEntity onlineStatus = deviceRepository.getOnlineStatus(deviceRespVO.getId());
if (onlineStatus != null) {
deviceRespVO.setOnline(onlineStatus.getOnline());
deviceRespVO.setKeepaliveAt(onlineStatus.getKeepaliveAt());
if (new Date().getTime() - onlineStatus.getKeepaliveAt().getTime() > 300000) {
deviceRespVO.setOnline(0);
} else {
deviceRespVO.setOnline(onlineStatus.getOnline());
}
} else {
deviceRespVO.setOnline(0);
deviceRespVO.setKeepaliveAt(null);

View File

@ -152,7 +152,7 @@ public class OrderServiceImpl implements OrderService {
WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO();
String goodsName = null;
if (orderItems.size() > 1) {
goodsName = "多项景区Vloh商品";
goodsName = "多项景区Vlog商品";
} else {
int type = orderItems.get(NumberConstant.ZERO).getGoodsType();
if (type == NumberConstant.ZERO) {

View File

@ -1,17 +0,0 @@
package com.ycwl.basic.service.mobile;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.model.wx.WechatMessageSubscribeForm;
public interface WxNotifyService {
/**
* 获取微信token
*/
String getAccessToken();
/**
* 发送模板消息
*/
JSONObject pushMessage(WechatMessageSubscribeForm info);
}

View File

@ -64,6 +64,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
@ -97,6 +99,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
private final FixedRateLimiter searchFaceLimiter = new FixedRateLimiter(200, TimeUnit.MILLISECONDS);
private final FixedRateLimiter deleteDbLimiter = new FixedRateLimiter(600, TimeUnit.MILLISECONDS);
private final FixedRateLimiter deleteEntityLimiter = new FixedRateLimiter(600, TimeUnit.MILLISECONDS);
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 1024, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1024));
@Autowired
private ScenicRepository scenicRepository;
@ -224,7 +227,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
log.setMatchRawResult("识别错误,错误为:["+e.getLocalizedMessage()+"]");
throw new BaseException(e.getMessage());
} finally {
new Thread(() -> {
executor.execute(() -> {
if (log.getMatchRawRecord() != null) {
List<MatchLocalRecord> collect = log.getMatchRawRecord().parallelStream().map(item -> {
MatchLocalRecord record = new MatchLocalRecord();
@ -251,7 +254,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
log.setMatchLocalRecord(JSON.toJSONString(collect));
}
logMapper.insert(log);
}).start();
});
}
}

View File

@ -74,6 +74,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
@ -120,6 +122,7 @@ 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));
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
@ -613,9 +616,9 @@ public class TaskTaskServiceImpl implements TaskService {
}
}
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId(), isBuy);
new Thread(() -> {
executor.execute(() -> {
sendVideoGeneratedServiceNotification(taskId);
}).start();
});
}
@Override

View File

@ -24,6 +24,7 @@ import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.entity.StorageFileObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@ -37,6 +38,7 @@ import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
@Component
@EnableScheduling
@Slf4j
@Profile("prod")
public class FaceCleaner {
@Autowired
private ScenicMapper scenicMapper;

View File

@ -10,6 +10,7 @@ import com.ycwl.basic.model.pc.device.req.DeviceReqQuery;
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@ -20,6 +21,7 @@ import java.util.List;
@Component
@EnableScheduling
@Slf4j
@Profile("prod")
public class VideoPieceCleaner {
@Autowired
private DeviceMapper deviceMapper;

View File

@ -62,7 +62,7 @@ public class VideoPieceGetter {
@Data
public static class Task {
public List<Long> faceSampleIds;
public List<Long> faceSampleIds = new ArrayList<>();
public Callback callback;
public Long memberId;
public Long faceId;
@ -114,7 +114,7 @@ public class VideoPieceGetter {
// taskStatusBiz.setFaceCutStatus(task.faceId, 0);
// }
AtomicBoolean invoke = new AtomicBoolean(false);
ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 16, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(32));
final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 512, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(512));
List<String> currentPlaceholder = new ArrayList<>();
List<FaceSampleEntity> list = faceSampleMapper.listByIds(task.getFaceSampleIds());
Collection<List<FaceSampleEntity>> collection = list.stream()
@ -128,7 +128,8 @@ public class VideoPieceGetter {
.values();
collection.forEach(faceSampleList -> {
executor.execute(() -> {
faceSampleList.parallelStream().forEach(faceSample -> {
faceSampleList.parallelStream().forEach(faceSample -> {
executor.execute(() -> {
DeviceEntity device = deviceRepository.getDevice(faceSample.getDeviceId());
DeviceConfigEntity config = deviceRepository.getDeviceConfig(faceSample.getDeviceId());
@ -255,11 +256,15 @@ public class VideoPieceGetter {
}
}
});
});
});
});
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
Thread.sleep(1000L);
log.info("executor等待被结束[A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
executor.shutdown();
executor.awaitTermination(5, TimeUnit.MINUTES);
log.info("executor已结束[A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
} catch (InterruptedException e) {
return;
} finally {

View File

@ -30,7 +30,7 @@ public class WxMpUtil {
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);
expireTime = new Date(System.currentTimeMillis() + jsonObject.getInteger("expires_in") * 1000 / 2);
return ACCESS_TOKEN;
}
@ -47,6 +47,10 @@ public class WxMpUtil {
httpPost.setHeader("Content-Type", "application/json");
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
if (response.getStatusLine().getStatusCode() != 200) {
expireTime = new Date();
throw new Exception("获取小程序码失败");
}
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
byte[] bytes = EntityUtils.toByteArray(responseEntity);

View File

@ -1,5 +1,8 @@
server:
port: 8030
tomcat:
threads:
min-spare: 64
spring:
application:
@ -18,13 +21,13 @@ spring:
username: zt
password: ZhEnTuAi2024zHeNtUaI
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时长毫秒超过这个时长还没可用的连接则发生SQLException 默认:30秒
minimum-idle: 5 # 最小连接数
maximum-pool-size: 20 # 最大连接数
connection-timeout: 10000 # 等待连接池分配连接的最大时长毫秒超过这个时长还没可用的连接则发生SQLException 默认:30秒
minimum-idle: 10 # 最小连接数
maximum-pool-size: 50 # 最大连接数
auto-commit: true # 事务自动提交
idle-timeout: 60000 # 连接超时的最大时长(毫秒)
pool-name: DateSourceHikariCP # 连接池名字
max-lifetime: 180000 # 连接的生命时长(毫秒)
idle-timeout: 120000 # 连接超时的最大时长(毫秒)
pool-name: DateSourceHikariCP # 连接池名字
max-lifetime: 300000 # 连接的生命时长(毫秒)
connection-test-query: SELECT 1 # 连接测试语句
jackson:
date-format: "yyyy-MM-dd HH:mm:ss"
@ -36,10 +39,9 @@ spring:
password: ''
jedis:
pool:
max-active: -1 # 连接池最大连接数(使用负值表示没有限制)
max-active: 100 # 连接池最大连接数(使用负值表示没有限制)
min-idle: 1 # 连接池中的最小空闲连接
time-between-eviction-runs: 3000
timeout: 40000
timeout: 1000
# 配置用户头像存放静态资源文件夹
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/

View File

@ -32,9 +32,9 @@
<fileNamePattern>logs/project_info.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<maxHistory>30</maxHistory>
<maxHistory>7</maxHistory>
<!-- 每个日志文件到10mb的时候开始切分最多保留30天但最大到20GB哪怕没到30天也要删除多余的日志 -->
<totalSizeCap>20GB</totalSizeCap>
<totalSizeCap>1GB</totalSizeCap>
<!-- maxFileSize:这是活动文件的大小默认值是10MB测试时可改成5KB看效果 -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>

View File

@ -67,7 +67,8 @@
delete from device where id = #{id}
</delete>
<select id="list" resultType="com.ycwl.basic.model.pc.device.resp.DeviceRespVO">
select d.id, scenic_id, d.name, no, d.longitude, d.latitude, d.status, create_at, d.update_at, s.name scenic_name, d.keepalive_at, d.online, p.wvp_device_no as device_no, p.wvp_channel_no channel_no
select d.id, scenic_id, d.name, no, d.longitude, d.latitude, d.status, create_at, d.update_at, s.name scenic_name, d.keepalive_at, d.online, p.wvp_device_no as device_no, p.wvp_channel_no channel_no,
(select url from source s where s.device_id=d.id order by id desc limit 1) coverUrl
from device d
left join scenic s on d.scenic_id = s.id
left join device_preview_config p on d.id = p.device_id and p.status = 1
@ -91,7 +92,7 @@
and d.create_at &lt;= #{endTime}
</if>
</where>
order by sort
order by d.scenic_id desc, sort asc
</select>
<select id="getById" resultType="com.ycwl.basic.model.pc.device.resp.DeviceRespVO">
select d.id, scenic_id, d.name, no, d.longitude, d.latitude, d.status, create_at, d.update_at, s.name scenic_name

View File

@ -117,4 +117,7 @@
order by update_at desc
limit 1
</select>
<select id="test" resultType="com.ycwl.basic.model.pc.face.resp.FaceRespVO">
SELECT * FROM `zt`.`face_sample` WHERE `scenic_id` = '3930324797233434624' AND `create_at` &lt; '2025-03-07 14:40:36' AND `device_id` = '3961959104355897344'
</select>
</mapper>

View File

@ -483,4 +483,8 @@
<select id="getOrderItem" resultType="com.ycwl.basic.model.pc.order.entity.OrderItemEntity">
select * from order_item where id = #{id}
</select>
<select id="queryTypeOrder" resultType="com.ycwl.basic.model.pc.order.entity.OrderEntity">
select * from `order` where member_id = #{userId} and type = #{orderType} and price_config_id = #{priceConfigId}
limit 1
</select>
</mapper>

View File

@ -52,7 +52,7 @@
select * from price_config
where scenic_id = #{scenicId}
and type = #{type}
<if test="goodsId != null">
<if test="goodsId != null and goodsId != ''">
and goods_ids like concat('%', #{goodsId}, '%')
</if>
</select>