Compare commits

..

2 Commits

Author SHA1 Message Date
lcj
67ff23e048 [add] 项目id校验拦截器 2025-07-08 09:27:48 +08:00
lcj
0f9e37b1a8 [update] 修改 2025-07-07 20:01:05 +08:00
26 changed files with 513 additions and 46 deletions

View File

@ -187,13 +187,14 @@ api-decrypt:
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc: springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs: api-docs:
# 是否开启接口文档 # 是否开启接口文档
enabled: true enabled: true
swagger-ui: path: /v3/api-docs
path: /swagger-ui.html # 明确Swagger UI路径
# 持久化认证数据
persistAuthorization: false
info: info:
# 标题 # 标题
title: '标题:${ruoyi.name}多租户管理系统_接口文档' title: '标题:${ruoyi.name}多租户管理系统_接口文档'
@ -245,7 +246,11 @@ springdoc:
packages-to-scan: org.dromara.cory packages-to-scan: org.dromara.cory
- group: 20.代码生成模块 - group: 20.代码生成模块
packages-to-scan: org.dromara.generator packages-to-scan: org.dromara.generator
# knife4j的增强配置不需要增强可以不配
knife4j:
enable: true
setting:
language: zh_cn
# 防止XSS攻击 # 防止XSS攻击
xss: xss:

View File

