Spring Boot中JasperReport函数编写及日期格式化问题求助
问题解答
一、Spring Boot中JasperReport相关函数优化
你的现有代码已经搭建了基础框架,可从以下几点优化,让代码更规范、稳定:
1. 修正参数与调用逻辑
createReport方法中的and should be date是占位符,需替换为实际日期参数,同时同步修改Controller的接口参数:
Controller修改:
@GetMapping("reportI") public ResponseEntity<?> getReport(String z, @RequestParam LocalDate date) throws JRException, IOException{ if(!s.existZ(z)) { throw new CustomException4("custom4", z); } byte[] report = s.createReport(z, date); if(report==null) { throw new CustomException4("custom4", z); } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/pdf")); headers.setContentDispositionFormData("attachment", "pdfName.pdf"); return ResponseEntity.ok().headers(headers).body(report); }
Service的createReport方法修正:
public byte[] createReport(String z, LocalDate date) throws JRException, IOException { List<IZ> dataList = ir.getIZByZAndDate(z, date); // 假设Repository有按z和日期查询的方法 if (CollectionUtils.isEmpty(dataList)) { return null; } // 用try-with-resources自动关闭流,避免资源泄漏 try (InputStream inputStream = this.getClass().getResourceAsStream("/jasperreports/nameOfJrxml.jrxml")) { JasperReport jasperReport = JasperCompileManager.compileReport(inputStream); Map<String, Object> params = new HashMap<>(); params.put("z", z); params.put("reportDate", date); // 将日期传入报表参数 JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(dataList); JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, dataSource); try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { JRPdfExporter exporter = new JRPdfExporter(); exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(byteArrayOutputStream)); exporter.exportReport(); return byteArrayOutputStream.toByteArray(); } } }
2. 生产环境性能优化
- 避免每次请求编译
.jrxml:提前将模板编译成.jasper二进制文件,放在resources/jasperreports/下,加载时改用:
JasperReport jasperReport = JasperLoadManager.loadReport(inputStream);
- 可将JasperReport实例注册为Spring单例Bean,复用实例减少重复加载开销。
3. 异常处理增强
Service层不要返回null,建议抛出自定义异常,统一由Controller的@ExceptionHandler处理:
if (CollectionUtils.isEmpty(dataList)) { throw new CustomException4("No data found for given z and date", z + " | " + date); }
二、MySQL日期解析与格式化(yyyy-MM-dd)
针对报表日期格式化,提供三种可行方案:
方案1:DTO层提前格式化
在IZ对应的DTO中新增格式化后的日期字段,转换逻辑放在DTO中:
public class IZDTO { // 其他字段 private String formattedDate; // 针对java.util.Date的转换 public void setDate(Date date) { if (date != null) { this.formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(date); } } // 针对Java 8+ LocalDate的转换 public void setLocalDate(LocalDate localDate) { if (localDate != null) { this.formattedDate = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); } } }
报表模板中直接引用$F{formattedDate}即可。
方案2:Jasper模板内直接格式化
如果实体类日期字段是java.util.Date或java.time.LocalDate,可在模板文本框表达式中直接格式化:
- 针对
java.util.Date:
new SimpleDateFormat("yyyy-MM-dd").format($F{dateField})
- 针对
java.time.LocalDate(需确保JasperReports版本支持Java 8时间API):
$F{localDateField}.format(DateTimeFormatter.ISO_LOCAL_DATE)
也可在模板字段属性中设置Pattern为yyyy-MM-dd(仅针对Date类型字段)。
方案3:Service层处理数据源时转换
构造数据源前手动转换日期字段:
List<IZ> dataList = ir.getIZByZAndDate(z, date); List<Map<String, Object>> formattedData = new ArrayList<>(); DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; for (IZ item : dataList) { Map<String, Object> map = new HashMap<>(); map.put("z", item.getZ()); map.put("formattedDate", item.getDate().toLocalDate().format(formatter)); // 其他字段映射 formattedData.add(map); } JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(formattedData);
适用于无需DTO、直接用Map传递数据的场景。
内容的提问来源于stack exchange,提问作者user23800914
相关产品推荐
相关产品推荐

