From bf4e04738da91ca464a3afe3956b4fd1d9e9e807 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Wed, 4 Dec 2024 11:47:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A5=E8=A1=A8=E6=A8=A1=E6=9D=BF=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/ReportTemplateController.java | 20 +++- .../dataobject/template/ReportTemplateDO.java | 9 -- .../template/ReportTemplateService.java | 21 +++- .../template/ReportTemplateServiceImpl.java | 108 ++++++++++++++---- 4 files changed, 122 insertions(+), 36 deletions(-) diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java index 4a7b1d32a..e7f6be641 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/controller/admin/template/ReportTemplateController.java @@ -26,7 +26,6 @@ import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.http.HttpStatus; -import org.apache.ibatis.annotations.Param; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -145,7 +144,7 @@ public class ReportTemplateController { @Operation(summary = "校验表达式") @Parameter(name = "content", description = "表达式", required = true) @PreAuthorize("@ss.hasPermission('report:design')") - public List scriptValidation(@Param("content") @NotEmpty(message = "表达式不能为空") String content) { + public List scriptValidation(@RequestParam("content") @NotEmpty(message = "表达式不能为空") String content) { content = StringUtils.decode(content); ANTLRInputStream antlrInputStream = new ANTLRInputStream(content); ReportParserLexer lexer = new ReportParserLexer(antlrInputStream); @@ -168,7 +167,7 @@ public class ReportTemplateController { @Operation(summary = "解析表达式中的数据集") @Parameter(name = "expr", description = "表达式", required = true) @PreAuthorize("@ss.hasPermission('report:design')") - public Map parseDatasetName(@Param("expr") @NotEmpty(message = "表达式不能为空") String expr) { + public Map parseDatasetName(@RequestParam("expr") @NotEmpty(message = "表达式不能为空") String expr) { ANTLRInputStream antlrInputStream = new ANTLRInputStream(expr); ReportParserLexer lexer = new ReportParserLexer(antlrInputStream); CommonTokenStream tokenStream = new CommonTokenStream(lexer); @@ -186,4 +185,19 @@ public class ReportTemplateController { } return result; } + + @GetMapping("/xml/{id}") + @Operation(summary = "导出模版") + @Parameter(name = "id", description = "模板id", required = true) + @PreAuthorize("@ss.hasPermission('report:design')") + public void exportTemplate(@PathVariable("id") Long templateId, HttpServletResponse response) { + templateService.exportTemplate(templateId, response); + } + + @PutMapping("/xml") + @Operation(summary = "导入模版") + @PreAuthorize("@ss.hasPermission('report:design')") + public void importTemplate(@RequestParam("name") @NotEmpty(message = "模版名称不能为空") String name, @RequestParam("file") MultipartFile file) { + templateService.importTemplate(name, file); + } } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/dal/dataobject/template/ReportTemplateDO.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/dal/dataobject/template/ReportTemplateDO.java index c59abe40c..42f75e060 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/dal/dataobject/template/ReportTemplateDO.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/dal/dataobject/template/ReportTemplateDO.java @@ -4,12 +4,9 @@ import com.baomidou.mybatisplus.annotation.*; import com.cf.imes.framework.mybatis.core.dataobject.BaseDO; import com.cf.imes.framework.mybatis.core.type.CompressStringTypeHandler; import com.cf.imes.framework.mybatis.core.type.JsonLongSetTypeHandler; -import com.cf.imes.framework.mybatis.core.type.LongListTypeHandler; -import com.cf.imes.module.report.dal.dataobject.datasource.ReportDatasourceDO; import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum; import lombok.*; -import java.util.List; import java.util.Set; /** @@ -56,12 +53,6 @@ public class ReportTemplateDO extends BaseDO { @TableField(fill = FieldFill.INSERT_UPDATE) private Long organId; - /** - * 数据源 - */ - @TableField(exist = false) - private List datasource; - /** * 数据源id列表 */ diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateService.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateService.java index ca80fb02d..88fce28ea 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateService.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateService.java @@ -7,6 +7,7 @@ import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateReqV import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateRespVO; import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateSaveReqVO; import com.cf.imes.module.report.dal.dataobject.template.ReportTemplateDO; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; @@ -75,7 +76,7 @@ public interface ReportTemplateService { /** * 模板预览 * - * @param params + * @param reqVO * @return */ HtmlReport preview(ReportTemplatePreviewReqVO reqVO); @@ -89,8 +90,24 @@ public interface ReportTemplateService { * 模版预览下载 * * @param type 文件类型 - * @param params + * @param reqVO * @param response */ void download(String type, ReportTemplatePreviewReqVO reqVO, HttpServletResponse response); + + /** + * 模板导出 + * + * @param templateId + * @param response + */ + void exportTemplate(Long templateId, HttpServletResponse response); + + /** + * 模版导入 + * + * @param name + * @param file + */ + void importTemplate(String name, MultipartFile file); } diff --git a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java index bb4201bb5..908010163 100644 --- a/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java +++ b/cf-module-report/cf-module-report-biz/src/main/java/com/cf/imes/module/report/service/template/ReportTemplateServiceImpl.java @@ -2,9 +2,14 @@ package com.cf.imes.module.report.service.template; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.URLUtil; +import cn.hutool.http.ContentType; +import cn.hutool.http.Header; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.bstek.common.exception.ReportDesignException; import com.bstek.designer.bean.PreviewParameters; @@ -47,11 +52,13 @@ import com.cf.imes.module.report.dal.mysql.datasource.ReportDatasourceMapper; import com.cf.imes.module.report.dal.mysql.template.ReportTemplateMapper; import com.cf.imes.module.report.enums.template.ReportTemplateTypeEnum; import com.cf.imes.module.report.utils.TenantParamsUtils; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import org.springframework.validation.annotation.Validated; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; @@ -59,13 +66,14 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR; @@ -81,6 +89,7 @@ import static com.cf.imes.module.report.enums.ErrorCodeConstants.TEMPLATE_PREIVE */ @Service @Validated +@Slf4j public class ReportTemplateServiceImpl implements ReportTemplateService { @Resource private ReportTemplateMapper templateMapper; @@ -92,6 +101,9 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { private ReportDatasetMapper datasetMapper; private static final String UTF8_CHARSET = CharsetUtil.UTF_8; + private static final String ATTACHMENT_PREFIX = "attachment; filename="; + private static final String DATASETIDS_FIELD_NAME = "datasetIds"; + private static final String DATASOURCEIDS_FIELD_NAME = "datasourceIds"; @Resource private TenantParamsUtils tenantParamsUtils; @@ -360,7 +372,7 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { if (ObjectUtil.isNotNull(queryMap)) { for (Map.Entry entry : queryMap.entrySet()) { String key = entry.getKey(); - if (ObjectUtils.isEmpty(entry.getValue()) && ObjectUtil.notEqual(key, "datasetIds") && ObjectUtil.notEqual(key, "datasourceIds")) { + if (ObjectUtils.isEmpty(entry.getValue()) && ObjectUtil.notEqual(key, DATASETIDS_FIELD_NAME) && ObjectUtil.notEqual(key, DATASOURCEIDS_FIELD_NAME)) { throw ServiceExceptionUtil.exception(TEMPLATE_PREIVEW_QUERYPARAM_EMPTY, key); } } @@ -405,12 +417,14 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { // 创建下载文件 ProducerEnum p = ProducerEnum.PDF; String downFileName = com.bstek.common.utils.StringUtils.randomFileName() + com.bstek.common.utils.StringUtils.getFileSuffix(p); - response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, UTF8_CHARSET)); + response.setHeader(Header.CONTENT_DISPOSITION.getValue(), ATTACHMENT_PREFIX + URLEncoder.encode(downFileName, UTF8_CHARSET)); + response.setHeader("code", "20000"); ExportUtils.export(out, report, p); long end = System.currentTimeMillis(); ToolUtils.logToConsole("获取打印文件耗时:" + (end - start) + "ms"); } catch (Exception ex) { + log.error("模版预览打印异常", ex); throw new ReportException(ex); } } @@ -435,13 +449,81 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { // 创建下载文件 ProducerEnum p = ProducerEnum.valueOf(type.toUpperCase()); String downFileName = com.bstek.common.utils.StringUtils.randomFileName() + com.bstek.common.utils.StringUtils.getFileSuffix(p); - response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downFileName, UTF8_CHARSET)); + response.setHeader(Header.CONTENT_DISPOSITION.getValue(), ATTACHMENT_PREFIX + URLEncoder.encode(downFileName, UTF8_CHARSET)); response.setHeader("code", "20000"); long start = System.currentTimeMillis(); ExportUtils.export(out, report, p); long end = System.currentTimeMillis(); ToolUtils.logToConsole("下载 " + type + " 报表耗时:" + (end - start) + "ms"); } catch (Exception ex) { + log.error("模版预览下载文件异常", ex); + throw new ReportException(ex); + } + } + + @Override + public void exportTemplate(Long templateId, HttpServletResponse response) { + ReportTemplateDO reportTemplateDO = validateTemplateExists(templateId); + if (ObjectUtil.isNull(reportTemplateDO)) { + throw exception(TEMPLATE_NOT_EXISTS); + } + PrintWriter writer = null; + try { + // 模版关键信息 + JSONObject exportObj = new JSONObject(); + exportObj.put("content", reportTemplateDO.getContent()); + Set datasourceIds = reportTemplateDO.getDatasourceIds(); + exportObj.put(DATASOURCEIDS_FIELD_NAME, CollUtil.isNotEmpty(datasourceIds) ? datasourceIds : Set.of()); + Set datasetIds = reportTemplateDO.getDatasetIds(); + exportObj.put(DATASETIDS_FIELD_NAME, CollUtil.isNotEmpty(datasetIds) ? datasourceIds : Set.of()); + + // 设置响应的内容类型为 application/json + response.setContentType(ContentType.JSON.getValue()); + response.setCharacterEncoding(UTF8_CHARSET); + response.setHeader(Header.CONTENT_DISPOSITION.getValue(), ATTACHMENT_PREFIX + URLEncoder.encode(String.format("%s.json", reportTemplateDO.getName()), UTF8_CHARSET)); + + // 写入响应的输出流 + writer = response.getWriter(); + writer.print(exportObj.toJSONString()); + writer.flush(); + } catch (Exception ex) { + log.error("模板导出异常", ex); + throw new ReportException(ex); + } finally { + IoUtil.close(writer); + } + } + + @Override + public void importTemplate(String name, MultipartFile file) { + try { + // 读取文件json + String templateStr = IoUtil.read(file.getInputStream(), UTF8_CHARSET); + JSONObject jsonObject = JSON.parseObject(templateStr); + + boolean isSuperAdmin = SecurityFrameworkUtils.isSuperAdmin(); + + ReportTemplateSaveReqVO createReqVO = new ReportTemplateSaveReqVO(); + createReqVO.setName(name); + // 校验模板名唯一性 + validateTemplateNameUnique(createReqVO, isSuperAdmin); + // 复制信息 + createReqVO.setContent(jsonObject.getString("content")); + createReqVO.setDatasetIds(jsonObject.getJSONArray(DATASETIDS_FIELD_NAME).stream().map(s -> Long.parseLong(s.toString())).collect(Collectors.toSet())); + createReqVO.setDatasourceIds(jsonObject.getJSONArray(DATASOURCEIDS_FIELD_NAME).stream().map(s -> Long.parseLong(s.toString())).collect(Collectors.toSet())); + // 新增模板 + ReportTemplateDO template = BeanUtils.toBean(createReqVO, ReportTemplateDO.class); + // 超管创建的作为内置模板 + if (isSuperAdmin) { + template.setType(ReportTemplateTypeEnum.SYSTEM); + } else { + template.setType(ReportTemplateTypeEnum.CUSTOM); + } + templateMapper.insert(template); + } catch (ServiceException sex) { + throw sex; + } catch (Exception ex) { + log.error("模板导入异常", ex); throw new ReportException(ex); } } @@ -474,22 +556,4 @@ public class ReportTemplateServiceImpl implements ReportTemplateService { parameters.put("pageIndex", params.getPageIndex()); return reportDefinition; } - - /** - * 模板生成文件类型校验 - * - * @param type - */ - private void validateProducerType(String type) { - boolean match = false; - for (ProducerEnum producerEnum : ProducerEnum.values()) { - if (Objects.equals(producerEnum.name(), type.toUpperCase())) { - match = true; - break; - } - } - if (!match) { - throw new ReportException("类型错误,请检查是否PDF/WORD/EXCEL"); - } - } }