二维码功能开发

This commit is contained in:
2025-06-18 17:53:09 +08:00
parent e05403bfa7
commit 4e0e50a4f8
9 changed files with 183 additions and 22 deletions

View File

@@ -94,7 +94,7 @@
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>3.3.4</version>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -112,6 +112,18 @@
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>RestTemplate-plugin</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.10.0</version>
</dependency>
</dependencies>

View File

@@ -13,6 +13,9 @@ public interface DetectionCommunicateConstant {
String DEVICE_CHANNEL_NAME = "AUTO_DETECTION_DEV";
String DEV = "_Dev";
String SOURCE = "_Source";

View File

@@ -94,6 +94,11 @@ public enum SourceOperateCodeEnum {
small_comp_end("small_comp_end","小电压校准结束"),
/**
* ftp文件传送指令
*/
FTP_SEND_01("FTP_SEND$01", "发送文件")
;

View File

@@ -191,7 +191,7 @@ public class PreDetectionServiceImpl implements PreDetectionService {
xuMsg.setOperateCode(SourceOperateCodeEnum.OPER_GATHER.getValue());
xuMsg.setData(JSON.toJSONString(sourceIssues));
xuMsg.setRequestId(SourceOperateCodeEnum.FORMAL_REAL.getValue() + "&&" + sourceIssues.getType());
SocketManager.sendMsg(DetectionCommunicateConstant.SOURCE_CHANNEL_NAME, JSON.toJSONString(xuMsg));
SocketManager.sendMsg(param.getUserPageId() + DetectionCommunicateConstant.SOURCE, JSON.toJSONString(xuMsg));
} else {
//TODO 是否最终检测完成需要推送给用户
PqScriptCheckDataParam checkDataParam = new PqScriptCheckDataParam();
@@ -219,7 +219,7 @@ public class PreDetectionServiceImpl implements PreDetectionService {
@Override
public void sendScript(SimulateDetectionParam param) {
Channel channel = SocketManager.getChannelByUserId(DetectionCommunicateConstant.SOURCE_CHANNEL_NAME);
Channel channel = SocketManager.getChannelByUserId(param.getUserPageId() + DetectionCommunicateConstant.SOURCE);
if (Objects.isNull(channel) || !channel.isActive()) {
// 进行源通信连接
PreDetectionParam preDetectionParam = new PreDetectionParam();
@@ -253,7 +253,7 @@ public class PreDetectionServiceImpl implements PreDetectionService {
@Override
public void closeTestSimulate(SimulateDetectionParam param) {
Channel channel = SocketManager.getChannelByUserId(DetectionCommunicateConstant.SOURCE_CHANNEL_NAME);
Channel channel = SocketManager.getChannelByUserId(param.getUserPageId() + DetectionCommunicateConstant.SOURCE);
if (Objects.isNull(channel) || !channel.isActive()) {
throw new BusinessException(DetectionResponseEnum.SOURCE_NOT_CONNECT);
}

View File

@@ -10,7 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
/**
*
* 检测通讯工具类
*
* @author hongawen
@@ -26,8 +25,9 @@ public class DetectionCommunicateUtil {
* 有则强行关闭
*/
public static void checkCommunicateChannel(PreDetectionParam param) {
Channel channelSource = SocketManager.getChannelByUserId(DetectionCommunicateConstant.SOURCE_CHANNEL_NAME);
Channel channelDev = SocketManager.getChannelByUserId(DetectionCommunicateConstant.DEVICE_CHANNEL_NAME);
Channel channelSource = SocketManager.getChannelByUserId(param.getUserPageId() + DetectionCommunicateConstant.SOURCE);
Channel channelDev = SocketManager.getChannelByUserId(param.getUserPageId() + DetectionCommunicateConstant.DEV);
if (Objects.nonNull(channelSource) && channelSource.isActive()) {
System.out.println("发送关闭源指令。。。。。。。。");
CnSocketUtil.quitSendSource(param);
@@ -43,8 +43,8 @@ public class DetectionCommunicateUtil {
log.error(e.getMessage());
}
SocketManager.removeUser(DetectionCommunicateConstant.SOURCE_CHANNEL_NAME);
SocketManager.removeUser(DetectionCommunicateConstant.DEVICE_CHANNEL_NAME);
SocketManager.removeUser(param.getUserPageId() + DetectionCommunicateConstant.SOURCE);
SocketManager.removeUser(param.getUserPageId() + DetectionCommunicateConstant.DEV);
try {
Thread.sleep(2000);
@@ -54,5 +54,4 @@ public class DetectionCommunicateUtil {
}
}

View File

@@ -64,8 +64,10 @@ public interface IPqReportService extends IService<PqReport> {
void generateReport(DevReportParam devReportParam);
void downloadReport(DevReportParam devReportParam, HttpServletResponse response);
/**
* 设备归档操作
*
@@ -73,4 +75,7 @@ public interface IPqReportService extends IService<PqReport> {
* @return 归档成功返回true否则返回false
*/
boolean documented(List<String> id);
}

View File

@@ -8,7 +8,12 @@ import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -17,8 +22,18 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.constant.PatternRegex;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.BinaryDataConverter;
import com.njcn.common.utils.images.ImageConverter;
import com.njcn.gather.detection.handler.SocketDevResponseService;
import com.njcn.gather.detection.pojo.constant.DetectionCommunicateConstant;
import com.njcn.gather.detection.pojo.enums.DetectionCodeEnum;
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
import com.njcn.gather.detection.pojo.param.PreDetectionParam;
import com.njcn.gather.detection.pojo.vo.DetectionData;
import com.njcn.gather.detection.pojo.vo.SocketMsg;
import com.njcn.gather.detection.util.socket.SocketManager;
import com.njcn.gather.detection.util.socket.cilent.NettyClient;
import com.njcn.gather.detection.util.socket.cilent.NettyDevClientHandler;
import com.njcn.gather.device.mapper.PqDevMapper;
import com.njcn.gather.device.pojo.enums.CheckStateEnum;
import com.njcn.gather.device.pojo.enums.DevReportStateEnum;
@@ -35,7 +50,6 @@ import com.njcn.gather.report.pojo.constant.PowerConstant;
import com.njcn.gather.report.pojo.constant.ReportConstant;
import com.njcn.gather.report.pojo.enums.*;
import com.njcn.gather.report.pojo.param.ReportParam;
import com.njcn.gather.report.pojo.po.CellEntity;
import com.njcn.gather.report.pojo.po.PqReport;
import com.njcn.gather.report.pojo.result.SingleTestResult;
import com.njcn.gather.report.pojo.vo.PqReportVO;
@@ -57,7 +71,10 @@ import com.njcn.gather.system.dictionary.pojo.po.DictData;
import com.njcn.gather.system.dictionary.service.IDictDataService;
import com.njcn.gather.type.pojo.po.DevType;
import com.njcn.gather.type.service.IDevTypeService;
import com.njcn.http.util.RestTemplateUtil;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.HttpServletUtil;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
@@ -65,24 +82,34 @@ import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBElement;
import java.awt.*;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferUShort;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -120,6 +147,16 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
private final ISysTestConfigService sysTestConfigService;
@Autowired
private RestTemplateUtil restTemplateUtil;
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, 8, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
// 队列满时由主线程执行
new ThreadPoolExecutor.CallerRunsPolicy()
);
private final long FILE_SIZE_LIMIT = 5 * 1024 * 1024;
@Override
@@ -496,6 +533,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
}
}
/**
* 根据设备类型生成报告
* 注:该方法目前仅支持楼下出厂检测场景,属于模板占位符替换方式,后期可能会有调整
@@ -537,7 +575,8 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
String dirPath = reportPath;
// 确保目录存在
ensureDirectoryExists(dirPath);
FileOutputStream out = new FileOutputStream(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx"));
String reportFullPath = dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx");
FileOutputStream out = new FileOutputStream(reportFullPath);
// 4. 保存新的Word文档
try {
baseModelDocument.write(out);
@@ -546,7 +585,16 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
}
out.close();
this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId());
Future<?> future = executor.submit(() -> {
this.updateDevAndPlanState(devReportParam.getDevId(), pqDevVO.getCreateId() + ".docx");
});
try {
future.get();
} catch (Exception e) {
log.error("检测报告上云异常,异常为:"+e.getMessage());
}
sendReportToCloud(pqDevVO.getIp(), reportFullPath, pqDevVO.getCreateId() + ".docx");
} catch (IOException e) {
log.error(ReportResponseEnum.GENERATE_REPORT_ERROR.getMessage(), e);
throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR);
@@ -554,6 +602,86 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
});
}
@Value("${socket.device.ip}")
private String ip;
@Value("${socket.device.port}")
private Integer port;
private final SocketDevResponseService socketDevResponseService;
/**
* 处理检测报告上传云服务器并生成二维码下装到装置
* 做成异步执行
*
* @param devIp 设备IP
* @param reportFullPath 检测报告本地全路径
* @param reportName 检测报告名称
*/
public void sendReportToCloud(String devIp, String reportFullPath, String reportName) {
// String url = "http://pqmcc.com:8060/api/file";
String url = "http://127.0.0.1:18082/api/file";
devIp = "192.168.1.239";
// 将文件上传至目标服务器
File file = new File(reportFullPath);
try {
ResponseEntity<String> responseEntity = restTemplateUtil.uploadFile(url + "/upload", file);
if (responseEntity.getStatusCode().is2xxSuccessful()) {
// 上传没问题后拼接url生成二维码并将二维码转为bin格式文件传递给设备通讯模块
String qrUrl = url + "/download/" + reportName;
BufferedImage bufferedImage = QrCodeUtil.generate(qrUrl, 148, 148);
// 将 BufferedImage 转换为单色图像
BufferedImage monoImage = new BufferedImage(148, 148, BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g2d = monoImage.createGraphics();
g2d.drawImage(bufferedImage, 0, 0, null);
g2d.dispose();
// 3. 【关键修正】创建一个新的1-bit单色图像并将原始图像绘制上去以强制转换为单色位图
BufferedImage monochromeImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
monochromeImage.getGraphics().drawImage(bufferedImage, 0, 0, null);
// 4. 将单色图像在内存中编码为完整的BMP文件流
byte[] finalBinData = ImageConverter.convertToBinFormat(bufferedImage);
String base64String = Base64.getEncoder().encodeToString(finalBinData);
System.out.println("二维码base64数据为" + base64String);
// 组装设备通讯模块的参数
SocketMsg<String> sendFileMsg = new SocketMsg<>();
sendFileMsg.setOperateCode(SourceOperateCodeEnum.FTP_SEND_01.getValue());
sendFileMsg.setRequestId(SourceOperateCodeEnum.FTP_SEND_01.getValue());
// 组装业务数据
JSONObject data = new JSONObject();
data.set("name", "njcn");
data.set("password", "Pqs@12345678");
data.set("port", "21");
data.set("path", "ftp://" + devIp + "/etc/temp.bin");
data.set("binData", base64String);
sendFileMsg.setData(data.toString());
String msg = JSON.toJSONString(sendFileMsg);
Channel channel = SocketManager.getChannelByUserId("cdf" + DetectionCommunicateConstant.DEV);
if (Objects.isNull(channel) || !channel.isActive()) {
// 进行源通信连接
PreDetectionParam preDetectionParam = new PreDetectionParam();
preDetectionParam.setUserPageId("cdf");
preDetectionParam.setSendWebMsg(false);
NettyClient.socketClient(ip, port, preDetectionParam, msg, new NettyDevClientHandler(preDetectionParam, socketDevResponseService));
} else {
channel.writeAndFlush(msg + "\n");
}
}
} catch (Exception e) {
// 进行日志记录入口
System.out.println("异常为:" + e.getMessage());
}
}
/**
* 根据计划绑定的报告模板生成报告
* 注:该方法目前属于同用信息占位符替换,数据页为面向对象动态填充拼凑方式

View File

@@ -77,8 +77,8 @@ Dip:
Flicker:
waveFluType: SQU
waveType: CPM
waveFluType: CPM
waveType: SQU
fDutyCycle: 50f
log:

View File

@@ -3,13 +3,18 @@ package com.njcn;
import com.njcn.gather.EntranceApplication;
import com.njcn.gather.report.pojo.DevReportParam;
import com.njcn.gather.report.service.IPqReportService;
import com.njcn.http.util.RestTemplateUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import java.io.File;
import java.util.HashMap;
/**
* @author hongawen
@@ -24,14 +29,18 @@ public class BaseJunitTest {
@Autowired
private IPqReportService pqReportService;
@Autowired
private RestTemplateUtil restTemplateUtil;
@Test
public void test() {
DevReportParam devReportParam = new DevReportParam();
devReportParam.setPlanId("ad3df9e4a90b4c3c8ce7d21a84ce6f59");
devReportParam.setPlanCode("31");
devReportParam.setScriptId("810e4050e1d445e3542c998a077a263a");
devReportParam.setDevId("a46349a3b3cf4789a6b82690a6076afd");
pqReportService.generateReport(devReportParam);
File file = new File("D:\\report\\PQS_882B4\\5555.docx");
try{
ResponseEntity<String> stringResponseEntity = restTemplateUtil.uploadFile("http://localhost:18082/api/file/upload",file);
}catch (Exception runtimeException){
System.out.println(runtimeException.getMessage());
}
}
}