Browse Source

可跑(不合并)

暂用(不合并)
huangqizhen 2 days ago
parent
commit
e56cb9744f
  1. 4
      src/main/java/com/example/demo/controller/GoldDetailController.java
  2. 13
      src/main/java/com/example/demo/exception/SystemException.java
  3. 3
      src/main/java/com/example/demo/mapper/GoldDetailMapper.java
  4. 84
      src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java
  5. 69
      src/main/java/com/example/demo/service/queue/AbstractMessageListener.java
  6. 10
      src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java
  7. 5
      src/main/resources/mapper/GoldDetailMapper.xml

4
src/main/java/com/example/demo/controller/GoldDetailController.java

@ -72,7 +72,7 @@ public class GoldDetailController {
}
return Result.success(goldDetailService.getGold(page.getPageNum(), page.getPageSize(), page.getUser()));
}
@PostMapping("export")
@PostMapping("/export")
public Result export(@Valid @RequestBody GoldDetailDTO dto) {
String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key可按用户/业务区分
String requestId = UUID.randomUUID().toString(); // 请求 ID防止误删锁
@ -83,7 +83,7 @@ public class GoldDetailController {
throw new BusinessException("操作太频繁,请稍后重试");
}
// 执行业务逻辑
return GoldDetailService.addExportRecord(dto);
return goldDetailService.addExportRecord(dto);
} finally {
// 释放锁
redisLockUtil.unlock(lockKey, requestId);

13
src/main/java/com/example/demo/exception/SystemException.java

@ -0,0 +1,13 @@
package com.example.demo.exception;
public class SystemException extends RuntimeException {
public SystemException(String message) {
super(message);
}
public SystemException(String message, Throwable cause) {
super(message, cause);
}
}

3
src/main/java/com/example/demo/mapper/GoldDetailMapper.java

@ -3,6 +3,7 @@ package com.example.demo.mapper;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Total;
import lombok.Data;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -22,6 +23,7 @@ public interface GoldDetailMapper {
Total getTotal(GoldDetail goldDetail);
List<User> getGold(User user);
Total GoldTotal(User user);
@Data
public static class ExportRecordIdHolder{
private Long id;
}
@ -34,5 +36,4 @@ public interface GoldDetailMapper {
@Param("fileName") String fileName,
@Param("dataNum") Integer dataNum
);
);
}

84
src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java

@ -0,0 +1,84 @@
package com.example.demo.service.listen;
import cn.hutool.core.util.StrUtil;
import com.example.demo.Util.ExecutionContextUtil;
import com.example.demo.Util.FeiShuAlertUtil;
import com.example.demo.Util.RedisUtil;
import com.example.demo.domain.vo.ExecutionContext;
import com.example.demo.service.ExportExcelService;
import com.example.demo.service.queue.AbstractMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static java.lang.Thread.sleep;
@Component
public class AiEmotionExportListener extends AbstractMessageListener<String> {
//注入ExportExcelService
@Autowired
private ExportExcelService exportExcelService;
@Autowired
public AiEmotionExportListener(
RedisUtil redisQueueUtil
) {
super(redisQueueUtil, "hwgold:queue:export_queue");
System.out.println("监听器已启动,队列: ");
}
@Override
protected void handleMessage(String message) {
if (StrUtil.isBlank(message)) {
System.err.println("redis消息队列数据为空" + message);
}
try {
Thread.sleep(5000);
exportExcelService.handleExcelExportData(message);
} catch (Exception e) {
logError(e, message);
throw new RuntimeException("Failed to process AI emotion export: " + e.getMessage(), e);
}
}
private void logError(Exception e, String message) {
System.err.println("Export data listener exception: " + e.getMessage());
e.printStackTrace();
try {
ExecutionContext context = ExecutionContextUtil.getExecutionContext();
String cause = "";
if (e.getCause() != null) {
cause = e.getCause().getMessage();
}
FeiShuAlertUtil.sendAlertMessage(
context,
e.getStackTrace()[0].getFileName(),
e.getStackTrace()[0].getLineNumber(),
"AI Emotion Export Error: " + e.getMessage() + " 底层错误: " + cause ,
"Failed message: " + message
);
} catch (Exception alertEx) {
System.err.println("Failed to send Feishu alert: " + alertEx.getMessage());
}
}
@Override
protected void handleError(Exception e, String message) {
System.err.println("处理消息失败: " + message);
e.printStackTrace();
}
}

69
src/main/java/com/example/demo/service/queue/AbstractMessageListener.java

@ -0,0 +1,69 @@
package com.example.demo.service.queue;
import com.example.demo.Util.RedisUtil;
import jakarta.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 抽象消息监听器
*/
public abstract class AbstractMessageListener<T> {
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
protected final RedisUtil redisQueueUtil;
protected final String queueName;
public AbstractMessageListener(RedisUtil redisQueueUtil, String queueName) {
this.redisQueueUtil = redisQueueUtil;
this.queueName = queueName;
}
@PostConstruct
public void init() {
executorService.submit(this::listen);
}
private void listen() {
System.out.println("消费者消费数据" + queueName + "<UNK>");
while (!Thread.currentThread().isInterrupted()) {
try {
Object message = redisQueueUtil.blockingGetMessage(queueName, 1);
if (message != null) {
try {
handleMessage((T) message);
} catch (Exception e) {
handleError(e, (T) message);
}
}
} catch (Exception e) {
System.err.println("监听队列异常: " + e.getMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
/**
* 处理消息
* @param message 消息内容
*/
protected abstract void handleMessage(T message);
/**
* 处理错误
* @param e 异常
* @param message 消息内容
*/
protected void handleError(Exception e, T message) {
System.err.println("处理消息异常: " + e.getMessage());
}
}

10
src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java

@ -1,10 +1,12 @@
package com.example.demo.serviceImpl;
import com.example.demo.Util.RedisUtil;
import com.example.demo.domain.DTO.GoldDetailDTO;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.vo.GoldDetail;
import com.example.demo.domain.vo.Result;
import com.example.demo.domain.vo.Total;
import com.example.demo.exception.SystemException;
import com.example.demo.mapper.GoldDetailMapper;
import com.example.demo.service.GoldDetailService;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -33,6 +35,8 @@ public class GoldDetailServiceImpl implements GoldDetailService {
@Autowired
private GoldDetailMapper goldDetailMapper;
@Autowired
private RedisUtil redisUtil;
@Override
public PageInfo<GoldDetail> getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail) {
@ -76,7 +80,7 @@ public class GoldDetailServiceImpl implements GoldDetailService {
dto.setDataNum(0);
try{
// 调用方式
GoldDetailMapper.ExportRecordIdHolder idHolder = new AiEmotionMapper.ExportRecordIdHolder();
GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder();
goldDetailMapper.insertExportRecord(
idHolder, // 用于接收主键
dto.getJwcode(),
@ -111,6 +115,6 @@ public class GoldDetailServiceImpl implements GoldDetailService {
}
}
}
}

5
src/main/resources/mapper/GoldDetailMapper.xml

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.GoldDetailMapper">
<insert id="insertExportRecord">
insert into
<insert id="insertExportRecord" useGeneratedKeys="true" keyProperty="recordId.id">
insert into excprt (jwcode,type,state,url,file_name,data_num)
values(#{jwcode},#{type},#{state},#{url},#{fileName},#{dataNum})
</insert>
<select id="getGoldDetail" resultType="com.example.demo.domain.vo.GoldDetail">

Loading…
Cancel
Save