打印报告功能
This commit is contained in:
parent
61f7e145b0
commit
b23efa4fad
@ -1,17 +1,19 @@
|
||||
package com.czlis.common.utils.file;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.czlis.common.config.RuoYiConfig;
|
||||
import com.czlis.common.constant.Constants;
|
||||
import com.czlis.common.utils.StringUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* 图片处理工具类
|
||||
@ -95,4 +97,227 @@ public class ImageUtils
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成图片到服务的static目录(Spring Boot场景)
|
||||
* @param imageBytes 图片二进制数据
|
||||
* @param staticSubDir static下的子目录(如"report_imgs/",避免文件混乱)
|
||||
* @param fileName 自定义文件名(如"lab_report_20240520.jpg",建议加唯一标识)
|
||||
* @return 生成的文件对象(包含static目录下的路径)
|
||||
* @throws IOException 路径获取/文件写入失败
|
||||
*/
|
||||
public static File generateToStaticDir(byte[] imageBytes, String staticSubDir, String fileName) throws IOException {
|
||||
// 1. 校验入参
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据不能为null");
|
||||
Objects.requireNonNull(staticSubDir, "static子目录不能为null");
|
||||
Objects.requireNonNull(fileName, "文件名不能为null");
|
||||
if (!fileName.contains(".")) {
|
||||
throw new IllegalArgumentException("文件名必须包含后缀(如.jpg/.bmp)");
|
||||
}
|
||||
|
||||
// 2. 获取服务的static目录绝对路径(Spring Boot核心:通过ResourceUtils获取)
|
||||
File staticDir = null;
|
||||
try {
|
||||
// 本地开发环境:target/classes/static(Maven/Gradle构建后路径)
|
||||
// 生产环境(Jar包部署):Jar包内的static目录(需注意只读问题,下文会说明)
|
||||
staticDir = new File(ResourceUtils.getURL("classpath:static").getPath());
|
||||
} catch (FileNotFoundException e) {
|
||||
// 若Jar包部署时获取不到classpath:static(因Jar包内资源无法直接以File形式访问)
|
||||
// 改用服务运行目录下的static(需手动创建)
|
||||
staticDir = new File(System.getProperty("user.dir") + File.separator + "static");
|
||||
}
|
||||
|
||||
// 3. 创建static下的子目录(如static/report_imgs/,避免所有文件堆在static根目录)
|
||||
File targetDir = new File(staticDir, staticSubDir);
|
||||
if (!targetDir.exists()) {
|
||||
boolean mkdirsSuccess = targetDir.mkdirs(); // 递归创建多级目录
|
||||
if (!mkdirsSuccess) {
|
||||
throw new IOException("创建static子目录失败:" + targetDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 检查static目录写入权限
|
||||
if (!targetDir.canWrite()) {
|
||||
throw new IOException("static目录无写入权限:" + targetDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
// 5. 创建目标文件(加唯一标识避免同名覆盖,如在文件名前加UUID)
|
||||
//String uniqueFileName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName;
|
||||
File targetFile = new File(targetDir, fileName);
|
||||
|
||||
// 6. 写入图片数据
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
System.out.println("图片已生成到static目录:" + targetFile.getAbsolutePath());
|
||||
return targetFile;
|
||||
}
|
||||
// 支持的图片格式(文件头标识 + 后缀名映射)
|
||||
private enum ImageFormat {
|
||||
JPG(new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF}, ".jpg"),
|
||||
PNG(new byte[]{(byte) 0x89, (byte) 0x50, (byte) 0x4E, (byte) 0x47}, ".png"),
|
||||
GIF(new byte[]{(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38}, ".gif"),
|
||||
BMP(new byte[]{(byte) 0x42, (byte) 0x4D}, ".bmp"); // BMP格式文件头标识
|
||||
|
||||
private final byte[] fileHeader; // 图片文件头(用于格式校验)
|
||||
private final String suffix; // 对应的文件后缀
|
||||
|
||||
ImageFormat(byte[] fileHeader, String suffix) {
|
||||
this.fileHeader = fileHeader;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
// 根据文件头匹配图片格式
|
||||
public static ImageFormat matchFormat(byte[] data) {
|
||||
if (data == null || data.length < 2) { // 至少需要2字节判断BMP格式
|
||||
return null;
|
||||
}
|
||||
for (ImageFormat format : values()) {
|
||||
// 检查数据长度是否足够
|
||||
if (data.length < format.fileHeader.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean match = true;
|
||||
for (int i = 0; i < format.fileHeader.length; i++) {
|
||||
if (data[i] != format.fileHeader[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心方法:将byte[]二进制数据生成图片临时文件
|
||||
* @param imageBytes 图片二进制数据(必须是JPG/PNG/GIF/BMP格式)
|
||||
* @param tempPrefix 临时文件前缀(如"report_img_",用于区分不同业务的临时文件)
|
||||
* @return 生成的临时图片文件(包含绝对路径,可直接给报告模板引用)
|
||||
* @throws IllegalArgumentException 入参非法(空数据、非图片格式)
|
||||
* @throws IOException 临时文件创建/写入失败
|
||||
*/
|
||||
public static File generateTempImage(byte[] imageBytes, String tempPrefix) throws IllegalArgumentException, IOException {
|
||||
// 1. 入参校验:避免空数据
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据[imageBytes]不能为null");
|
||||
if (imageBytes.length == 0) {
|
||||
throw new IllegalArgumentException("图片二进制数据[imageBytes]长度不能为0");
|
||||
}
|
||||
Objects.requireNonNull(tempPrefix, "临时文件前缀[tempPrefix]不能为null");
|
||||
if (tempPrefix.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("临时文件前缀[tempPrefix]不能为空字符串");
|
||||
}
|
||||
|
||||
// 2. 图片格式校验:确保是支持的图片类型(避免生成无效文件)
|
||||
ImageFormat imageFormat = ImageFormat.matchFormat(imageBytes);
|
||||
if (imageFormat == null) {
|
||||
throw new IllegalArgumentException("不支持的图片格式!仅支持JPG/PNG/GIF/BMP");
|
||||
}
|
||||
|
||||
// 3. 创建临时文件
|
||||
File tempImageFile = File.createTempFile(tempPrefix, imageFormat.suffix);
|
||||
|
||||
// 4. 临时文件安全配置
|
||||
tempImageFile.deleteOnExit();
|
||||
setFileSafePermission(tempImageFile);
|
||||
|
||||
// 5. 写入二进制数据到临时文件
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(
|
||||
new FileOutputStream(tempImageFile, false)
|
||||
)) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
// 6. 二次校验
|
||||
if (!tempImageFile.exists() || tempImageFile.length() != imageBytes.length) {
|
||||
throw new IOException("临时图片文件生成失败!文件大小不匹配或文件未创建");
|
||||
}
|
||||
|
||||
return tempImageFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载方法:指定图片格式(跳过自动校验,适用于已知格式的场景)
|
||||
* @param imageBytes 图片二进制数据
|
||||
* @param tempPrefix 临时文件前缀
|
||||
* @param targetSuffix 目标格式后缀(如".jpg", ".png",必须带".")
|
||||
* @return 临时图片文件
|
||||
* @throws IOException 临时文件操作异常
|
||||
*/
|
||||
public static File generateTempImage(byte[] imageBytes, String tempPrefix, String targetSuffix) throws IOException {
|
||||
// 入参校验
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据[imageBytes]不能为null");
|
||||
Objects.requireNonNull(tempPrefix, "临时文件前缀[tempPrefix]不能为null");
|
||||
Objects.requireNonNull(targetSuffix, "目标格式后缀[targetSuffix]不能为null");
|
||||
if (!targetSuffix.startsWith(".")) {
|
||||
throw new IllegalArgumentException("目标格式后缀必须以'.'开头(如\".jpg\")");
|
||||
}
|
||||
|
||||
// 创建临时文件
|
||||
File tempImageFile = File.createTempFile(tempPrefix, targetSuffix);
|
||||
tempImageFile.deleteOnExit();
|
||||
setFileSafePermission(tempImageFile);
|
||||
|
||||
// 写入数据
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempImageFile))) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
// 校验文件
|
||||
if (!tempImageFile.exists()) {
|
||||
throw new IOException("指定格式的临时图片文件生成失败");
|
||||
}
|
||||
|
||||
return tempImageFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:设置临时文件安全权限(跨平台兼容)
|
||||
*/
|
||||
private static void setFileSafePermission(File file) {
|
||||
if (file == null || !file.exists()) {
|
||||
return;
|
||||
}
|
||||
// Windows系统:通过设置文件属性隐藏
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec("attrib +h " + file.getAbsolutePath());
|
||||
process.waitFor();
|
||||
} catch (Exception e) {
|
||||
System.err.println("临时文件隐藏失败:" + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// Linux/Mac系统:设置权限为"仅当前用户读写"(600权限)
|
||||
file.setReadable(true, true);
|
||||
file.setWritable(true, true);
|
||||
file.setExecutable(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:手动删除临时文件
|
||||
* @param tempFile 临时文件对象
|
||||
* @return 删除成功返回true,失败返回false
|
||||
*/
|
||||
public static boolean deleteTempImage(File tempFile) {
|
||||
if (tempFile == null || !tempFile.exists()) {
|
||||
System.out.println("临时文件不存在,无需删除");
|
||||
return true;
|
||||
}
|
||||
boolean deleted = tempFile.delete();
|
||||
if (deleted) {
|
||||
System.out.println("临时文件删除成功:" + tempFile.getAbsolutePath());
|
||||
} else {
|
||||
System.err.println("临时文件删除失败:" + tempFile.getAbsolutePath());
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,16 +22,8 @@ public class BarCodeParam {
|
||||
private String yq;
|
||||
private String ybh;
|
||||
private String hospitalName;
|
||||
private String pic1;
|
||||
private String pic2;
|
||||
private String pic3;
|
||||
private String pic4;
|
||||
private String pic5;
|
||||
private String pic6;
|
||||
private String pic7;
|
||||
private String pic8;
|
||||
private String pic9;
|
||||
private String pic10;
|
||||
private String pic11;
|
||||
private String pic12;
|
||||
/**
|
||||
* 图片数组
|
||||
*/
|
||||
private String[] pic;
|
||||
}
|
||||
|
||||
@ -1,234 +0,0 @@
|
||||
package com.czlis.interfaceCommon.utils;
|
||||
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ImageUtils {
|
||||
/**
|
||||
* 生成图片到服务的static目录(Spring Boot场景)
|
||||
* @param imageBytes 图片二进制数据
|
||||
* @param staticSubDir static下的子目录(如"report_imgs/",避免文件混乱)
|
||||
* @param fileName 自定义文件名(如"lab_report_20240520.jpg",建议加唯一标识)
|
||||
* @return 生成的文件对象(包含static目录下的路径)
|
||||
* @throws IOException 路径获取/文件写入失败
|
||||
*/
|
||||
public static File generateToStaticDir(byte[] imageBytes, String staticSubDir, String fileName) throws IOException {
|
||||
// 1. 校验入参
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据不能为null");
|
||||
Objects.requireNonNull(staticSubDir, "static子目录不能为null");
|
||||
Objects.requireNonNull(fileName, "文件名不能为null");
|
||||
if (!fileName.contains(".")) {
|
||||
throw new IllegalArgumentException("文件名必须包含后缀(如.jpg/.bmp)");
|
||||
}
|
||||
|
||||
// 2. 获取服务的static目录绝对路径(Spring Boot核心:通过ResourceUtils获取)
|
||||
File staticDir = null;
|
||||
try {
|
||||
// 本地开发环境:target/classes/static(Maven/Gradle构建后路径)
|
||||
// 生产环境(Jar包部署):Jar包内的static目录(需注意只读问题,下文会说明)
|
||||
staticDir = new File(ResourceUtils.getURL("classpath:static").getPath());
|
||||
} catch (FileNotFoundException e) {
|
||||
// 若Jar包部署时获取不到classpath:static(因Jar包内资源无法直接以File形式访问)
|
||||
// 改用服务运行目录下的static(需手动创建)
|
||||
staticDir = new File(System.getProperty("user.dir") + File.separator + "static");
|
||||
}
|
||||
|
||||
// 3. 创建static下的子目录(如static/report_imgs/,避免所有文件堆在static根目录)
|
||||
File targetDir = new File(staticDir, staticSubDir);
|
||||
if (!targetDir.exists()) {
|
||||
boolean mkdirsSuccess = targetDir.mkdirs(); // 递归创建多级目录
|
||||
if (!mkdirsSuccess) {
|
||||
throw new IOException("创建static子目录失败:" + targetDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 检查static目录写入权限
|
||||
if (!targetDir.canWrite()) {
|
||||
throw new IOException("static目录无写入权限:" + targetDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
// 5. 创建目标文件(加唯一标识避免同名覆盖,如在文件名前加UUID)
|
||||
String uniqueFileName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName;
|
||||
File targetFile = new File(targetDir, uniqueFileName);
|
||||
|
||||
// 6. 写入图片数据
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
System.out.println("图片已生成到static目录:" + targetFile.getAbsolutePath());
|
||||
return targetFile;
|
||||
}
|
||||
// 支持的图片格式(文件头标识 + 后缀名映射)
|
||||
private enum ImageFormat {
|
||||
JPG(new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF}, ".jpg"),
|
||||
PNG(new byte[]{(byte) 0x89, (byte) 0x50, (byte) 0x4E, (byte) 0x47}, ".png"),
|
||||
GIF(new byte[]{(byte) 0x47, (byte) 0x49, (byte) 0x46, (byte) 0x38}, ".gif"),
|
||||
BMP(new byte[]{(byte) 0x42, (byte) 0x4D}, ".bmp"); // BMP格式文件头标识
|
||||
|
||||
private final byte[] fileHeader; // 图片文件头(用于格式校验)
|
||||
private final String suffix; // 对应的文件后缀
|
||||
|
||||
ImageFormat(byte[] fileHeader, String suffix) {
|
||||
this.fileHeader = fileHeader;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
// 根据文件头匹配图片格式
|
||||
public static ImageFormat matchFormat(byte[] data) {
|
||||
if (data == null || data.length < 2) { // 至少需要2字节判断BMP格式
|
||||
return null;
|
||||
}
|
||||
for (ImageFormat format : values()) {
|
||||
// 检查数据长度是否足够
|
||||
if (data.length < format.fileHeader.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean match = true;
|
||||
for (int i = 0; i < format.fileHeader.length; i++) {
|
||||
if (data[i] != format.fileHeader[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心方法:将byte[]二进制数据生成图片临时文件
|
||||
* @param imageBytes 图片二进制数据(必须是JPG/PNG/GIF/BMP格式)
|
||||
* @param tempPrefix 临时文件前缀(如"report_img_",用于区分不同业务的临时文件)
|
||||
* @return 生成的临时图片文件(包含绝对路径,可直接给报告模板引用)
|
||||
* @throws IllegalArgumentException 入参非法(空数据、非图片格式)
|
||||
* @throws IOException 临时文件创建/写入失败
|
||||
*/
|
||||
public static File generateTempImage(byte[] imageBytes, String tempPrefix) throws IllegalArgumentException, IOException {
|
||||
// 1. 入参校验:避免空数据
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据[imageBytes]不能为null");
|
||||
if (imageBytes.length == 0) {
|
||||
throw new IllegalArgumentException("图片二进制数据[imageBytes]长度不能为0");
|
||||
}
|
||||
Objects.requireNonNull(tempPrefix, "临时文件前缀[tempPrefix]不能为null");
|
||||
if (tempPrefix.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("临时文件前缀[tempPrefix]不能为空字符串");
|
||||
}
|
||||
|
||||
// 2. 图片格式校验:确保是支持的图片类型(避免生成无效文件)
|
||||
ImageFormat imageFormat = ImageFormat.matchFormat(imageBytes);
|
||||
if (imageFormat == null) {
|
||||
throw new IllegalArgumentException("不支持的图片格式!仅支持JPG/PNG/GIF/BMP");
|
||||
}
|
||||
|
||||
// 3. 创建临时文件
|
||||
File tempImageFile = File.createTempFile(tempPrefix, imageFormat.suffix);
|
||||
|
||||
// 4. 临时文件安全配置
|
||||
tempImageFile.deleteOnExit();
|
||||
setFileSafePermission(tempImageFile);
|
||||
|
||||
// 5. 写入二进制数据到临时文件
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(
|
||||
new FileOutputStream(tempImageFile, false)
|
||||
)) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
// 6. 二次校验
|
||||
if (!tempImageFile.exists() || tempImageFile.length() != imageBytes.length) {
|
||||
throw new IOException("临时图片文件生成失败!文件大小不匹配或文件未创建");
|
||||
}
|
||||
|
||||
return tempImageFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载方法:指定图片格式(跳过自动校验,适用于已知格式的场景)
|
||||
* @param imageBytes 图片二进制数据
|
||||
* @param tempPrefix 临时文件前缀
|
||||
* @param targetSuffix 目标格式后缀(如".jpg", ".png",必须带".")
|
||||
* @return 临时图片文件
|
||||
* @throws IOException 临时文件操作异常
|
||||
*/
|
||||
public static File generateTempImage(byte[] imageBytes, String tempPrefix, String targetSuffix) throws IOException {
|
||||
// 入参校验
|
||||
Objects.requireNonNull(imageBytes, "图片二进制数据[imageBytes]不能为null");
|
||||
Objects.requireNonNull(tempPrefix, "临时文件前缀[tempPrefix]不能为null");
|
||||
Objects.requireNonNull(targetSuffix, "目标格式后缀[targetSuffix]不能为null");
|
||||
if (!targetSuffix.startsWith(".")) {
|
||||
throw new IllegalArgumentException("目标格式后缀必须以'.'开头(如\".jpg\")");
|
||||
}
|
||||
|
||||
// 创建临时文件
|
||||
File tempImageFile = File.createTempFile(tempPrefix, targetSuffix);
|
||||
tempImageFile.deleteOnExit();
|
||||
setFileSafePermission(tempImageFile);
|
||||
|
||||
// 写入数据
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempImageFile))) {
|
||||
bos.write(imageBytes);
|
||||
bos.flush();
|
||||
}
|
||||
|
||||
// 校验文件
|
||||
if (!tempImageFile.exists()) {
|
||||
throw new IOException("指定格式的临时图片文件生成失败");
|
||||
}
|
||||
|
||||
return tempImageFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:设置临时文件安全权限(跨平台兼容)
|
||||
*/
|
||||
private static void setFileSafePermission(File file) {
|
||||
if (file == null || !file.exists()) {
|
||||
return;
|
||||
}
|
||||
// Windows系统:通过设置文件属性隐藏
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec("attrib +h " + file.getAbsolutePath());
|
||||
process.waitFor();
|
||||
} catch (Exception e) {
|
||||
System.err.println("临时文件隐藏失败:" + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// Linux/Mac系统:设置权限为"仅当前用户读写"(600权限)
|
||||
file.setReadable(true, true);
|
||||
file.setWritable(true, true);
|
||||
file.setExecutable(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:手动删除临时文件
|
||||
* @param tempFile 临时文件对象
|
||||
* @return 删除成功返回true,失败返回false
|
||||
*/
|
||||
public static boolean deleteTempImage(File tempFile) {
|
||||
if (tempFile == null || !tempFile.exists()) {
|
||||
System.out.println("临时文件不存在,无需删除");
|
||||
return true;
|
||||
}
|
||||
boolean deleted = tempFile.delete();
|
||||
if (deleted) {
|
||||
System.out.println("临时文件删除成功:" + tempFile.getAbsolutePath());
|
||||
} else {
|
||||
System.err.println("临时文件删除失败:" + tempFile.getAbsolutePath());
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -3,10 +3,12 @@ package com.czlis.interfaceCommon.utils;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.czlis.common.config.RuoYiConfig;
|
||||
import com.czlis.common.core.domain.Result;
|
||||
import com.czlis.common.core.domain.entity.lis.LabGraph;
|
||||
import com.czlis.common.utils.file.FileUtils;
|
||||
import com.czlis.common.utils.file.ImageUtils;
|
||||
import com.czlis.common.utils.ip.IpUtils;
|
||||
import com.czlis.common.utils.uuid.UUID;
|
||||
import com.czlis.interfaceCommon.mapper.BackPaperMapper;
|
||||
@ -26,6 +28,7 @@ import net.sf.jasperreports.engine.JREmptyDataSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import java.io.File;
|
||||
@ -34,8 +37,6 @@ import java.sql.Connection;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ReportUtil {
|
||||
@ -70,7 +71,7 @@ public class ReportUtil {
|
||||
public void printBackpaper(List<String> sqhs) {
|
||||
String sqh = sqhs.get(0);
|
||||
BackPaperParam backPaperParam = backPaperMapper.selectReqmian(sqh);
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
// ObjectMapper objectMapper = new ObjectMapper();
|
||||
Map<String, Object> parameters = BeanUtil.beanToMap(backPaperParam);
|
||||
parameters.put("company", commonUtil.getCompany(backPaperParam.getYljg()));
|
||||
parameters.put("age", AgeUtils.getAge(backPaperParam.getBrsr()));
|
||||
@ -100,7 +101,7 @@ public class ReportUtil {
|
||||
|
||||
try {
|
||||
//构造数据
|
||||
System.out.println("入参参数:"+parameters.toString());
|
||||
System.out.println("入参参数:" + parameters.toString());
|
||||
JasperReportUtil.print(RuoYiConfig.getMzPrintName(), "backpaper", parameters, detailList);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -108,42 +109,62 @@ public class ReportUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public Result printToPdf(BarCodeParam barCodeParam, String pdfName){
|
||||
String templatePath = RuoYiConfig.getProfile()+"/templates/barcode_zy.jrxml"; // 模板文件路径
|
||||
return printToPdf("barcode_zy",barCodeParam,pdfName,false);
|
||||
public Result printToPdf(BarCodeParam barCodeParam, String pdfName) {
|
||||
String templatePath = RuoYiConfig.getProfile() + "/templates/barcode_zy.jrxml"; // 模板文件路径
|
||||
return printToPdf("barcode_zy", barCodeParam, pdfName, false);
|
||||
}
|
||||
|
||||
public Result printToPdf(String templatename,BarCodeParam barCodeParam, String pdfName,boolean base64){
|
||||
String outputPath = RuoYiConfig.getProfile()+"/config/static/printPDF/"+UUID.randomUUID().toString()+".pdf"; // PDF输出路径(多级目录会自动创建)
|
||||
// log.info("打印输入输出地址:{},{}",path,outputPath);
|
||||
public Result printToPdf(String templatename, BarCodeParam barCodeParam, String pdfName, boolean base64) {
|
||||
String outputPath = RuoYiConfig.getProfile() + "/config/static/printPDF/" + UUID.randomUUID().toString() + ".pdf"; // PDF输出路径(多级目录会自动创建)
|
||||
// log.info("打印输入输出地址:{},{}",path,outputPath);
|
||||
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(barCodeParam);
|
||||
try {
|
||||
Connection connection = dataSource.getConnection();
|
||||
//JasperReportUtil.generatePdf(templatename,outputPath,stringObjectMap,connection);
|
||||
JasperReportUtil.exportToPdf(templatename,stringObjectMap,connection,outputPath);
|
||||
JasperReportUtil.exportToPdf(templatename, stringObjectMap, connection, outputPath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("打印条码失败,参数{}",barCodeParam,e);
|
||||
log.error("打印条码失败,参数{}", barCodeParam, e);
|
||||
}
|
||||
String httpPath = getPrintURL(pdfName);
|
||||
log.info("传给前端的pdf地址:{}",httpPath);
|
||||
if(base64){
|
||||
log.info("传给前端的pdf地址:{}", httpPath);
|
||||
if (base64) {
|
||||
//删除图片文件
|
||||
String[] pic = barCodeParam.getPic();
|
||||
if(pic.length > 0){
|
||||
for (int i = 0; i < pic.length; i++) {
|
||||
String picFilePath = RuoYiConfig.getProfile() + "/config/static/graphs/"+ StrUtil.splitToArray(pic[i], "graphs/")[1];
|
||||
FileUtils.deleteFile(picFilePath);
|
||||
}
|
||||
}
|
||||
//删除最后给前端的pdf文件
|
||||
File file = new File(outputPath);
|
||||
String data=Base64.encode(file);
|
||||
String data = Base64.encode(file);
|
||||
FileUtils.deleteFile(outputPath);
|
||||
return new Result("0","打印成功!",data);
|
||||
}else{
|
||||
return new Result("0","打印成功!",httpPath);
|
||||
return new Result("0", "打印成功!", data);
|
||||
} else {
|
||||
return new Result("0", "打印成功!", httpPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getPrintURL(String pdfName){
|
||||
public String getPrintURL(String pdfName) {
|
||||
String httpPath = "";
|
||||
if(printURL == null || printURL.equals("")){
|
||||
httpPath = "http://"+ IpUtils.getHostIp() +":" + port + "/printPDF/"+pdfName+".pdf";
|
||||
}else{
|
||||
httpPath = "http://"+ printURL +":" + port + "/printPDF/"+pdfName+".pdf";
|
||||
if (printURL == null || printURL.equals("")) {
|
||||
httpPath = "http://" + IpUtils.getHostIp() + ":" + port + "/printPDF/" + pdfName + ".pdf";
|
||||
} else {
|
||||
httpPath = "http://" + printURL + ":" + port + "/printPDF/" + pdfName + ".pdf";
|
||||
}
|
||||
|
||||
return httpPath;
|
||||
}
|
||||
|
||||
public String getHttpURL(String pathChild) {
|
||||
String httpPath = "";
|
||||
if (printURL == null || printURL.equals("")) {
|
||||
httpPath = "http://" + IpUtils.getHostIp() + ":" + port + "/" + pathChild;
|
||||
} else {
|
||||
httpPath = "http://" + printURL + ":" + port + "/" + pathChild;
|
||||
}
|
||||
|
||||
return httpPath;
|
||||
@ -151,63 +172,64 @@ public class ReportUtil {
|
||||
|
||||
/**
|
||||
* 判断当前报告单是否使用A4报告单
|
||||
*
|
||||
* @param jyrq
|
||||
* @param yq
|
||||
* @param ybh
|
||||
* @return
|
||||
*/
|
||||
public String getReportPaperSize(Date jyrq,String yq,String ybh){
|
||||
public String getReportPaperSize(Date jyrq, String yq, String ybh) {
|
||||
//是否分A4,A5报告单
|
||||
String NOBOTH =commonUtil.getComOptValue(yq,"NOBOTH");
|
||||
String NOBOTH = commonUtil.getComOptValue(yq, "NOBOTH");
|
||||
//NOBOTH=0全部A5
|
||||
if("".equals(NOBOTH)||NOBOTH==null||"0".equals(NOBOTH)){
|
||||
if ("".equals(NOBOTH) || NOBOTH == null || "0".equals(NOBOTH)) {
|
||||
return "A5";
|
||||
}
|
||||
//NOBOTH=1全部A4
|
||||
if("1".equals(NOBOTH)){
|
||||
if ("1".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}
|
||||
//NOBOTH=2报告一A4,=3报告二A4
|
||||
//当前仪器是否开启双报告单模式,未开启则直接判断纸张
|
||||
String DOUBLEREPORT=commonUtil.getComOptValue(yq,"DOUBLEREPORT");
|
||||
if("".equals(DOUBLEREPORT)||DOUBLEREPORT==null||"0".equals(DOUBLEREPORT)){
|
||||
if("2".equals(NOBOTH)){
|
||||
String DOUBLEREPORT = commonUtil.getComOptValue(yq, "DOUBLEREPORT");
|
||||
if ("".equals(DOUBLEREPORT) || DOUBLEREPORT == null || "0".equals(DOUBLEREPORT)) {
|
||||
if ("2".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}else {
|
||||
} else {
|
||||
return "A5";
|
||||
}
|
||||
}
|
||||
//判断细菌仪使用的报告单模板
|
||||
String yqdl = commonUtil.getYqdl(yq);
|
||||
if("细菌仪".equals(yqdl)){
|
||||
int ym=commonUtil.getLabResultMedCount(jyrq,yq,ybh);
|
||||
if(ym>1){
|
||||
if("2".equals(NOBOTH)){
|
||||
if ("细菌仪".equals(yqdl)) {
|
||||
int ym = commonUtil.getLabResultMedCount(jyrq, yq, ybh);
|
||||
if (ym > 1) {
|
||||
if ("2".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}else {
|
||||
} else {
|
||||
return "A5";
|
||||
}
|
||||
}else{
|
||||
if("3".equals(NOBOTH)){
|
||||
} else {
|
||||
if ("3".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}else {
|
||||
} else {
|
||||
return "A5";
|
||||
}
|
||||
}
|
||||
}
|
||||
//常规报告如果报告使用报告二模板,判断报告二是否A4
|
||||
int bg2=commonUtil.getLabReport2(jyrq,yq,ybh);
|
||||
if(bg2>0){
|
||||
if("3".equals(NOBOTH)){
|
||||
int bg2 = commonUtil.getLabReport2(jyrq, yq, ybh);
|
||||
if (bg2 > 0) {
|
||||
if ("3".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}else {
|
||||
} else {
|
||||
return "A5";
|
||||
}
|
||||
}
|
||||
//无任何设定则使用报告单一
|
||||
if("2".equals(NOBOTH)){
|
||||
if ("2".equals(NOBOTH)) {
|
||||
return "A4";
|
||||
}else {
|
||||
} else {
|
||||
return "A5";
|
||||
}
|
||||
}
|
||||
@ -215,15 +237,16 @@ public class ReportUtil {
|
||||
|
||||
/**
|
||||
* 将两个PDF文件的第一页横向(左右)合并到一个页面
|
||||
*
|
||||
* @param Base64input1 左侧PDF BASE64
|
||||
* @param Base64input2 右侧PDF BASE64
|
||||
* @param output 合并后的PDF文件路径
|
||||
* @param output 合并后的PDF文件路径
|
||||
*/
|
||||
public void mergePdfsHorizontally(String Base64input1, String Base64input2, String output) throws IOException {
|
||||
//把base64数据生成pdf文件
|
||||
String path1 = RuoYiConfig.getProfile() +"/config/static/printPDF/"+UUID.randomUUID().toString()+".pdf";
|
||||
String path1 = RuoYiConfig.getProfile() + "/config/static/printPDF/" + UUID.randomUUID().toString() + ".pdf";
|
||||
Base64.decodeToFile(Base64input1, new File(path1));
|
||||
String path2 = RuoYiConfig.getProfile() +"/config/static/printPDF/"+UUID.randomUUID().toString()+".pdf";
|
||||
String path2 = RuoYiConfig.getProfile() + "/config/static/printPDF/" + UUID.randomUUID().toString() + ".pdf";
|
||||
Base64.decodeToFile(Base64input2, new File(path2));
|
||||
try (PdfWriter writer = new PdfWriter(output);
|
||||
PdfDocument pdfDoc = new PdfDocument(writer);
|
||||
@ -247,7 +270,7 @@ public class ReportUtil {
|
||||
mergedPage.setCropBox(mergedPageSize);
|
||||
|
||||
// 4. 创建画布
|
||||
try (Canvas canvas = new Canvas(mergedPage,pdfDoc.getDefaultPageSize())) {
|
||||
try (Canvas canvas = new Canvas(mergedPage, pdfDoc.getDefaultPageSize())) {
|
||||
|
||||
// 5. 左侧页面定位:左下角对齐合并页左下角(x=0, y=0)
|
||||
Image image1 = new Image(pdf1.getFirstPage().copyAsFormXObject(pdfDoc));
|
||||
@ -271,8 +294,9 @@ public class ReportUtil {
|
||||
|
||||
/**
|
||||
* 将PDF文件的指定页面旋转90度(顺时针)
|
||||
* @param input 输入PDF路径
|
||||
* @param output 输出PDF路径
|
||||
*
|
||||
* @param input 输入PDF路径
|
||||
* @param output 输出PDF路径
|
||||
* @param pageNumber 要旋转的页码(从1开始)
|
||||
* @throws IOException 处理PDF时可能抛出的异常
|
||||
*/
|
||||
@ -311,41 +335,48 @@ public class ReportUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public Result printReport(Date jyrq,String yq,String ybh,String sqh){
|
||||
String hospitalName = commonUtil.getCompany(commonUtil.getLabInstr(yq).getYljg());//commonUtil.getComDictNameById("HOS", "1");
|
||||
public Result printReport(Date jyrq, String yq, String ybh, String sqh) {
|
||||
String hospitalName = commonUtil.getCompany(commonUtil.getLabInstr(yq).getYljg());
|
||||
BarCodeParam barCodeParam = new BarCodeParam();
|
||||
barCodeParam.setJyrq(jyrq);
|
||||
barCodeParam.setYq(yq);
|
||||
barCodeParam.setYbh(ybh);
|
||||
barCodeParam.setSqh(sqh);
|
||||
barCodeParam.setHospitalName(hospitalName);
|
||||
String filename[]=getReportpic(jyrq,yq,ybh);
|
||||
String httpPath = getPrintURL("graphs");
|
||||
for(int i=0;i<filename.length;i++){
|
||||
EntityUtils.setItem(barCodeParam,"pic"+(i+1),httpPath+"/"+filename[i]);
|
||||
String[] filename = getReportpic(jyrq, yq, ybh);
|
||||
String httpPath = getHttpURL("graphs");
|
||||
String[] picPath = new String[filename.length];
|
||||
for (int i = 0; i < filename.length; i++) {
|
||||
//EntityUtils.setItem(barCodeParam, "pic" + (i + 1), httpPath + "/" + filename[i]);
|
||||
picPath[i] = httpPath + "/" + filename[i];
|
||||
log.info("传给模板的地址:{}", httpPath + "/" + filename[i]);
|
||||
}
|
||||
return printToPdf("report_ST",barCodeParam,UUID.randomUUID().toString(),true);
|
||||
barCodeParam.setPic(picPath);
|
||||
return printToPdf("report_image2", barCodeParam, UUID.randomUUID().toString(), true);
|
||||
|
||||
}
|
||||
public String[] getReportpic(Date jyrq,String yq,String ybh) {
|
||||
List<LabGraph> labGraphList= commonUtil.getLabGraphAll(jyrq,yq,ybh);
|
||||
String filepath="graphs";
|
||||
String filename[]=null;
|
||||
int filecount=0;
|
||||
if(labGraphList.size()>0){
|
||||
for(LabGraph labGraph:labGraphList){
|
||||
String txlb =labGraph.getTxlb();
|
||||
String txlbmc=UUID.randomUUID().toString()+"."+txlb.toLowerCase();
|
||||
byte[] txnr=labGraph.getTxnr();
|
||||
try {
|
||||
ImageUtils.generateToStaticDir(txnr,filepath,txlbmc);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
filename[filecount]=txlbmc;
|
||||
filecount++;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
public String[] getReportpic(Date jyrq, String yq, String ybh) {
|
||||
List<LabGraph> labGraphList = commonUtil.getLabGraphAll(jyrq, yq, ybh);
|
||||
String filepath = "graphs";
|
||||
log.info("labGraphList.size():{}", labGraphList.size());
|
||||
if (labGraphList.size() <= 0) return null;
|
||||
String[] filename = new String[labGraphList.size()];
|
||||
int filecount = 0;
|
||||
if (labGraphList.size() > 0) {
|
||||
for (LabGraph labGraph : labGraphList) {
|
||||
String txlb = labGraph.getTxlb();
|
||||
String txlbmc = UUID.randomUUID().toString() + "." + txlb.toLowerCase();
|
||||
byte[] txnr = labGraph.getTxnr();
|
||||
try {
|
||||
ImageUtils.generateToStaticDir(txnr, filepath, txlbmc);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
filename[filecount] = txlbmc;
|
||||
filecount++;
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -112,6 +112,12 @@
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@ -110,8 +110,8 @@ public class SecurityConfig {
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
requests.antMatchers("/login", "/register", "/captchaImage","/loginAnonymous").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/**/*.pdf","/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**","/printPDF/**","/graphs/**").permitAll()
|
||||
.antMatchers("/doc.html").permitAll() //Knife4j 过滤
|
||||
// 除上面外的所有请求全部需要鉴权认证
|
||||
.anyRequest().authenticated();
|
||||
|
||||
File diff suppressed because one or more lines are too long
83
lis-system/src/test/java/com/czlis/system/javaSE.java
Normal file
83
lis-system/src/test/java/com/czlis/system/javaSE.java
Normal file
@ -0,0 +1,83 @@
|
||||
package com.czlis.system;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class javaSE {
|
||||
|
||||
|
||||
//日期计算
|
||||
@Test
|
||||
public void test1(){
|
||||
DateTime dateTime = DateUtil.offsetDay(DateUtil.date(), 10);
|
||||
System.out.println(dateTime);
|
||||
}
|
||||
|
||||
//json转xml
|
||||
@Test
|
||||
public void test2(){
|
||||
String jsonStr = "{\"yljg\":\"\",\"brdh\":\"\",\"brly\":\"\",\"dept\":\"\",\"sqh\":\"\",\"userid\":\"\",\"stime\":\"\",\"etime\":\"\",\"bz1\":\"\"}";
|
||||
JSONObject jsonObj = JSONUtil.parseObj(jsonStr);
|
||||
Map<String,Object> map = jsonObj.toBean(Map.class);
|
||||
String xmlStr = XmlUtil.mapToXmlStr(map, "Request");
|
||||
System.out.println(xmlStr);
|
||||
|
||||
// int i = DateUtil.ageOfNow("2025-06-01");
|
||||
// System.out.println(i);
|
||||
}
|
||||
|
||||
//json序列化测试
|
||||
@Test
|
||||
public void test3(){
|
||||
List<String> dddwList = new ArrayList<>();
|
||||
dddwList.add("代号");
|
||||
dddwList.add("名称");
|
||||
dddwList.add("代号+名称");
|
||||
List<String> inputList = new ArrayList<>();
|
||||
inputList.add("1");
|
||||
inputList.add("2");
|
||||
inputList.add("3");
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("dddw",dddwList);
|
||||
map.put("input",inputList);
|
||||
map.put("radio","");
|
||||
String jsonStr = JSONUtil.toJsonStr(map);
|
||||
System.out.println(jsonStr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4(){
|
||||
String now = DateUtil.today();
|
||||
System.out.println("now:"+now); //1757902710365
|
||||
long time = DateUtil.parse(now, "yyyy-MM-dd").getTime();
|
||||
System.out.println("time:"+time);
|
||||
File file = new File("D:\\DumpStack.log");
|
||||
long modified = file.lastModified();
|
||||
//DateTime date = DateUtil.date(modified);
|
||||
System.out.println(modified);
|
||||
if(time > modified){
|
||||
System.out.println("当前时间大于文件修改时间");
|
||||
}else{
|
||||
System.out.println("当前时间小于文件修改时间");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5(){
|
||||
String temp = "http://47.97.125.165:8904/graphs/8c50363e-e589-4ef9-8401-c968810e9601.gif";
|
||||
String string = StrUtil.splitToArray(temp, "graphs/")[1];
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
||||
@ -22,11 +22,7 @@
|
||||
<artifactId>lis-interfaceCommon</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
Loading…
x
Reference in New Issue
Block a user