Browse Source

[feat]增加导出功能

pull/7/head
杨威 4 weeks ago
parent
commit
184de2cd6b
  1. 11
      dk-modules/business/pom.xml
  2. 12
      dk-modules/business/src/main/java/org/dromara/business/controller/BusinessAlertController.java
  3. 5
      dk-modules/business/src/main/java/org/dromara/business/mapper/BusinessAlertMapper.java
  4. 4
      dk-modules/business/src/main/java/org/dromara/business/service/IBusinessAlertService.java
  5. 146
      dk-modules/business/src/main/java/org/dromara/business/service/impl/BusinessAlertServiceImpl.java
  6. 264
      dk-modules/business/src/main/java/org/dromara/business/utils/FreemarkerUtil.java
  7. 283
      dk-modules/business/src/main/java/org/dromara/business/utils/ZipStreamUtil.java
  8. 7
      dk-modules/business/src/main/resources/mapper/business/BusinessAlertMapper.xml
  9. 13546
      dk-modules/business/src/main/resources/templates/alert.ftl
  10. 2
      dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceQrtzController.java

11
dk-modules/business/pom.xml

@ -121,6 +121,17 @@
<artifactId>common-rocketmq</artifactId>
</dependency>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>

12
dk-modules/business/src/main/java/org/dromara/business/controller/BusinessAlertController.java

@ -7,6 +7,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.client.utils.TenantUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.business.domain.BusinessAlert;
@ -32,6 +33,7 @@ import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.Date;
import java.util.List;
@ -186,6 +188,16 @@ public class BusinessAlertController extends BaseController {
}
/**
* 导出预警数据
* @param bo
*/
@Operation(summary ="导出预警数据",description = "导出预警数据")
@GetMapping("/alert/export")
public void exportBusinessAlert(BusinessAlertBo bo, HttpServletResponse response) throws IOException {
businessAlertService.exportAlert(bo,response);
}
// @Operation(summary ="ai实时流预警保存-用于演示",description = "ai实时流预警保存-用于演示")

5
dk-modules/business/src/main/java/org/dromara/business/mapper/BusinessAlertMapper.java

@ -121,4 +121,9 @@ public interface BusinessAlertMapper extends BaseMapperPlus<BusinessAlert, Busin
Integer selectCurrentAlertCount(@Param("currentDate") String currentDate);
void batchUpdateCaseNumber(@Param("list") List<BusinessAlertVo> alertVoList);
@DataPermission(
@DataColumn(key = "deptName", value = "t.dept_id")
)
List<BusinessAlert> exportAlert(@Param("ew") QueryWrapper<BusinessAlert> ew, @Param("tbPrefix") ProjectTablePrefixConfig tbPrefix);
}

4
dk-modules/business/src/main/java/org/dromara/business/service/IBusinessAlertService.java

@ -1,5 +1,6 @@
package org.dromara.business.service;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.business.api.domain.bo.RemoteBusinessAlertBo;
import org.dromara.business.api.domain.vo.RemoteBusinessAlertVo;
import org.dromara.business.domain.BusinessAlert;
@ -8,6 +9,7 @@ import org.dromara.business.domain.vo.BusinessAlertVo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@ -102,4 +104,6 @@ public interface IBusinessAlertService {
Boolean updateBusinessAlert(BusinessAlert businessAlert);
TableDataInfo<BusinessAlertVo> listAiVerifyAlert(BusinessAlertVo vo,PageQuery pageQuery);
void exportAlert(BusinessAlertBo bo, HttpServletResponse response) throws IOException;
}

