1、报表新增接口:复制模版、模板预览打印、模版预览下载,ureport-community字体加载问题修复;2、站内信列表移除userType入参,回调数据不返回userId和userType;

This commit is contained in:
gaoqr
2024-09-02 18:47:04 +08:00
parent 7c1c837ec4
commit 80dc750a26
26 changed files with 308 additions and 39 deletions
@@ -6,6 +6,7 @@ import com.bstek.designer.excel.ExcelParserUtils;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.dsl.ReportParserLexer;
import com.bstek.ureport.dsl.ReportParserParser;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.ExportUtils;
import com.bstek.ureport.export.ProducerEnum;
import com.bstek.ureport.export.html.HtmlReport;
@@ -21,6 +22,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.service.template.ReportTemplateService;
import com.cf.imes.module.report.validation.template.ReportTemplateProducerTypeInEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,7 +33,6 @@ import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.commons.io.IOUtils;
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.*;
import org.springframework.web.multipart.MultipartFile;
@@ -64,14 +65,21 @@ public class ReportTemplateController {
private ReportTemplateService templateService;
@PutMapping("/template")
@Operation(summary = "创建报表模板信息")
@Operation(summary = "创建报表模板")
// @PreAuthorize("@ss.hasPermission('report:template:create')")
public CommonResult<Long> createTemplate(@Valid @RequestBody ReportTemplateSaveReqVO createReqVO) {
return success(templateService.createReportTemplate(createReqVO));
}
@PutMapping("/template/copy")
@Operation(summary = "复制报表模板")
// @PreAuthorize("@ss.hasPermission('report:template:create')")
public CommonResult<Long> copyTemplate(@Valid @RequestBody ReportTemplateSaveReqVO createReqVO) {
return success(templateService.copyReportTemplate(createReqVO));
}
@PostMapping("/template")
@Operation(summary = "更新报表模板信息")
@Operation(summary = "更新报表模板")
// @PreAuthorize("@ss.hasPermission('report:template:update')")
public CommonResult<Boolean> updateTemplate(@Valid @RequestBody ReportTemplateSaveReqVO updateReqVO) {
templateService.updateReportTemplate(updateReqVO);
@@ -79,7 +87,7 @@ public class ReportTemplateController {
}
@DeleteMapping("/template/{id}")
@Operation(summary = "删除报表模板信息")
@Operation(summary = "删除报表模板")
@Parameter(name = "id", description = "模板id", required = true)
// @PreAuthorize("@ss.hasPermission('report:template:delete')")
public CommonResult<Boolean> deleteReportTemplate(@PathVariable("id") Long id) {
@@ -110,6 +118,18 @@ public class ReportTemplateController {
return success(templateService.preview(params));
}
@PostMapping("/template/print")
@Operation(summary = "模板预览打印")
public void print(@RequestBody PreviewParameters reportParameters, HttpServletResponse response) {
templateService.print(reportParameters, response);
}
@PostMapping("/template/download/{type}")
@Operation(summary = "模板预览下载")
public void print(@PathVariable @Valid @ReportTemplateProducerTypeInEnum String type, @RequestBody PreviewParameters reportParameters, HttpServletResponse response) {
templateService.download(type, reportParameters, response);
}
@PostMapping("/template/export")
@Operation(summary = "模板导出")
// @PreAuthorize("@ss.hasPermission('report:template:query')")
@@ -120,6 +140,8 @@ public class ReportTemplateController {
out = response.getOutputStream();
ProducerEnum p = ProducerEnum.valueOf(reqDTO.getProducerType().toUpperCase());
ExportUtils.export(out, report, p);
} catch (ReportException rex) {
throw rex;
} catch (Exception ex) {
log.error("[generateExcel] 报表模板生成excel异常", ex);
} finally {
@@ -0,0 +1,28 @@
package com.cf.imes.module.report.framework.ureport.bean;
import com.cf.imes.module.report.framework.ureport.annotation.CfReportSpringbeanDatasource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Gqr
* @since 2024/9/2 9:38
*/
@CfReportSpringbeanDatasource(value = "MockSpringBeanDatasource", name = "模拟springbean数据源")
public class MockSpringBeanDatasource {
public List<Map<String, Object>> mockResult(String dsName, String datasetName, Map<String, Object> parameters) {
List<Map<String, Object>> resultList = new ArrayList<>();
Map<String, Object> resultMap1 = new HashMap<>();
resultMap1.put("key", 1);
resultMap1.put("value", "模拟1");
Map<String, Object> resultMap2 = new HashMap<>();
resultMap2.put("key", 2);
resultMap2.put("value", "模拟2");
return resultList;
}
}
@@ -0,0 +1,27 @@
package com.cf.imes.module.report.framework.web.core.handler;
import com.bstek.ureport.exception.ReportException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.CommonResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 自定义报表异常处理器
*
* @author Gqr
* @since 2024/9/2 14:52
*/
@RestControllerAdvice
@AllArgsConstructor
@Slf4j
public class ReportExceptionHandler {
@ExceptionHandler(value = ReportException.class)
public CommonResult<?> reportExceptionHandler(ReportException ex) {
log.warn("[reportExceptionHandler]", ex);
return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), String.format("报表异常:%s", ex.getMessage()));
}
}
@@ -9,6 +9,7 @@ import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateReqV
import com.cf.imes.module.report.controller.admin.template.vo.ReportTemplateSaveReqVO;
import com.cf.imes.module.report.dal.dataobject.template.ReportTemplateDO;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
@@ -20,7 +21,7 @@ import java.util.List;
*/
public interface ReportTemplateService {
/**
* 创建报表模板信息
* 创建报表模板
*
* @param createReqVO 创建信息
* @return 编号
@@ -28,14 +29,21 @@ public interface ReportTemplateService {
Long createReportTemplate(@Valid ReportTemplateSaveReqVO createReqVO);
/**
* 更新报表模板信息
* 复制报表模
* @param createReqVO
* @return
*/
Long copyReportTemplate(@Valid ReportTemplateSaveReqVO createReqVO);
/**
* 更新报表模板
*
* @param updateReqVO 更新信息
*/
void updateReportTemplate(@Valid ReportTemplateSaveReqVO updateReqVO);
/**
* 删除报表模板信息
* 删除报表模板
*
* @param id 编号
*/
@@ -81,4 +89,18 @@ public interface ReportTemplateService {
* @return
*/
Report generateReport(ReportTemplateGenerateReqDTO dto);
/**
* 模版预览打印
*/
void print(PreviewParameters params, HttpServletResponse response);
/**
* 模版预览下载
*
* @param type 文件类型
* @param params
* @param response
*/
void download(String type, PreviewParameters params, HttpServletResponse response);
}
@@ -19,11 +19,16 @@ import com.bstek.ureport.definition.datasource.DatasourceDefinition;
import com.bstek.ureport.definition.datasource.JdbcDatasourceDefinition;
import com.bstek.ureport.definition.datasource.SpringBeanDatasourceDefinition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.ExportUtils;
import com.bstek.ureport.export.ProducerEnum;
import com.bstek.ureport.export.ReportRender;
import com.bstek.ureport.export.html.HtmlProducer;
import com.bstek.ureport.export.html.HtmlReport;
import com.bstek.ureport.model.Report;
import com.bstek.ureport.parser.ReportParser;
import com.bstek.ureport.utils.ToolUtils;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
@@ -51,13 +56,17 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
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 static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.report.enums.ErrorCodeConstants.DATATEMPLATE_BUILDIN_OPERATION_PERMISSION_ERROR;
@@ -113,6 +122,51 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
return templateId;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long copyReportTemplate(ReportTemplateSaveReqVO createReqVO) {
Long templateId = createReqVO.getId();
// 校验存在
ReportTemplateDO reportTemplateDO = validateTemplateExists(templateId);
// 校验内置模板操作权限
validateSystemTemplate(reportTemplateDO);
ReportTemplateDO copyTemplateDO = BeanUtils.toBean(reportTemplateDO, ReportTemplateDO.class);
// 重置id
copyTemplateDO.setId(null);
copyTemplateDO.setName(createReqVO.getName());
// 新增模版
templateMapper.insert(copyTemplateDO);
Long newtemplateId = copyTemplateDO.getId();
// 复制datasource、dataset
List<ReportDatasourceDO> templateDatasourceList = datasourceService.getTemplateDatasourceList(ReportDatasourceReqVO.builder().templateId(templateId).build());
List<ReportDatasourceSaveReqVO> copyDatasourceList = new ArrayList<>();
// 遍历数据源
templateDatasourceList.forEach(ds -> {
ReportDatasourceSaveReqVO copyDatasourceSaveReqVO = JsonUtils.parseObject(JsonUtils.toJsonString(ds), ReportDatasourceSaveReqVO.class);
copyDatasourceSaveReqVO.setId(null);
copyDatasourceSaveReqVO.setTemplateId(newtemplateId);
List<ReportDatasetDO> templateDatasetList = ds.getDatasets();
// 遍历数据集
if (CollUtil.isNotEmpty(templateDatasetList)) {
List<ReportDatasetSaveReqVO> copyDatasetList = new ArrayList<>();
templateDatasetList.forEach(dt -> {
ReportDatasetSaveReqVO copyDatasetSaveReqVO = BeanUtils.toBean(dt, ReportDatasetSaveReqVO.class);
copyDatasetSaveReqVO.setId(null);
copyDatasetSaveReqVO.setDatasourceId(null);
copyDatasetList.add(copyDatasetSaveReqVO);
});
copyDatasourceSaveReqVO.setDatasets(copyDatasetList);
}
copyDatasourceList.add(copyDatasourceSaveReqVO);
});
// 更新数据源
analyzeDatasource(copyDatasourceList, newtemplateId);
// 返回主键
return newtemplateId;
}
/**
* 解析数据源集合并入库
*
@@ -120,6 +174,9 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
* @param templateId 模板id
*/
private void analyzeDatasource(List<ReportDatasourceSaveReqVO> datasource, Long templateId) {
if (CollUtil.isEmpty(datasource)) {
return;
}
datasource.forEach(ds -> {
// 更新/新增数据源
Long datasourceId;
@@ -334,6 +391,56 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
return htmlProducer.produce(reportDefinition, report);
}
@Override
public void print(PreviewParameters params, HttpServletResponse response) {
long start = System.currentTimeMillis();
ReportRender reportRender = new ReportRender();
ReportDefinition reportDefinition = getReportDefinition(reportRender, params);
Report report = reportRender.render(reportDefinition, params.getQuery());
Map<String, String> chartImages = params.getChartImages();
report.setChartImages(chartImages);
try {
OutputStream out = response.getOutputStream();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/pdf; charset=UTF-8");
// 创建下载文件
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, "UTF-8"));
response.setHeader("code", "20000");
ExportUtils.export(out, report, p);
long end = System.currentTimeMillis();
ToolUtils.logToConsole("获取打印文件耗时:" + (end - start) + "ms");
} catch (Exception ex) {
throw new ReportException(ex);
}
}
@Override
public void download(String type, PreviewParameters params, HttpServletResponse response) {
ReportRender reportRender = new ReportRender();
ReportDefinition reportDefinition = getReportDefinition(reportRender, params);
Report report = reportRender.render(reportDefinition, params.getQuery());
Map<String, String> chartImages = params.getChartImages();
report.setChartImages(chartImages);
try {
OutputStream out = response.getOutputStream();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream; charset=UTF-8");
// 创建下载文件
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, "UTF-8"));
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) {
throw new ReportException(ex);
}
}
private ReportDefinition getReportDefinition(ReportRender reportRender, PreviewParameters params) {
ReportDefinition reportDefinition;
@@ -366,6 +473,8 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
@Override
public Report generateReport(ReportTemplateGenerateReqDTO reqDTO) {
// 校验生成文件类型
validateProducerType(reqDTO.getProducerType());
Long templateId = reqDTO.getTemplateId();
// 校验模板
validateTemplateExists(templateId);
@@ -383,4 +492,22 @@ public class ReportTemplateServiceImpl implements ReportTemplateService {
return reportRender.render(reportDefinition, previewParameters.getQuery());
}
/**
* 模板生成文件类型校验
*
* @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");
}
}
}
@@ -0,0 +1,36 @@
package com.cf.imes.module.report.validation.template;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义报表模板生成文件类型入参校验注解
*
* @author Gqr
* @since 2024/7/17 9:33
*/
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER,
ElementType.TYPE_USE
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {ReportTemplateProducerTypeInEnumValidator.class}
)
public @interface ReportTemplateProducerTypeInEnum {
String message() default "类型错误,请检查是否PDF/WORD/EXCEL";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,37 @@
package com.cf.imes.module.report.validation.template;
import com.bstek.ureport.export.ProducerEnum;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Objects;
/**
* 自定义报表模板生成文件类型入参校验器
*
* @author Gqr
* @since 2024/7/17 9:33
*/
public class ReportTemplateProducerTypeInEnumValidator implements ConstraintValidator<ReportTemplateProducerTypeInEnum, String> {
@Override
public void initialize(ReportTemplateProducerTypeInEnum constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.isEmpty(value)) {
return false;
}
for (ProducerEnum producerEnum : ProducerEnum.values()) {
if (Objects.equals(producerEnum.name(), value.toUpperCase())) {
return true;
}
}
return false;
}
}