@ -0,0 +1,39 @@
package org.dromara.test;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.utils.PdfBoxQrCodeGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
/**
* @author lcj
* @date 2025/7/7 10:13
*/
@Slf4j
@SpringBootTest
public class PDFTest {
@Test
void test() {
String srcPdf = "http://58.17.134.85:9000/xinnengyuan-dev/2025/07/07/146cb913cb4841eb9944463b762cba53.pdf"; // 原始PDF
String destPdf = "output.pdf"; // 输出PDF
Map<String, Object> params = new HashMap<>();
params.put("版本:", "1.0");
params.put("文件名:", "绝对哦啊手机号丢啊");
params.put("文件类型:", "蓝图");
String qrText = "fdas1.0 dasasd saddsa";
String qrPath = "qrcode.png";
byte[] bytes = PdfBoxQrCodeGenerator.generateQRCodeBytes(qrText, 200, 200);
try {
PdfBoxQrCodeGenerator.addQRCodeToPDF(srcPdf, destPdf, bytes, 1, 1510, 900); // 页码从1开始坐标单位是 pt约1/72英寸
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("二维码添加成功!");
}
}

View File

@ -26,6 +26,11 @@
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId> <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.github.therapi</groupId> <groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId> <artifactId>therapi-runtime-javadoc</artifactId>
@ -36,6 +41,12 @@
<artifactId>jackson-module-kotlin</artifactId> <artifactId>jackson-module-kotlin</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -26,6 +26,11 @@
<artifactId>ruoyi-common-satoken</artifactId> <artifactId>ruoyi-common-satoken</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<!-- dynamic-datasource 多数据源--> <!-- dynamic-datasource 多数据源-->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>

View File

@ -1,5 +1,6 @@
package org.dromara.common.mybatis.handler; package org.dromara.common.mybatis.handler;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
* @author Lion Li * @author Lion Li
*/ */
@Slf4j @Slf4j
@Hidden
@RestControllerAdvice @RestControllerAdvice
public class MybatisExceptionHandler { public class MybatisExceptionHandler {

View File

@ -22,6 +22,11 @@
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<!--redisson--> <!--redisson-->
<dependency> <dependency>
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>

View File

@ -2,6 +2,7 @@ package org.dromara.common.redis.handler;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import com.baomidou.lock.exception.LockFailureException; import com.baomidou.lock.exception.LockFailureException;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
* @author AprilWind * @author AprilWind
*/ */
@Slf4j @Slf4j
@Hidden
@RestControllerAdvice @RestControllerAdvice
public class RedisExceptionHandler { public class RedisExceptionHandler {

View File

@ -24,6 +24,11 @@
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ --> <!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>

View File

@ -4,6 +4,7 @@ import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException; import cn.dev33.satoken.exception.NotRoleException;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
* @author Lion Li * @author Lion Li
*/ */
@Slf4j @Slf4j
@Hidden
@RestControllerAdvice @RestControllerAdvice
public class SaTokenExceptionHandler { public class SaTokenExceptionHandler {

View File

@ -28,6 +28,11 @@
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,6 +1,7 @@
package org.dromara.common.sms.handler; package org.dromara.common.sms.handler;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
* @author AprilWind * @author AprilWind
*/ */
@Slf4j @Slf4j
@Hidden
@RestControllerAdvice @RestControllerAdvice
public class SmsExceptionHandler { public class SmsExceptionHandler {

View File

@ -26,6 +26,11 @@
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<!-- SpringBoot Web容器 --> <!-- SpringBoot Web容器 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -3,6 +3,7 @@ package org.dromara.common.web.handler;
import cn.hutool.core.text.AntPathMatcher; import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus; import cn.hutool.http.HttpStatus;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolation;
@ -34,6 +35,7 @@ import java.io.IOException;
* @author Lion Li * @author Lion Li
*/ */
@Slf4j @Slf4j
@Hidden
@RestControllerAdvice @RestControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {

View File

@ -16,8 +16,6 @@
</description> </description>
<dependencies> <dependencies>
<!-- word转pdf转图片 --> <!-- word转pdf转图片 -->
@ -62,12 +60,38 @@
<version>2.0.29</version> <version>2.0.29</version>
</dependency> </dependency>
<!-- word 模版导出 poi-tl 模板引擎 -->
<dependency> <dependency>
<groupId>com.deepoove</groupId> <groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId> <artifactId>poi-tl</artifactId>
<version>1.12.2</version> <!-- 建议使用最新版本 --> <version>1.12.2</version> <!-- 建议使用最新版本 -->
</dependency> </dependency>
<!-- 在pdf上生成二维码 -->
<!-- 支持中文字体 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- iText -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
<!-- ZXing -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 通用工具--> <!-- 通用工具-->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>

View File

@ -0,0 +1,37 @@
package org.dromara.common.config;
import jakarta.annotation.Resource;
import lombok.Data;
import org.dromara.common.interceptor.ValidProjectInterceptor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author lcj
* @date 2025/7/8 9:06
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "security")
public class WebMvcConfig implements WebMvcConfigurer {
@Resource
private ValidProjectInterceptor validProjectInterceptor;
/**
* 排除路径
*/
private List<String> excludes;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(validProjectInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludes)
.excludePathPatterns("/resource/sse/**", "/auth/**", "/system/user/**", "/project/projectRelevancy/login/list", "/system/menu/getRouters");
}
}

View File

@ -0,0 +1,39 @@
package org.dromara.common.interceptor;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.project.service.IBusProjectService;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* @author lcj
* @date 2025/7/7 19:57
*/
@Slf4j
@Component
public class ValidProjectInterceptor implements HandlerInterceptor {
@Resource
private IBusProjectService projectService;
// 请求前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String projectId = request.getHeader("projectId");
Long userId = LoginHelper.getUserId();
if (StringUtils.isBlank(projectId) || userId == null) {
throw new ServiceException("无访问权限", HttpStatus.FORBIDDEN);
}
projectService.validAuth(Long.valueOf(projectId), userId);
// 返回 true 表示继续执行false 则请求被终止
return true;
}
}

View File

@ -0,0 +1,142 @@
package org.dromara.common.utils;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author lcj
* @date 2025/7/7 9:56
*/
public class PdfBoxQrCodeGenerator {
/**
* 生成二维码图片并返回路径
*
* @param text 二维码文本
* @param width 二维码宽度
* @param height 二维码高度
* @param outputPath 二维码图片保存路径
* @return 二维码图片保存路径
*/
public static String generateQRCodeImage(String text, int width, int height, String outputPath) throws Exception {
BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height);
MatrixToImageWriter.writeToPath(bitMatrix, "PNG", new File(outputPath).toPath());
return outputPath;
}
/**
* 获取二维码图片字节数组
*
* @param text 二维码文本
* @param width 二维码宽度
* @param height 二维码高度
* @return 二维码图片字节数组
*/
public static byte[] generateQRCodeBytes(String text, int width, int height) {
BufferedImage image = QrCodeUtil.generate(text, width, height);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImgUtil.write(image, ImgUtil.IMAGE_TYPE_PNG, out);
return out.toByteArray();
}
/**
* 获取二维码图片字节数组
*
* @param text 二维码文本
* @return 二维码图片字节数组
*/
public static byte[] generateQRCodeBytes(String text) {
return generateQRCodeBytes(text, 200, 200);
}
/**
* 在PDF指定位置添加二维码
*
* @param srcPdf 原PDF文件路径
* @param destPdf 新PDF文件路径
* @param qrImagePath 二维码图片路径
* @param pageNum 页码
* @param x 坐标
* @param y 坐标
*/
public static void addQRCodeToPDF(String srcPdf, String destPdf, String qrImagePath, int pageNum, float x, float y) throws IOException, DocumentException {
PdfReader reader = new PdfReader(srcPdf);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf));
PdfContentByte content = stamper.getOverContent(pageNum);
Image image = Image.getInstance(qrImagePath);
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
image.scaleAbsolute(100, 100); // 设置二维码大小
content.addImage(image);
stamper.close();
reader.close();
}
/**
* 在PDF指定位置添加二维码
*
* @param srcPdf 原PDF文件路径
* @param destPdf 新PDF文件路径
* @param qrCodeBytes 二维码图片字节数组
* @param pageNum 页码
* @param x 坐标
* @param y 坐标
*/
public static void addQRCodeToPDF(String srcPdf, String destPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException {
PdfReader reader = new PdfReader(srcPdf);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf));
PdfContentByte content = stamper.getOverContent(pageNum);
Image image = Image.getInstance(qrCodeBytes);
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
image.scaleAbsolute(100, 100); // 设置二维码大小
content.addImage(image);
stamper.close();
reader.close();
}
/**
* 在PDF指定位置添加二维码并返回数据流
*
* @param srcPdf 原PDF文件路径
* @param qrCodeBytes 二维码图片字节数组
* @param pageNum 页码
* @param x 坐标
* @param y 坐标
* @return 插入二维码后的PDF文件流
*/
public static ByteArrayOutputStream addQRCodeToPDF(String srcPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException {
PdfReader reader = new PdfReader(srcPdf);
ByteArrayOutputStream pdfOut = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, pdfOut);
PdfContentByte content = stamper.getOverContent(pageNum);
Image image = Image.getInstance(qrCodeBytes);
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
image.scaleAbsolute(100, 100); // 设置二维码大小
content.addImage(image);
stamper.close();
reader.close();
return pdfOut;
}
}

View File

@ -1,28 +1,29 @@
package org.dromara.cory.controller; package org.dromara.cory.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*; import cn.dev33.satoken.annotation.SaMode;
import org.springframework.validation.annotation.Validated; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.cory.domain.vo.BusContactformtemplateVo;
import org.dromara.cory.domain.bo.BusContactformtemplateBo;
import org.dromara.cory.service.IBusContactformtemplateService;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.cory.domain.bo.BusContactformtemplateBo;
import org.dromara.cory.domain.vo.BusContactformtemplateVo;
import org.dromara.cory.service.IBusContactformtemplateService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/** /**
* 联系单模板 * 联系单模板
* *
@ -47,9 +48,9 @@ public class BusContactformtemplateController extends BaseController {
} }
/** /**
* 查询联系单模板列表 * 查询联系单模板列表(不分页)
*/ */
@SaCheckPermission("cory:contactformtemplate:listNoPage") @SaCheckPermission(value = {"cory:contactformtemplate:listNoPage", "cory:contactformtemplate:list"}, mode = SaMode.OR)
@GetMapping("/listNoPage") @GetMapping("/listNoPage")
public R<List<BusContactformtemplateVo>> listNoPage(BusContactformtemplateBo bo) { public R<List<BusContactformtemplateVo>> listNoPage(BusContactformtemplateBo bo) {
return R.ok(busContactformtemplateService.queryList(bo)); return R.ok(busContactformtemplateService.queryList(bo));
@ -75,7 +76,7 @@ public class BusContactformtemplateController extends BaseController {
@SaCheckPermission("cory:contactformtemplate:query") @SaCheckPermission("cory:contactformtemplate:query")
@GetMapping("/{id}") @GetMapping("/{id}")
public R<BusContactformtemplateVo> getInfo(@NotNull(message = "主键不能为空") public R<BusContactformtemplateVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) { @PathVariable Long id) {
return R.ok(busContactformtemplateService.queryById(id)); return R.ok(busContactformtemplateService.queryById(id));
} }
@ -89,7 +90,7 @@ public class BusContactformtemplateController extends BaseController {
public R<Void> add( public R<Void> add(
BusContactformtemplateBo bo, BusContactformtemplateBo bo,
@RequestPart("file") MultipartFile file) { @RequestPart("file") MultipartFile file) {
return toAjax(busContactformtemplateService.insertByBo(bo,file)); return toAjax(busContactformtemplateService.insertByBo(bo, file));
} }

View File

@ -1,16 +1,13 @@
package org.dromara.cory.domain.bo; package org.dromara.cory.domain.bo;
import org.dromara.cory.domain.BusContactformtemplate; import com.baomidou.mybatisplus.annotation.TableId;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*; import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.translation.annotation.Translation; import org.dromara.cory.domain.BusContactformtemplate;
import org.dromara.common.translation.constant.TransConstant;
import org.springframework.web.multipart.MultipartFile; import java.util.List;
/** /**
* 联系单模板业务对象 bus_contactformtemplate * 联系单模板业务对象 bus_contactformtemplate
@ -22,6 +19,12 @@ import org.springframework.web.multipart.MultipartFile;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@AutoMapper(target = BusContactformtemplate.class, reverseConvertGenerate = false) @AutoMapper(target = BusContactformtemplate.class, reverseConvertGenerate = false)
public class BusContactformtemplateBo extends BaseEntity { public class BusContactformtemplateBo extends BaseEntity {
/**
* 自增ID
*/
@TableId(value = "id")
private Long id;
/** /**
* 项目ID * 项目ID
@ -49,4 +52,8 @@ public class BusContactformtemplateBo extends BaseEntity {
*/ */
private String remark; private String remark;
/**
* 根据ids查询数据in
*/
private List<Long> ids;
} }

View File

@ -1,5 +1,6 @@
package org.dromara.cory.service.impl; package org.dromara.cory.service.impl;
import cn.hutool.core.collection.CollUtil;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.docx4j.openpackaging.exceptions.Docx4JException; import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.MapstructUtils;
@ -92,6 +93,7 @@ public class BusContactformtemplateServiceImpl implements IBusContactformtemplat
LambdaQueryWrapper<BusContactformtemplate> lqw = Wrappers.lambdaQuery(); LambdaQueryWrapper<BusContactformtemplate> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(BusContactformtemplate::getId); lqw.orderByAsc(BusContactformtemplate::getId);
lqw.like(StringUtils.isNotBlank(bo.getName()), BusContactformtemplate::getName, bo.getName()); lqw.like(StringUtils.isNotBlank(bo.getName()), BusContactformtemplate::getName, bo.getName());
lqw.in(CollUtil.isNotEmpty(bo.getIds()), BusContactformtemplate::getId, bo.getIds());
// lqw.eq(StringUtils.isNotBlank(bo.getPath()), BusContactformtemplate::getPath, bo.getPath()); // lqw.eq(StringUtils.isNotBlank(bo.getPath()), BusContactformtemplate::getPath, bo.getPath());
// lqw.eq(StringUtils.isNotBlank(bo.getThumbnail()), BusContactformtemplate::getThumbnail, bo.getThumbnail()); // lqw.eq(StringUtils.isNotBlank(bo.getThumbnail()), BusContactformtemplate::getThumbnail, bo.getThumbnail());
return lqw; return lqw;
@ -135,9 +137,10 @@ public class BusContactformtemplateServiceImpl implements IBusContactformtemplat
*/ */
@Override @Override
public Boolean updateByBo(BusContactformtemplateBo bo) { public Boolean updateByBo(BusContactformtemplateBo bo) {
BusContactformtemplate update = MapstructUtils.convert(bo, BusContactformtemplate.class); BusContactformtemplate busContactformtemplate = new BusContactformtemplate();
validEntityBeforeSave(update); busContactformtemplate.setId(bo.getId());
return baseMapper.updateById(update) > 0; busContactformtemplate.setName(bo.getName());
return baseMapper.updateById(busContactformtemplate) > 0;
} }
/** /**

View File

@ -69,6 +69,11 @@ public class DesDrawing extends BaseEntity {
*/ */
private String originalName; private String originalName;
/**
* 原文件id
*/
private Long originalFileId;
/** /**
* 是否最新0否 1是 * 是否最新0否 1是
*/ */

View File

@ -13,6 +13,7 @@ import org.dromara.design.domain.vo.drawing.DesDrawingVo;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* 图纸管理Service接口 * 图纸管理Service接口
@ -94,4 +95,12 @@ public interface IDesDrawingService extends IService<DesDrawing> {
* @return 图纸管理对象视图 * @return 图纸管理对象视图
*/ */
Page<DesDrawingVo> getVoPage(Page<DesDrawing> drawingPage); Page<DesDrawingVo> getVoPage(Page<DesDrawing> drawingPage);
/**
* 异步添加二维码到PDF
*
* @param drawing 图纸管理对象
* @return 是否添加成功
*/
CompletableFuture<Boolean> addQRCodeToPDF(DesDrawing drawing);
} }

View File

@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itextpdf.text.DocumentException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
@ -20,6 +21,7 @@ import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.utils.PdfBoxQrCodeGenerator;
import org.dromara.design.domain.DesDrawing; import org.dromara.design.domain.DesDrawing;
import org.dromara.design.domain.dto.drawing.DesDrawingCreateReq; import org.dromara.design.domain.dto.drawing.DesDrawingCreateReq;
import org.dromara.design.domain.dto.drawing.DesDrawingQueryReq; import org.dromara.design.domain.dto.drawing.DesDrawingQueryReq;
@ -33,11 +35,19 @@ import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -60,6 +70,10 @@ public class DesDrawingServiceImpl extends ServiceImpl<DesDrawingMapper, DesDraw
@Resource @Resource
private WorkflowService workflowService; private WorkflowService workflowService;
@Lazy
@Resource
private IDesDrawingService self;
/** /**
* 查询图纸管理 * 查询图纸管理
* *
@ -135,6 +149,7 @@ public class DesDrawingServiceImpl extends ServiceImpl<DesDrawingMapper, DesDraw
} }
desDrawing.setFileName(name); desDrawing.setFileName(name);
desDrawing.setFileUrl(fileUrl); desDrawing.setFileUrl(fileUrl);
desDrawing.setOriginalFileId(fileUrl);
desDrawing.setFileSuffix(ossVo.getFileSuffix()); desDrawing.setFileSuffix(ossVo.getFileSuffix());
desDrawing.setVersionNumber(req.getVersionNumber()); desDrawing.setVersionNumber(req.getVersionNumber());
desDrawing.setFileType(fileType); desDrawing.setFileType(fileType);
@ -174,6 +189,16 @@ public class DesDrawingServiceImpl extends ServiceImpl<DesDrawingMapper, DesDraw
} }
DesDrawing desDrawing = new DesDrawing(); DesDrawing desDrawing = new DesDrawing();
BeanUtils.copyProperties(req, desDrawing); BeanUtils.copyProperties(req, desDrawing);
if (req.getFileUrl() != null && !req.getFileUrl().equals(oldDrawing.getFileUrl())) {
Long fileUrl = req.getFileUrl();
SysOssVo ossVo = ossService.getById(fileUrl);
// 数据校验
if (ObjectUtils.isEmpty(ossVo)) {
throw new ServiceException("图纸文件不能为空", HttpStatus.BAD_REQUEST);
}
desDrawing.setFileUrl(fileUrl);
desDrawing.setOriginalFileId(fileUrl);
}
boolean result = this.updateById(desDrawing); boolean result = this.updateById(desDrawing);
if (!result) { if (!result) {
throw new ServiceException("修改图纸失败", HttpStatus.ERROR); throw new ServiceException("修改图纸失败", HttpStatus.ERROR);
@ -292,6 +317,16 @@ public class DesDrawingServiceImpl extends ServiceImpl<DesDrawingMapper, DesDraw
drawing.setStatus(BusinessStatusEnum.WAITING.getStatus()); drawing.setStatus(BusinessStatusEnum.WAITING.getStatus());
} }
this.updateById(drawing); this.updateById(drawing);
// 如果审核已完成
if (BusinessStatusEnum.FINISH.getStatus().equals(processEvent.getStatus())) {
log.info("图纸审核任务已完成: {}", processEvent);
self.addQRCodeToPDF(drawing)
.thenAccept(result -> log.info("图纸[{}-{}]添加二维码成功", drawing.getFileName(), drawing.getId()))
.exceptionally(ex -> {
log.error("图纸[{}-{}]添加二维码失败", drawing.getFileName(), drawing.getId(), ex);
return null;
});
}
} }
/** /**
@ -328,4 +363,36 @@ public class DesDrawingServiceImpl extends ServiceImpl<DesDrawingMapper, DesDraw
this.removeById(drawing.getId()); this.removeById(drawing.getId());
} }
/**
* 异步添加二维码到PDF
*
* @param drawing 图纸管理对象
* @return 是否添加成功
*/
@Async
@Override
public CompletableFuture<Boolean> addQRCodeToPDF(DesDrawing drawing) {
Long fileUrl = drawing.getOriginalFileId();
if (fileUrl == null) {
return CompletableFuture.completedFuture(false);
}
SysOssVo ossVo = ossService.getById(fileUrl);
// 整合二维码需要显示的数据
String params = "ID[" + drawing.getId() + "] finish";
byte[] bytes = PdfBoxQrCodeGenerator.generateQRCodeBytes(params);
try {
ByteArrayOutputStream baos = PdfBoxQrCodeGenerator.addQRCodeToPDF(ossVo.getUrl(), bytes, 1, 1510, 900);
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String originalName = drawing.getOriginalName();
String contentType = fileNameMap.getContentTypeFor(originalName);
SysOssVo upload = ossService.upload(new ByteArrayInputStream(baos.toByteArray()), originalName, contentType, baos.size());
drawing.setFileUrl(upload.getOssId());
} catch (IOException | DocumentException e) {
log.error("图纸管理 => 审核结束,向文件添加二维码失败", e);
return CompletableFuture.completedFuture(false);
}
this.updateById(drawing);
return CompletableFuture.completedFuture(true);
}
} }

View File

@ -258,7 +258,7 @@ public class DesSpecialSchemeServiceImpl extends ServiceImpl<DesSpecialSchemeMap
* *
* @param processEvent 参数 * @param processEvent 参数
*/ */
@EventListener(condition = "#processEvent.flowCode == 'specialScheme'") @EventListener(condition = "#processEvent.flowCode.endsWith('specialScheme')")
public void processHandler(ProcessEvent processEvent) { public void processHandler(ProcessEvent processEvent) {
log.info("图纸审核任务执行了{}", processEvent.toString()); log.info("图纸审核任务执行了{}", processEvent.toString());
DesSpecialScheme specialScheme = this.getById(Convert.toLong(processEvent.getBusinessId())); DesSpecialScheme specialScheme = this.getById(Convert.toLong(processEvent.getBusinessId()));
@ -279,7 +279,7 @@ public class DesSpecialSchemeServiceImpl extends ServiceImpl<DesSpecialSchemeMap
* *
* @param processTaskEvent 参数 * @param processTaskEvent 参数
*/ */
@EventListener(condition = "#processTaskEvent.flowCode == 'specialScheme'") @EventListener(condition = "#processTaskEvent.flowCode.endsWith('specialScheme')")
public void processTaskHandler(ProcessTaskEvent processTaskEvent) { public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
log.info("图纸审核任务创建了{}", processTaskEvent.toString()); log.info("图纸审核任务创建了{}", processTaskEvent.toString());
} }
@ -291,7 +291,7 @@ public class DesSpecialSchemeServiceImpl extends ServiceImpl<DesSpecialSchemeMap
* *
* @param processDeleteEvent 参数 * @param processDeleteEvent 参数
*/ */
@EventListener(condition = "#processDeleteEvent.flowCode == 'specialScheme'") @EventListener(condition = "#processDeleteEvent.flowCode.endsWith('specialScheme')")
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
log.info("监听删除流程事件,图纸审核任务执行了{}", processDeleteEvent.toString()); log.info("监听删除流程事件,图纸审核任务执行了{}", processDeleteEvent.toString());
DesSpecialScheme specialScheme = this.getById(Convert.toLong(processDeleteEvent.getBusinessId())); DesSpecialScheme specialScheme = this.getById(Convert.toLong(processDeleteEvent.getBusinessId()));

View File

@ -81,7 +81,18 @@ public interface ISysOssService {
SysOssUploadVo uploadFileUrlWithNoSave(String fileUrl, String filePath); SysOssUploadVo uploadFileUrlWithNoSave(String fileUrl, String filePath);
/** /**
* 通过 url 上传到对象存储服务,不保存文件信息到数据库 * 通过输入流上传到对象存储服务,不保存文件信息到数据库
*
* @param inputStream 要上传的文件输入流
* @param originalFileName 文件名
* @param contentType 文件类型
* @param length 文件长度
* @return 上传成功后的 SysOssVo 对象,包含文件信息
*/
SysOssVo upload(InputStream inputStream, String originalFileName, String contentType, long length);
/**
* 通过输入流上传到对象存储服务,不保存文件信息到数据库
* *
* @param inputStream 要上传的文件输入流 * @param inputStream 要上传的文件输入流
* @param filePath 文件路径 * @param filePath 文件路径
@ -119,10 +130,11 @@ public interface ISysOssService {
/** /**
* MinioFileName 获取minio的即将存储文件的路径 * MinioFileName 获取minio的即将存储文件的路径
*
* @param prefix 前缀举例prefix * @param prefix 前缀举例prefix
* @param file 为了获取后缀(举例:.png * @param file 为了获取后缀(举例:.png
* @return 返回全路径 * @return 返回全路径
*/ */
String minioFileName (String prefix, MultipartFile file); String minioFileName(String prefix, MultipartFile file);
} }

View File

@ -291,6 +291,36 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
return uploadVo; return uploadVo;
} }
/**
* 通过输入流上传到对象存储服务,不保存文件信息到数据库
*
* @param inputStream 要上传的文件输入流
* @param originalFileName 文件名
* @param contentType 文件类型
* @param length 文件长度
* @return 上传成功后的 SysOssVo 对象,包含文件信息
*/
@Override
public SysOssVo upload(InputStream inputStream, String originalFileName, String contentType, long length) {
String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
UploadResult uploadResult;
// 上传
OssClient storage = OssFactory.instance();
try {
// 如果 length 不确定(如传 -1就读取整个流算长度
if (length <= 0) {
byte[] bytes = IoUtil.readBytes(inputStream);
length = bytes.length;
inputStream = new ByteArrayInputStream(bytes); // 重置 InputStream
}
uploadResult = storage.uploadSuffix(inputStream, suffix, length, contentType);
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
// 保存文件信息
return buildResultEntity(originalFileName, suffix, storage.getConfigKey(), uploadResult);
}
/** /**
* 通过 url 上传到对象存储服务,不保存文件信息到数据库 * 通过 url 上传到对象存储服务,不保存文件信息到数据库
* *
@ -390,12 +420,13 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
/** /**
* MinioFileName 获取minio的即将存储文件的路径 * MinioFileName 获取minio的即将存储文件的路径
*
* @param prefix 前缀举例prefix * @param prefix 前缀举例prefix
* @param file 为了获取后缀(举例:.png * @param file 为了获取后缀(举例:.png
* @return 返回全路径 * @return 返回全路径
*/ */
@Override @Override
public String minioFileName (String prefix, MultipartFile file) { public String minioFileName(String prefix, MultipartFile file) {
String originalFilename = file.getOriginalFilename(); String originalFilename = file.getOriginalFilename();
String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length()); String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length());
OssClient storage = OssFactory.instance(); OssClient storage = OssFactory.instance();