146
dk-modules/business/src/main/java/org/dromara/business/service/impl/BusinessAlertServiceImpl.java

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
@ -24,6 +25,7 @@ import org.dromara.business.mapper.BusinessAlertConstructInfoMapper;
import org.dromara.business.mapper.BusinessAlertMapper;
import org.dromara.business.service.IBusinessAlertService;
import org.dromara.business.utils.BatchProcessorUtil;
import org.dromara.business.utils.FreemarkerUtil;
import org.dromara.business.utils.MinioUntil;
import org.dromara.business.utils.constants.MinIOConstants;
import org.dromara.common.core.enums.BusinessStatusEnum;
@ -37,6 +39,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.business.utils.MinioUtil;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.RemoteLabelPostService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteAiLabelPostVo;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.dromara.workflow.api.RemoteWorkflowService;
@ -45,7 +48,11 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@ -57,6 +64,12 @@ import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.util.Base64;
/**
* 预警任务Service业务层处理
*
@ -82,6 +95,9 @@ public class BusinessAlertServiceImpl implements IBusinessAlertService {
@Autowired
private ProjectTablePrefixConfig ptPrefix;
@DubboReference
private RemoteUserService remoteUserService;
/**
* 新增预警任务
*
@ -759,6 +775,136 @@ public class BusinessAlertServiceImpl implements IBusinessAlertService {
return TableDataInfo.build(businessAlertVos);
}
@Override
public void exportAlert(BusinessAlertBo bo, HttpServletResponse response) throws IOException {
Map<String,Object> resultMap = new HashMap<>();
if (ObjectUtil.hasEmpty(bo.getStartTime(),bo.getEndTime())) {
bo.setStartTime(DateUtils.getDate());
bo.setEndTime(DateUtils.getDate());
}
//获取所有的用户信息
List<RemoteUserVo> remoteUserVos = remoteUserService.selectUserByUserIds(List.of());
Map<Long, List<RemoteUserVo>> userIdMap = remoteUserVos.stream().collect(Collectors.groupingBy(RemoteUserVo::getUserId));
QueryWrapper<BusinessAlert> wrapper = buildQueryWrapper(bo);
if (ObjectUtil.isEmpty(wrapper)){
throw new RuntimeException("没有可查看的预警数据!");
}
wrapper.eq("t.business_type",1);
//根据前端查询条件查询
List<BusinessAlert> alertList = this.baseMapper.exportAlert(wrapper,ptPrefix);
long todoCount = alertList.stream().filter(p -> p.getHandleType().equalsIgnoreCase("waiting")).count();
long finishCount = alertList.stream().filter(p -> p.getHandleType().equalsIgnoreCase("finish")).count();
//构建预警数量
resultMap.put("total",alertList.size());
resultMap.put("todo",todoCount);
resultMap.put("finish",finishCount);
//构建预警时间
resultMap.put("startTime",bo.getStartTime());
resultMap.put("endTime",bo.getEndTime());
long startMillis = System.currentTimeMillis();
alertList.parallelStream().forEach(businessAlert->{
try {
if (ObjectUtil.isNotEmpty(userIdMap.get(businessAlert.getAssignUserId()))){
businessAlert.setAssignUserName(userIdMap.get(businessAlert.getAssignUserId()).get(0).getNickName());
}
businessAlert.setHandleType(businessAlert.getHandleType().equalsIgnoreCase("waiting")?"未处理":businessAlert.getHandleType().equalsIgnoreCase("finish")?"已完结":businessAlert.getHandleType().equalsIgnoreCase("cancel")?"已忽略":"待验证");
if (businessAlert.getBusinessType() == 1){
businessAlert.setImages(imageToBase64(MinioUntil.getObjectUrlOne(MinIOConstants.BUCKET_ALERT, businessAlert.getImages(), 3600).toString()));
if (ObjectUtil.isEmpty(businessAlert.getImages())){
log.info("images为null");
}
businessAlert.setMaxImages(imageToBase64(MinioUntil.getObjectUrlOne(MinIOConstants.BUCKET_ALERT, businessAlert.getMaxImages(), 3600).toString()));
if (ObjectUtil.isEmpty(businessAlert.getMaxImages())){
log.info("MaxImages为null");
}
businessAlert.setMaxMateSourceImgUrl(imageToBase64(MinioUntil.getObjectUrlOne(MinIOConstants.BUCKET_ALERT, businessAlert.getMaxMateSourceImgUrl(), 3600).toString()));
if (ObjectUtil.isEmpty(businessAlert.getMaxMateSourceImgUrl())){
log.info("MaxMateSourceImgUrl为null");
}
businessAlert.setMateSourceImgUrl(imageToBase64(MinioUntil.getObjectUrlOne(MinIOConstants.BUCKET_ALERT, businessAlert.getMateSourceImgUrl(), 3600).toString()));
if (ObjectUtil.isEmpty(businessAlert.getMateSourceImgUrl())){
log.info("MateSourceImgUrl为null");
}
}else {
businessAlert.setImages(imageToBase64(MinioUntil.getObjectUrlOne(MinIOConstants.BUCKET_ALERT, businessAlert.getImages(), 3600).toString()));
}
} catch (Exception e) {
log.error(e.getMessage(),e);
}
});
long endMillis = System.currentTimeMillis();
System.out.println("消耗时长:" + (endMillis-startMillis));
resultMap.put("alertList",alertList);
//生成word
FreemarkerUtil.renderTplFileToWord("预警导出.docx","alert.ftl",resultMap,response);
// FreemarkerUtil.renderTplFileToPDF("预警导出.docx","alert.ftl",resultMap,response);
}
// 压缩图片方法
private static BufferedImage compressImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
Image resizedImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
BufferedImage bufferedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(resizedImage, 0, 0, null);
g.dispose();
return bufferedImage;
}
// 下载图片并转换为Base64
public static String imageToBase64(String imageUrl) throws Exception {
int targetWidth = 800; // 你可以调整这个值来控制图片压缩的程度
int targetHeight = 600;
// 创建URL对象
URL url = new URL(imageUrl);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
// 获取输入流
InputStream inputStream = connection.getInputStream();
// 读取图片
BufferedImage originalImage = ImageIO.read(inputStream);
// 压缩图片
BufferedImage compressedImage = compressImage(originalImage, targetWidth, targetHeight);
// 将压缩后的图片转换为字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(compressedImage, "jpg", byteArrayOutputStream); // 将图片写为JPEG格式
byte[] imageBytes = byteArrayOutputStream.toByteArray();
// 将字节数组编码为Base64
String base64Encoded = Base64.getEncoder().encodeToString(imageBytes);
return base64Encoded;
}
@Override
public Boolean deleteAlert(List<Long> alertIdList) {
if (ObjectUtil.isEmpty(alertIdList)) {

264
dk-modules/business/src/main/java/org/dromara/business/utils/FreemarkerUtil.java

@ -0,0 +1,264 @@
package org.dromara.business.utils;
import cn.hutool.extra.spring.SpringUtil;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import freemarker.template.Template;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
public class FreemarkerUtil {
/**
* Freemarker的配置类模板目录默认 resources下的 templates
*/
private static FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
/**
* 将模板文件填充数据后转为String
*
* @param templateName ftl模板文件名
* @param datas 数据集合
* @return
*/
public static String renderTplFileToStr(String templateName, Map<String, Object> datas) {
try {
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(templateName, "UTF-8");
StringWriter out = new StringWriter();
template.process(datas, out);
out.flush();
out.close();
return out.getBuffer().toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将模板文件填充数据后导出为文件导出html,word文件都使用此方法
*
* @param templateName ftl模板文件名
* @param datas 数据集合
* @param outFile 导出的文件路径名称
*/
public static void renderTplFileToLocalFile(String templateName, Map<String, Object> datas, ByteArrayOutputStream fos) {
Writer out = null;
OutputStreamWriter oWriter = null;
try {
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(templateName, "UTF-8");
oWriter = new OutputStreamWriter(fos, "UTF-8");
// 这个地方对流的编码不可或缺,使用main()单独调用时,应该可以,但是如果是web请求导出时导出后word文档就会打不开,并且包XML文件错误。主要是编码格式不正确,无法解析。
out = new BufferedWriter(new OutputStreamWriter(fos));
out = new BufferedWriter(oWriter);
template.process(datas, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (oWriter != null) {
oWriter.close();
}
if (fos != null) {
fos.close();
}
if (out != null) {
out.close();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
/**
* 根据word模板获取输入流
*
* @param templateName
* @param datas
* @return
* @throws IOException
*/
public static InputStream renderTplFileToWordInputStream(String templateName, Map<String, Object> datas) throws IOException {
Document doc = null;
DataInputStream in = null;
try {
in = renderTplFileToIOFile(templateName, datas);
doc = new Document();
doc.loadFromStream(in, FileFormat.Auto);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.saveToStream(baos, FileFormat.Docx);
ByteArrayOutputStream byteArrayOutputStream = ZipStreamUtil.copyStream(baos);
//输出流转为输入流
InputStreamSource inputStreamSource = new ByteArrayResource(byteArrayOutputStream.toByteArray());
return inputStreamSource.getInputStream();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
if (doc != null) {
doc.close();
}
}
return null;
}
/**
* 将模板文件填充数据后返回文件流
*
* @param templateName ftl模板文件名
* @param datas 数据集合
*/
public static DataInputStream renderTplFileToIOFile(String templateName, Map<String, Object> datas) throws Exception {
ByteArrayInputStream in = null;
Writer out = null;
try {
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(templateName, "UTF-8");
out = new StringWriter();
template.process(datas, out);
String out1 = out.toString().replace("&", "&amp;");//替换非法字符
in = new ByteArrayInputStream(out1.getBytes("UTF-8"));
return new DataInputStream(in);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
}
return null;
}
/**
* 根据word模板获取输入流
*
* @param templateName
* @param datas
* @return
* @throws IOException
*/
public static void renderTplFileToWord(String documentName , String templateName, Map<String, Object> datas, HttpServletResponse response) throws IOException {
response.setContentType("application/x-msdownload;");
response.setHeader("Content-disposition", "attachment; filename=" + documentName);
Document doc = null;
DataInputStream in = null;
try {
in = renderTplFileToIOFile(templateName, datas);
doc = new Document();
doc.loadFromStream(in, FileFormat.Auto);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.saveToStream(baos, FileFormat.Docx);
ByteArrayOutputStream byteArrayOutputStream = ZipStreamUtil.copyStream(baos);
// 将生成的文档写入到响应的输出流中
response.reset(); // 重置响应
response.getOutputStream().write(byteArrayOutputStream.toByteArray());
response.getOutputStream().flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
if (doc != null) {
doc.close();
}
}
}
/**
* 根据word模板获取输入流
*
* @param templateName
* @param datas
* @return
* @throws IOException
*/
public static void renderTplFileToPDF(String fileName ,String templateName, Map<String, Object> datas,HttpServletResponse response) throws IOException {
response.setCharacterEncoding(StandardCharsets.UTF_8.name()); // 字符集编码
response.setContentType("application/pdf;");
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
response.addHeader("Access-Control-Allow-Origin", "*"); // 实现跨域
Document doc = null;
DataInputStream in = null;
try {
in = renderTplFileToIOFile(templateName, datas);
doc = new Document();
doc.loadFromStream(in, FileFormat.Auto);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.saveToStream(baos, FileFormat.PDF);
// 将生成的文档写入到响应的输出流中
response.reset(); // 重置响应
response.getOutputStream().write(baos.toByteArray());
response.getOutputStream().flush();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encodeImageToBase64(String imageUrl) throws Exception {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
try (InputStream in = connection.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
byte[] imageBytes = baos.toByteArray();
return Base64.getEncoder().encodeToString(imageBytes);
}
}
}

283
dk-modules/business/src/main/java/org/dromara/business/utils/ZipStreamUtil.java

@ -0,0 +1,283 @@
package org.dromara.business.utils;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.util.function.BiFunction;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static java.util.zip.ZipEntry.STORED;
import static java.util.zip.ZipOutputStream.DEFLATED;
public class ZipStreamUtil {
public static void main(String[] args) {
/* String srcPath = "E:\\360极速浏览器下载\\Linksla生产 (1).docx";
String outPath = "E:\\360极速浏览器下载\\Linksla生产2.docx";
try (FileInputStream is = new FileInputStream(srcPath)) {
try (FileOutputStream os = new FileOutputStream(outPath)) {
ZipStreamUtil.zipEntryCopyStream(os, is, new BiFunction<ZipEntry, ZipInputStream, byte[]>() {
@Override
public byte[] apply(ZipEntry se, ZipInputStream zis) {
byte[] rt = null;
String name = se.getName();
if (null == name) return rt;
String line = String.format("ZipEntry(%s, isDirectory=%d, size=%d, compressedSize=%d, time=%d, crc=%d, method=%d, comment=%s)",
se.getName(), (se.isDirectory()) ? 1 : 0, se.getSize(), se.getCompressedSize(), se.getTime(), se.getCrc(), se.getMethod(), se.getComment());
System.out.println(line);
if (name.endsWith("word/document.xml")) {
try {
byte[] oldBytes = ZipStreamUtil.toByteArray(zis);
String str = (new String(oldBytes));
String appendString = str.replace("Evaluation Warning: The document was created with Spire.Doc for JAVA.", "");
//rt = str.getBytes();
// 为了避免多余的编码转换, 改成下面的代码更好.
try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
//ZipStreamUtil.copyStream(buf, zis);
buf.write(appendString.getBytes());
rt = buf.toByteArray();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return rt;
}
});
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("ZipTxtAppendTest done." + outPath);*/
}
/**
* 过滤word 水印
*
* @param baos
* @return
* @throws IOException
*/
public static ByteArrayOutputStream copyStream(ByteArrayOutputStream baos) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ByteArrayOutputStream baoss = new ByteArrayOutputStream();
try {
ZipStreamUtil.zipEntryCopyStream(baoss, bais, new BiFunction<ZipEntry, ZipInputStream, byte[]>() {
@Override
public byte[] apply(ZipEntry se, ZipInputStream zis) {
byte[] rt = null;
String name = se.getName();
if (null == name) return rt;
String line = String.format("ZipEntry(%s, isDirectory=%d, size=%d, compressedSize=%d, time=%d, crc=%d, method=%d, comment=%s)",
se.getName(), (se.isDirectory()) ? 1 : 0, se.getSize(), se.getCompressedSize(), se.getTime(), se.getCrc(), se.getMethod(), se.getComment());
System.out.println(line);
if (name.endsWith("word/document.xml")) {
try {
byte[] oldBytes = ZipStreamUtil.toByteArray(zis);
String str = (new String(oldBytes));
String appendString = str.replace("Evaluation Warning: The document was created with Spire.Doc for JAVA.", "");
try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
buf.write(appendString.getBytes());
rt = buf.toByteArray();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return rt;
}
});
} finally {
bais.close();
baoss.close();
}
return baoss;
}
public static byte[] toByteArray(InputStream in) throws IOException {
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
copyStream(out, in);
return out.toByteArray();
}
}
public static void copyStream(OutputStream os, InputStream is) throws IOException {
copyStream(os, is, 0);
}
public static void copyStream(OutputStream os, InputStream is, int bufsize) throws IOException {
if (bufsize <= 0) bufsize = 4096;
int len;
byte[] bytes = new byte[bufsize];
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
}
/**
* 基于ZIP项目的复制Zip流.
*
* @param dst The output stream of the destination zip.
* @param src Source zip.
* @param transform 转换处理. 可以为null, 不转换. 该回调函数的原型为`byte[] transform(ZipEntry zipEntry, ZipInputStream zis)`, 当返回值为 null时保留原值, 为非null时用返回值替换当前ZipEntry对应的流数据.
* @return 返回转换次数.
* @throws IOException
*/
public static int zipEntryCopyStreamZip(ZipOutputStream zos, ZipInputStream zis, BiFunction<ZipEntry, ZipInputStream, byte[]> transform) throws IOException {
int rt = 0;
ZipEntry se;
while ((se = zis.getNextEntry()) != null) {
if (null == se) continue;
//String line = String.format("ZipEntry(%s, isDirectory=%d, size=%d, compressedSize=%d, time=%d, crc=%d, method=%d, comment=%s)",
// se.getName(), (se.isDirectory())?1:0, se.getSize(), se.getCompressedSize(), se.getTime(), se.getCrc(), se.getMethod(), se.getComment());
//System.out.println(line);
byte[] dstBytes = null;
if (null != transform) {
dstBytes = transform.apply(se, zis);
}
// choose by dstBytes.
if (null == dstBytes) {
ZipEntry de = new ZipEntry(se);
de.setCompressedSize(-1); // 重新压缩后, csize 可能不一致, 故需要恢复为默认值.
zos.putNextEntry(de);
copyStream(zos, zis);
zos.closeEntry();
} else {
++rt;
//ZipEntry de = new ZipEntry(se);
//de.setCompressedSize(-1);
//de.setCrc(-1);
// == fix IllegalArgumentException.
ZipEntry de = new ZipEntry(se.getName());
//System.out.println(se.getTime());
//final long timeNone = 312739200000L;
//if (timeNone!=se.getTime() && null!=se.getLastModifiedTime()) { // 发现会被自动改为当前时间.
if (null != se.getLastModifiedTime()) {
de.setLastModifiedTime(se.getLastModifiedTime());
}
if (null != se.getLastAccessTime()) {
de.setLastAccessTime(se.getLastAccessTime());
}
if (null != se.getCreationTime()) {
de.setCreationTime(se.getCreationTime());
}
de.setSize(dstBytes.length);
//de.setCompressedSize(se.getCompressedSize()); // changed.
//de.setCrc(se.getCrc()); // changed.
int method = se.getMethod();
if (method != STORED && method != DEFLATED) {
// No setMethod .
} else {
de.setMethod(method);
}
de.setExtra(se.getExtra());
de.setComment(se.getComment());
zos.putNextEntry(de);
zos.write(dstBytes);
zos.closeEntry();
}
}
return rt;
}
/**
* 基于ZIP项目的复制流.
*
* @param dst The output stream of the destination zip.
* @param src Source zip.
* @param transform 转换处理. 可以为null, 不转换. 该回调函数的原型为`byte[] transform(ZipEntry zipEntry, ZipInputStream zis)`, 当返回值为 null时保留原值, 为非null时用返回值替换当前ZipEntry对应的流数据.
* @return 返回转换次数.
* @throws IOException
*/
public static int zipEntryCopyStream(OutputStream os, InputStream is, BiFunction<ZipEntry, ZipInputStream, byte[]> transform) throws IOException {
try (ZipInputStream zis = new ZipInputStream(is)) {
try (ZipOutputStream zos = new ZipOutputStream(os)) {
return zipEntryCopyStreamZip(zos, zis, transform);
}
}
}
public static void saveImageToFile(String imageUrl, File destination) throws IOException {
try (InputStream in = new URL(imageUrl).openStream()) {
Files.copy(in, destination.toPath());
}
}
public static void addFolderToZip(File sourceFolder, String baseFolderName, ZipOutputStream zos) throws IOException {
for (File file : sourceFolder.listFiles()) {
if (file.isDirectory()) {
addFolderToZip(file, baseFolderName + "/" + file.getName(), zos);
} else {
try (InputStream in = Files.newInputStream(file.toPath())) {
ZipEntry zipEntry = new ZipEntry(baseFolderName + "/" + file.getName());
zos.putNextEntry(zipEntry);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) >= 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
}
}
}
}
public static void deleteDirectory(File directory) {
for (File file : directory.listFiles()) {
if (file.isDirectory()) {
deleteDirectory(file);
}
file.delete();
}
directory.delete();
}
// Helper method to add image to zip stream
public static void addImageToZip(String imageUrl, File targetFile, String folderName, ZipOutputStream zos) throws IOException {
if (imageUrl == null || imageUrl.isEmpty()) {
throw new IllegalArgumentException("The image URL cannot be null or empty.");
}
URL url;
try {
url = new URL(imageUrl);
} catch (MalformedURLException e) {
throw new IOException("Invalid URL format: " + imageUrl, e);
}
try (InputStream imageStream = url.openStream()) {
// Create zip entry for image
String zipEntryName = folderName + "/" + targetFile.getName();
ZipEntry zipEntry = new ZipEntry(zipEntryName);
zos.putNextEntry(zipEntry);
// Write image content to zip stream
byte[] buffer = new byte[8192]; // 8KB buffer for optimal performance
int bytesRead;
while ((bytesRead = imageStream.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry();
} catch (IOException e) {
// Log the error and rethrow the exception for higher-level handling
System.err.println("Error processing image from URL: " + imageUrl);
e.printStackTrace();
throw e;
}
}
}

7
dk-modules/business/src/main/resources/mapper/business/BusinessAlertMapper.xml

@ -967,4 +967,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</update>
<select id="exportAlert" resultType="org.dromara.business.domain.BusinessAlert">
select t.* from (select
ba.*
from ${tbPrefix.tableBusiness}.business_alert ba) t
${ew.getCustomSqlSegment}
</select>
</mapper>

13546
dk-modules/business/src/main/resources/templates/alert.ftl

File diff suppressed because it is too large

2
dk-modules/sample/src/main/java/org/dromara/sample/manage/controller/DeviceQrtzController.java

@ -47,7 +47,7 @@ public class DeviceQrtzController extends BaseController {
* */
@SaCheckPermission("devict:qrtz:list")
@GetMapping(value = "/page")
public TableDataInfo<DeviceQrtzEntity> queryPageDept(@RequestParam(name="pageNum", defaultValue="1") Integer pageNum,
public TableDataInfo<DeviceQrtzEntity> queryPageDept(@RequestParam(name="pageNo", defaultValue="1") Integer pageNum,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize, DeviceQrtzDTO deviceQrtzDTO) {
Page<DeviceQrtzEntity> page = new Page(pageNum,pageSize);
return deviceQrtzService.listManageDeviceQrtz(page, deviceQrtzDTO);

Loading…
Cancel
Save