Bean、DTO、VO、Entity、Form...?

本文详细解释了Java项目中常见的模型类如Bean、DTO、VO、Entity及Form的区别与用途,帮助开发者更好地理解并选择合适的数据载体。
Java项目中,经常遇到很多具有统一命名规则的类。比如:XXXBean、XXXDTO、XXXEntity、XXXVO、XXXForm等。这些类大多被用于MVC的Model层,有很多共性。比如都具有私有属性、Setter/Getter,但具体什么时候该用什么呢。

[b](1)Bean[/b]
JavaBeans的简称,对于Java程序员来说是最不陌生的,即使是刚开始学Java,也会应该听说过它。它是Sun公司定义的一个程序组件,并且有明确的编码规范,比如:类应该有属性,而且是私有的,通过Setter/Getter方法来访问私有属性。

[url=http://baike.baidu.com/view/1006495.htm]http://baike.baidu.com/view/1006495.htm[/url]
[url=http://en.wikipedia.org/wiki/JavaBeans]http://en.wikipedia.org/wiki/JavaBeans[/url]
[url=http://docstore.mik.ua/orelly/java-ent/jnut/ch06_02.htm]http://docstore.mik.ua/orelly/java-ent/jnut/ch06_02.htm[/url]

[b](2)DTO[/b]
Data Transfer Object数据传输对象的简称,多用于多个系统之间,网络通信,数据库存取等。将调用或返回的数据保存在DTO中从而减少调用负载。它不包含业务逻辑处理,但可以有数据整合性的校验。DTO需要注意的是必须序列化,即implements Serializable。

[url=http://baike.baidu.com/view/160599.htm]http://baike.baidu.com/view/160599.htm[/url]
[url=http://en.wikipedia.org/wiki/Data_transfer_object]http://en.wikipedia.org/wiki/Data_transfer_object[/url]
[url=http://msdn.microsoft.com/en-us/library/ms978717.aspx]http://msdn.microsoft.com/en-us/library/ms978717.aspx[/url]
[url=http://martinfowler.com/bliki/LocalDTO.html]http://martinfowler.com/bliki/LocalDTO.html[/url]
[url=http://martinfowler.com/eaaCatalog/dataTransferObject.html]http://martinfowler.com/eaaCatalog/dataTransferObject.html[/url]

[b](3)VO[/b]
Value Object值对象的简称,敏捷开发方法的创始人之一Martin Fowler认为“Value Object as a small object such as a Money or date range object”。
主要用于领域驱动设计(Domain Driven Design),VO的值/实例一般是不会变的,比如下个月的第一个工作日。一般没有Setter方法通过构造函数设定值。

这个是最多被大家无解的。

[url=http://en.wikipedia.org/wiki/Value_object]http://en.wikipedia.org/wiki/Value_object[/url]
[url=http://martinfowler.com/bliki/ValueObject.html]http://martinfowler.com/bliki/ValueObject.html[/url]

[b](4)Entity[/b]
实体,多用于DB中以表为单位存取数据,类中定义了表的每个字段的Setter/Getter。一个Entity实例即为表中的一条数据。起源于EJB,比如EJB1.x、2.x中的EntityBean,EJB3.x的JPA。

[b](5)Form[/b]
起源于Struts,现在也常用语Spring中。主要用于接收页面表单中的数据或者页面显示用数据的存储,包含校验Validate方法。

[b]综上[/b]
VO多用于金钱或者时间等代表价值的对象,比较特殊。
JavaBean更像是一个总称,他包含了Form(与页面交互)、DTO(各种信息的集合体)、Entity(与DB交互)

[b]其他[/b]
1)POJO
Plain Old Java Object简单Java对象的简称,多用于和EJB的复杂做对比。不被框架,对象模型,规约等约束,也不依存于这些东西。

2)Domain Object
域对象
package com.hvlink.service.impl; import com.alibaba.nacos.common.utils.StringUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.hvlink.entity.dto.asn.AsnPackDTO; import com.hvlink.entity.param.asn.AsnPackExportParam; import com.hvlink.entity.param.asn.AsnPackLabelParam; import com.hvlink.entity.po.asn.AsnPackPO; import com.hvlink.entity.vo.asn.AsnPackLabelVO; import com.hvlink.mapper.asn.AsnPackMapper; import com.hvlink.pagination.PageResult; import com.hvlink.service.IAsnPackService; import com.hvlink.utils.BeanCopyUtils; import com.hvlink.utils.QRCodeUtils; import com.itextpdf.text.Image; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; /** * ASN包装信息(AsnPack)表服务实现类 * * @author sunzhuang * @since 2025-09-23 16:39:02 */ @Slf4j @RequiredArgsConstructor @Service("asnPackService") public class AsnPackServiceImpl extends ServiceImpl<AsnPackMapper, AsnPackPO> implements IAsnPackService { private final AsnPackMapper asnPackMapper; /** * 查询标签信息 * * @param asnPackLabelParam 请求参数 * @return 查询结果 */ @Override public PageResult<AsnPackLabelVO> queryPage(AsnPackLabelParam asnPackLabelParam) { // 查询标签数据 Page<AsnPackDTO> page = new Page<>(asnPackLabelParam.getPageIndex(), asnPackLabelParam.getPageSize()); Page<AsnPackDTO> dtoPage = asnPackMapper.queryLabelPage(page, asnPackLabelParam); // 转换 DTOVO List<AsnPackLabelVO> voList = Collections.emptyList(); if (!CollectionUtils.isEmpty(dtoPage.getRecords())) { voList = dtoPage.getRecords().stream() .map(dto -> BeanCopyUtils.copyBean(dto, AsnPackLabelVO.class)) .collect(Collectors.toList()); } // 构建分页结果 PageResult<AsnPackLabelVO> result = new PageResult<>(); result.setRecords(voList); result.setTotal(dtoPage.getTotal()); result.setPageIndex(asnPackLabelParam.getPageIndex()); result.setPageSize(asnPackLabelParam.getPageSize()); return result; } @Override public Mono<ResponseEntity<Resource>> exportLabels(AsnPackExportParam exportParam) { return Mono.defer(() -> { try { // 参数验证 if (exportParam == null || exportParam.getIds() == null || exportParam.getIds().isEmpty()) { return Mono.error(new IllegalArgumentException("导出参数或ID列表不能为空")); } // 查询导出数据 List<AsnPackDTO> exportData = asnPackMapper.selectByIds(exportParam.getIds()); if (exportData.isEmpty()) { return Mono.error(new RuntimeException("未找到导出数据")); } // 验证导出类型 if (!isValidExportType(exportParam.getExportType())) { return Mono.error(new IllegalArgumentException("不支持的导出类型: " + exportParam.getExportType())); } // 根据导出类型选择模板 String templatePath = getTemplatePath(exportParam.getExportType()); // 生成PDF字节数组 byte[] pdfBytes = generatePdfBytes(exportData, exportParam.getExportType(), templatePath); // 创建资源 Resource resource = new ByteArrayResource(pdfBytes); // 设置响应头 String fileName = buildFileName(exportParam.getExportType()); ResponseEntity<Resource> responseEntity = ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName) .contentType(MediaType.APPLICATION_PDF) .contentLength(pdfBytes.length) .body(resource); return Mono.just(responseEntity); } catch (Exception e) { log.error("标签导出失败", e); return Mono.error(new RuntimeException("标签导出失败: " + e.getMessage())); } }); } private String getTemplatePath(String exportType) { switch (exportType.toUpperCase()) { case "P": return "static/templates/托标签模板.pdf"; // 托标签模板 case "C": return "static/templates/箱标签模板.pdf"; // 箱标签模板 case "B": return "static/templates/包标签模板.pdf"; // 包标签模板 default: throw new IllegalArgumentException("不支持的导出类型: " + exportType); } } private boolean isValidExportType(String exportType) { if (exportType == null) return false; String type = exportType.toUpperCase(); return type.equals("P") || type.equals("C") || type.equals("B"); } private String buildFileName(String exportType) { String typeName = ""; switch (exportType.toUpperCase()) { case "P": typeName = "托标签"; break; case "C": typeName = "箱标签"; break; case "B": typeName = "包标签"; break; default: typeName = "标签"; } return typeName + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".pdf"; } private byte[] generatePdfBytes(List<AsnPackDTO> data, String exportType, String templatePath) throws Exception { ClassPathResource templateResource = new ClassPathResource(templatePath); if (!templateResource.exists()) { throw new RuntimeException("模板文件不存在: " + templatePath); } try (InputStream templateStream = templateResource.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { PdfReader reader = new PdfReader(templateStream); PdfStamper stamper = new PdfStamper(reader, outputStream); AcroFields form = stamper.getAcroFields(); log.info("找到的表单字段: {}", form.getFields().keySet()); BaseFont simSunFont = BaseFont.createFont("C:/Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); form.addSubstitutionFont(simSunFont); // 填充表单数据 if (!data.isEmpty()) { fillFormFields(form, data.get(0), exportType); } stamper.setFormFlattening(true); stamper.close(); reader.close(); return outputStream.toByteArray(); } } private void fillFormFields(com.itextpdf.text.pdf.AcroFields form, AsnPackDTO item, String exportType) throws Exception { Map<String, String> fieldValues = buildFieldValues(item, exportType); log.info("要填充的数据: {}", fieldValues); // 填充表单字段 for (Map.Entry<String, String> entry : fieldValues.entrySet()) { String fieldName = entry.getKey(); String fieldValue = entry.getValue(); if (form.getFields().containsKey(fieldName)) { if (StringUtils.hasText(fieldValue)) { try { form.setField(fieldName, fieldValue); log.info("成功填充字段: {} = {}", fieldName, fieldValue); } catch (Exception e) { log.error("填充字段失败: {}, 值: {}", fieldName, fieldValue, e); } } else { log.warn("字段值为空: {}", fieldName); } } else { log.warn("未找到表单字段: {}", fieldName); } } } private Map<String, String> buildFieldValues(AsnPackDTO item, String exportType) { Map<String, String> values = new HashMap<>(); // 公共字段 values.put("part_desc", item.getPartDesc()); values.put("part_code", item.getPartCode()); values.put("supplier_name", item.getSupplierName()); values.put("supplier_code", item.getSupplierCode()); values.put("order_no", item.getAsnNo()); values.put("production_batch", item.getProductionBatch()); values.put("case_code", generateCaseCode(item, exportType)); values.put("remark", item.getRemark()); // 数量相关字段 switch (exportType.toUpperCase()) { case "P": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("P", item.getSupplierCode())); values.put("master_label", "MASTER LABEL " + item.getWarehouseCode()); break; case "C": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("C", item.getSupplierCode())); break; case "B": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("B", item.getSupplierCode())); break; } return values; } private String generateCaseCode(AsnPackDTO item, String exportType) { switch (exportType.toUpperCase()) { case "P": return "1/1"; // X/Y格式 case "C": return "1/5-1"; // X/Y-Z格式 case "B": return "1/10-C-1"; // X/Y-C-Z格式 default: return item.getCaseCode(); } } private String generateUniqueCode(String prefix, String supplierCode) { SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); String dateStr = sdf.format(new Date()); // 这里需要生成6位流水号,可以从数据库获取或使用序列 String sequence = String.format("%06d", System.currentTimeMillis() % 1000000); return prefix + supplierCode + dateStr + sequence; } private String formatQuantity(Double quantity) { return quantity != null ? String.valueOf(quantity) : "0"; } private void addQRCode(PdfStamper stamper, AcroFields form, AsnPackDTO item, String exportType) throws Exception { try { String uniqueCode = generateUniqueCode( exportType.equals("P") ? "P" : exportType.equals("C") ? "C" : "B", item.getSupplierCode() ); // 生成二维码图片 ByteArrayOutputStream qrCodeStream = QRCodeUtils.generateQRCode(uniqueCode, 100, 100); byte[] qrCodeBytes = qrCodeStream.toByteArray(); Image qrCodeImage = Image.getInstance(qrCodeBytes); // 获取二维码字段位置 if (form.getFields().containsKey("QRcode")) { int pageNo = form.getFieldPositions("QRcode").get(0).page; Rectangle rect = form.getFieldPositions("QRcode").get(0).position; // 获取操作层 PdfContentByte content = stamper.getOverContent(pageNo); // 设置图片位置大小 qrCodeImage.setAbsolutePosition(rect.getLeft(), rect.getBottom()); qrCodeImage.scaleToFit(rect.getWidth(), rect.getHeight()); // 添加图片 content.addImage(qrCodeImage); } } catch (Exception e) { log.warn("生成二维码失败: {}", e.getMessage()); } } } 我现在导出后,PDF上除了填充的字段,其他的都不显示,导致导出后PDF的内容只有填充的字段,请根据这个人的写法,帮我修改,看看能不能修复 public static void main(String[] args){ //TODO 模板替换 String inputFileName = "/test/template/template_v1.pdf"; FileOutputStream os = null; PdfStamper ps = null; PdfReader reader = null; try { // 1 获取文件的输出流 os = new FileOutputStream(new File("/test/template/data.pdf")); // 2 读取pdf模板 reader = new PdfReader(inputFileName); // 3 根据表单生成一个新的pdf ps = new PdfStamper(reader, os); // 4 获取pdf表单 AcroFields form = ps.getAcroFields(); // 5 给表单添加中文字体 // TODO 字体替换 注意文件后缀大写、逗号0 BaseFont bf = BaseFont.createFont("/test/template/simsun.TTC,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); form.addSubstitutionFont(bf); //6填充模板表单数据 form.setField("name","张三"); form.setField("phone","18977546523"); form.setField("address","地球村北京"); ps.setFormFlattening(true); // 7 填充图片到form PdfStamper stamper = ps; // 通过域名获取所在页坐标,左下角为起点 int pageno = form.getFieldPositions("photo").get(0).page; Rectangle signrect = form.getFieldPositions("photo").get(0).position; float x = signrect.getLeft(); //float width = signrect.getWidth(); float y = signrect.getBottom(); // 读图片 Image image = Image.getInstance("F:\\test\\template\\photo.jpg"); //float img_width = image.getWidth(); // 获取操作的页面 PdfContentByte under = stamper.getOverContent(pageno); // 添加图片 image.setAbsolutePosition(x, y); // 图片的大小 image.scaleToFit(signrect.getWidth(), signrect.getHeight()); under.addImage(image); } catch (Exception e) { e.printStackTrace(); } finally { try { ps.close(); reader.close(); os.close(); } catch (Exception e) { e.printStackTrace(); } } }
10-09
package com.hvlink.service.impl; import com.alibaba.nacos.common.utils.StringUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.hvlink.entity.dto.asn.AsnPackDTO; import com.hvlink.entity.param.asn.AsnPackExportParam; import com.hvlink.entity.param.asn.AsnPackLabelParam; import com.hvlink.entity.po.asn.AsnPackPO; import com.hvlink.entity.vo.asn.AsnPackLabelVO; import com.hvlink.mapper.asn.AsnPackMapper; import com.hvlink.pagination.PageResult; import com.hvlink.service.IAsnPackService; import com.hvlink.utils.BeanCopyUtils; import com.hvlink.utils.QRCodeUtils; import com.itextpdf.text.Image; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; /** * ASN包装信息(AsnPack)表服务实现类 * * @author sunzhuang * @since 2025-09-23 16:39:02 */ @Slf4j @RequiredArgsConstructor @Service("asnPackService") public class AsnPackServiceImpl extends ServiceImpl<AsnPackMapper, AsnPackPO> implements IAsnPackService { private final AsnPackMapper asnPackMapper; /** * 查询标签信息 * * @param asnPackLabelParam 请求参数 * @return 查询结果 */ @Override public PageResult<AsnPackLabelVO> queryPage(AsnPackLabelParam asnPackLabelParam) { // 查询标签数据 Page<AsnPackDTO> page = new Page<>(asnPackLabelParam.getPageIndex(), asnPackLabelParam.getPageSize()); Page<AsnPackDTO> dtoPage = asnPackMapper.queryLabelPage(page, asnPackLabelParam); // 转换 DTOVO List<AsnPackLabelVO> voList = Collections.emptyList(); if (!CollectionUtils.isEmpty(dtoPage.getRecords())) { voList = dtoPage.getRecords().stream() .map(dto -> BeanCopyUtils.copyBean(dto, AsnPackLabelVO.class)) .collect(Collectors.toList()); } // 构建分页结果 PageResult<AsnPackLabelVO> result = new PageResult<>(); result.setRecords(voList); result.setTotal(dtoPage.getTotal()); result.setPageIndex(asnPackLabelParam.getPageIndex()); result.setPageSize(asnPackLabelParam.getPageSize()); return result; } @Override public Mono<ResponseEntity<Resource>> exportLabels(AsnPackExportParam exportParam) { return Mono.defer(() -> { try { // 参数验证 if (exportParam == null || exportParam.getIds() == null || exportParam.getIds().isEmpty()) { return Mono.error(new IllegalArgumentException("导出参数或ID列表不能为空")); } // 查询导出数据 List<AsnPackDTO> exportData = asnPackMapper.selectByIds(exportParam.getIds()); if (exportData.isEmpty()) { return Mono.error(new RuntimeException("未找到导出数据")); } // 验证导出类型 if (!isValidExportType(exportParam.getExportType())) { return Mono.error(new IllegalArgumentException("不支持的导出类型: " + exportParam.getExportType())); } // 根据导出类型选择模板 String templatePath = getTemplatePath(exportParam.getExportType()); // 生成PDF字节数组 byte[] pdfBytes = generatePdfBytes(exportData, exportParam.getExportType(), templatePath); // 创建资源 Resource resource = new ByteArrayResource(pdfBytes); // 设置响应头 String fileName = buildFileName(exportParam.getExportType()); ResponseEntity<Resource> responseEntity = ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName) .contentType(MediaType.APPLICATION_PDF) .contentLength(pdfBytes.length) .body(resource); return Mono.just(responseEntity); } catch (Exception e) { log.error("标签导出失败", e); return Mono.error(new RuntimeException("标签导出失败: " + e.getMessage())); } }); } private String getTemplatePath(String exportType) { switch (exportType.toUpperCase()) { case "P": return "static/templates/P.pdf"; // 托标签模板 case "C": return "static/templates/C.pdf"; // 箱标签模板 case "B": return "static/templates/B.pdf"; // 包标签模板 default: throw new IllegalArgumentException("不支持的导出类型: " + exportType); } } private boolean isValidExportType(String exportType) { if (exportType == null) return false; String type = exportType.toUpperCase(); return type.equals("P") || type.equals("C") || type.equals("B"); } private String buildFileName(String exportType) { String typeName = ""; switch (exportType.toUpperCase()) { case "P": typeName = "托标签"; break; case "C": typeName = "箱标签"; break; case "B": typeName = "包标签"; break; default: typeName = "标签"; } return typeName + "_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".pdf"; } private byte[] generatePdfBytes(List<AsnPackDTO> data, String exportType, String templatePath) throws Exception { ClassPathResource templateResource = new ClassPathResource(templatePath); if (!templateResource.exists()) { throw new RuntimeException("模板文件不存在: " + templatePath); } try (InputStream templateStream = templateResource.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { PdfReader reader = new PdfReader(templateStream); PdfStamper stamper = new PdfStamper(reader, outputStream); AcroFields form = stamper.getAcroFields(); // 添加中文字体支持 BaseFont simSunFont = BaseFont.createFont("C:/Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); form.addSubstitutionFont(simSunFont); // 填充第一个数据项 AsnPackDTO item = data.get(0); fillFormFields(form, item, exportType); // 添加二维码到指定位置 addQRCode(stamper, form, item, exportType); stamper.setFormFlattening(true); // 将表单转为静态文本 stamper.close(); // 关闭 stamper 会自动写入修改后的内容 reader.close(); return outputStream.toByteArray(); } } private void fillFormFields(AcroFields form, AsnPackDTO item, String exportType) throws Exception { Map<String, String> fieldValues = buildFieldValues(item, exportType); log.info("要填充的数据: {}", fieldValues); // 填充表单字段 for (Map.Entry<String, String> entry : fieldValues.entrySet()) { String fieldName = entry.getKey(); String fieldValue = entry.getValue(); if (form.getFields().containsKey(fieldName)) { if (StringUtils.hasText(fieldValue)) { try { form.setField(fieldName, fieldValue); log.info("成功填充字段: {} = {}", fieldName, fieldValue); } catch (Exception e) { log.error("填充字段失败: {}, 值: {}", fieldName, fieldValue, e); } } else { log.warn("字段值为空: {}", fieldName); } } else { log.warn("未找到表单字段: {}", fieldName); } } } private Map<String, String> buildFieldValues(AsnPackDTO item, String exportType) { Map<String, String> values = new HashMap<>(); // 公共字段 values.put("part_desc", item.getPartDesc()); values.put("part_code", item.getPartCode()); values.put("supplier_name", item.getSupplierName()); values.put("supplier_code", item.getSupplierCode()); values.put("order_no", item.getAsnNo()); values.put("production_batch", item.getProductionBatch()); values.put("case_code", generateCaseCode(item, exportType)); values.put("remark", item.getRemark()); // 数量相关字段 switch (exportType.toUpperCase()) { case "P": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("P", item.getSupplierCode())); values.put("master_label", "MASTER LABEL " + item.getWarehouseCode()); break; case "C": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("C", item.getSupplierCode())); break; case "B": values.put("quantity", formatQuantity(item.getQuantity())); values.put("pack_quantity", formatQuantity(item.getPackQuantity())); values.put("unique_code", generateUniqueCode("B", item.getSupplierCode())); break; } return values; } private String generateCaseCode(AsnPackDTO item, String exportType) { switch (exportType.toUpperCase()) { case "P": return "1/1"; // X/Y格式 case "C": return "1/5-1"; // X/Y-Z格式 case "B": return "1/10-C-1"; // X/Y-C-Z格式 default: return item.getCaseCode(); } } private String generateUniqueCode(String prefix, String supplierCode) { SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd"); String dateStr = sdf.format(new Date()); String sequence = String.format("%06d", System.currentTimeMillis() % 1000000); return prefix + supplierCode + dateStr + sequence; } private String formatQuantity(Double quantity) { return quantity != null ? String.valueOf(quantity) : "0"; } private void addQRCode(PdfStamper stamper, AcroFields form, AsnPackDTO item, String exportType) throws Exception { try { String uniqueCode = generateUniqueCode( exportType.equals("P") ? "P" : exportType.equals("C") ? "C" : "B", item.getSupplierCode() ); // 生成二维码 ByteArrayOutputStream qrCodeStream = QRCodeUtils.generateQRCode(uniqueCode, 100, 100); Image qrCodeImage = Image.getInstance(qrCodeStream.toByteArray()); // 获取字段位置 List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions("QRcode"); if (fieldPositions == null || fieldPositions.isEmpty()) { log.warn("未找到 QRcode 字段的位置信息"); return; } AcroFields.FieldPosition position = fieldPositions.get(0); int pageNo = position.page; Rectangle rect = position.position; PdfContentByte canvas = stamper.getOverContent(pageNo); // 使用上层绘制,避免干扰底层 qrCodeImage.setAbsolutePosition(rect.getLeft(), rect.getBottom()); qrCodeImage.scaleToFit(rect.getWidth(), rect.getHeight()); canvas.addImage(qrCodeImage); } catch (Exception e) { log.error("添加二维码失败", e); throw e; // 显式抛出便于调试 } } } 我的导出文件名为什么没有生效?导出的名字是ec9e0590-bc96-4a99-b42d-f429a8c4e598.pdf
最新发布
10-10
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值