栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java生成pdf文件或jpg图片的案例讲解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java生成pdf文件或jpg图片的案例讲解

在一些业务场景中,需要生成pdf文件或者jpg图片,有时候还需要带上水印。我们可以事先用freemarker定义好html模板,然后把模板转换成pdf或jpg文件。

同时freemarker模板还支持变量的定义,在使用时可以填充具体的业务数据。

1、Maven导包

 org.springframework.boot
 spring-boot-starter-parent
 2.1.4.RELEASE


 
 
 org.springframework
 spring-context-support
 
 
 org.freemarker
 freemarker
 
 
 
 com.itextpdf
 itextpdf
 5.5.12
 
 
 
 com.itextpdf
 itext-asian
 5.2.0
 
 
 
 com.itextpdf.tool
 xmlworker
 5.5.12
 
 
 
 org.apache.pdfbox
 pdfbox
 2.0.5
 

2、接口定义

2.1、请求

@Data
public class GeneratePdfReq {
 
 @NotBlank(message = "生成pdf文件的绝对路径不能为空")
 @Pattern(regexp = "^.*(\.pdf|\.jpg)$", message = "生成的文件必须以.pdf或.jpg结尾")
 private String absolutePath;
 
 @NotBlank(message = "使用的模板路径不能为空")
 private String templateName;
 
 private Object dataModel;
 
 private WaterMarkInfo waterMarkInfo;
 
 private float width = 595;
 
 private float height = 842;
}

2.2、水印

@Data
public class WaterMarkInfo {
 
 private String waterMark = "";
 
 private float opacity = 0.2F;
 
 private String fontName = "STSong-Light";
 
 private String encoding = "UniGB-UCS2-H";
 
 private float fontSize = 24;
 
 private float x = 50;
 
 private float y = 40;
 
 private float rotation = 45;
}

2.3、响应

@Data
public class GeneratePdfResp {
 
 private String absolutePath;
}
3、应用代码

3.1、渲染freemarker模板获取html网页

@Service("freeMarkerService")
@Slf4j
public class FreeMarkerServiceImpl implements FreeMarkerService {
 @Autowired
 private FreeMarkerConfigurer freeMarkerConfigurer;
 
 @Override
 public String getHtml(String templatePath, Object dataModel) {
 log.info("开始将模板{}渲染为html,业务数据{}", templatePath, JSONUtil.toJsonPrettyStr(dataModel));
 Configuration cfg = freeMarkerConfigurer.getConfiguration();
 cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); // freemaker异常时仍旧抛出,统一异常处理
 cfg.setClassicCompatible(true);// 不需要对null值预处理,否则需要在模板取值时判断是否存在,不然报错
 StringWriter stringWriter = new StringWriter();
 try {
  // 设置模板所在目录,绝对路径方式,不打进jar包
//  cfg.setDirectoryForTemplateLoading(new File(templatePath).getParentFile());
//  Template temp = cfg.getTemplate(new File(templatePath).getName());
  // 相对路径设置模板所在目录,模板打进jar包,默认就是resources目录下的/templates目录。
  cfg.setClassForTemplateLoading(this.getClass(), "/templates");
  Template temp = cfg.getTemplate(templatePath);
  temp.process(dataModel, stringWriter);
 } catch (Exception e) {
  log.error(PdfErrorCode.PDF_TEMPLATE_RENDER_FAIL.getDesc(), e);
  throw new PdfBizException(PdfErrorCode.PDF_TEMPLATE_RENDER_FAIL);
 }
 return stringWriter.toString();
 }
}

3.2、将html网页转pdf,并添加水印

@Service("pdfService")
@Slf4j
public class PdfServiceImpl implements PdfService {
 public static final String FONT_PATH = "fonts/simsun.ttc,1";
 @Autowired
 private WaterMarkerService waterMarkerService;
 
 @Override
 public byte[] html2Pdf(String html, float width, float height, WaterMarkInfo waterMarkInfo) {
 log.info("=================开始将html转换为pdf=================");
 ByteArrayOutputStream out = new ByteArrayOutputStream();
 this.html2Pdf(html, width, height, out);
 byte[] bytes = out.toByteArray();
 // 设置水印
 if (waterMarkInfo != null) {
  bytes = waterMarkerService.addWaterMarker(bytes, waterMarkInfo);
 }
 return bytes;
 }
 
 @Override
 @SneakyThrows
 public void html2Pdf(String html, float width, float height, OutputStream out) {
 @Cleanup document document = new document(new RectangleReadonly(width, height)); // 默认A4纵向
 // 这里需要关闭document才能让生成的pdf字节数据刷到输出流中
 PdfWriter writer = PdfWriter.getInstance(document, out); // 关闭可能导致生成的pdf显示异常(Chrome)
 document.open();
 // 设置字体,这里统一用simsun.ttc即宋体
 XMLWorkerFontProvider asianFontProvider = new XMLWorkerFontProvider() {
  @Override
  public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, baseColor color, boolean cached) {
  Font font;
  try {
   font = new Font(baseFont.createFont(FONT_PATH, baseFont.IDENTITY_H, baseFont.EMBEDDED));
  } catch (Exception e) {
   log.error(PdfErrorCode.SET_PDF_FONT_FAIL.getDesc(), e);
   throw new PdfBizException(PdfErrorCode.SET_PDF_FONT_FAIL);
  }
  font.setStyle(style);
  font.setColor(color);
  if (size > 0) {
   font.setSize(size);
  }
  return font;
  }
 };
 // 生成pdf
 try {
  XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes("UTF-8")), null, Charset.forName("UTF-8"), asianFontProvider);
  // 如果系统已经装有simsun.ttc字体,则不需要单独设置字体也不需要itext-asian jar包
//  XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes("UTF-8")), null, Charset.forName("UTF-8"));
 } catch (RuntimeWorkerException e) {
  log.error(PdfErrorCode.HTML_CONVERT2PDF_FAIL.getDesc(), e);
  throw new PdfBizException(PdfErrorCode.HTML_CONVERT2PDF_FAIL);
 }
 }
}

添加水印实现类

@Service("waterMarkerService")
@Slf4j
public class WaterMarkerServiceImpl implements WaterMarkerService {
 
 @Override
 public byte[] addWaterMarker(byte[] source, WaterMarkInfo waterMarkInfo) {
 log.info("开始设置水印数据{}", JSONUtil.toJsonPrettyStr(waterMarkInfo));
 ByteArrayOutputStream out = new ByteArrayOutputStream();
 this.addWaterMarker(source, waterMarkInfo, out);
 return out.toByteArray();
 }
 
 @Override
 @SneakyThrows
 public void addWaterMarker(byte[] source, WaterMarkInfo waterMarkInfo, OutputStream out) {
 @Cleanup PdfReader reader = new PdfReader(source);
 // 这里需要关闭PdfStamper才能让生成的pdf字节数据刷到输出流中
 @Cleanup PdfStamper pdfStamper = new PdfStamper(reader, out);
 baseFont font = baseFont.createFont(waterMarkInfo.getFontName(), waterMarkInfo.getEncoding(), baseFont.EMBEDDED);
 PdfGState gs = new PdfGState();
 gs.setFillOpacity(waterMarkInfo.getOpacity());
 // 给每页pdf生成水印
 for (int i = 1; i <= reader.getNumberOfPages(); i++) {
  PdfContentByte waterMarker = pdfStamper.getUnderContent(i);
  waterMarker.beginText();
  // 设置水印透明度
  waterMarker.setGState(gs);
  // 设置水印字体和大小
  waterMarker.setFontAndSize(font, waterMarkInfo.getFontSize());
  // 设置水印位置、内容、旋转角度
  float X = reader.getPageSize(i).getWidth() * waterMarkInfo.getX() / 100;
  float Y = reader.getPageSize(i).getHeight() * waterMarkInfo.getY() / 100;
  waterMarker.showTextAligned(Element.ALIGN_CENTER, waterMarkInfo.getWaterMark(), X, Y, waterMarkInfo.getRotation());
  // 设置水印颜色
  waterMarker.setColorFill(baseColor.GRAY);
  waterMarker.endText();
 }
 }
}

3.3、整合实现

@Slf4j
@Service("generatePdfService")
public class GeneratePdfServiceImpl implements RestService {
 @Autowired
 private FreeMarkerService freeMarkerService;
 @Autowired
 private PdfService pdfService;
 @Override
 @SneakyThrows
 public GeneratePdfResp service(GeneratePdfReq generatePdfReq) {
 log.info("开始生成pdf文件,请求报文:{}", JSONUtil.toJsonPrettyStr(generatePdfReq));
 
 String html = freeMarkerService.getHtml(generatePdfReq.getTemplateName(), generatePdfReq.getDataModel());
 
 byte[] bytes = pdfService.html2Pdf(html, generatePdfReq.getWidth(), generatePdfReq.getHeight(), generatePdfReq.getWaterMarkInfo());
 
 File targetFile = new File(generatePdfReq.getAbsolutePath());
 // 上级目录不存在则创建
 if (!targetFile.getParentFile().exists()) {
  targetFile.getParentFile().mkdirs();
 }
 // 根据不同文件名后缀生成对应文件
 if (generatePdfReq.getAbsolutePath().endsWith("pdf")) {
  FileUtils.writeByteArrayToFile(targetFile, bytes);
 } else {
  @Cleanup PDdocument document = PDdocument.load(bytes);
  PDFRenderer renderer = new PDFRenderer(document);
  BufferedImage bufferedImage = renderer.renderImageWithDPI(0, 150);// 只打第一页,dpi越大图片越高清也越耗时
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ImageIO.write(bufferedImage, "jpg", baos);
  FileUtils.writeByteArrayToFile(targetFile, baos.toByteArray());
 }
 log.info("文件本地保存完成,文件路径:[{}]", targetFile.getAbsolutePath());
 
 GeneratePdfResp generatePdfResp = new GeneratePdfResp();
 generatePdfResp.setAbsolutePath(targetFile.getAbsolutePath());
 return generatePdfResp;
 }
}

3.4、controller

@Slf4j
@RestController
public class PdfController {
 @Autowired
 private RestService generatePdfService;
 @PostMapping(value = "/html2Pdf")
 public GeneratePdfResp html2Pdf(@RequestBody @Validated GeneratePdfReq req) {
 GeneratePdfResp resp = generatePdfService.service(req);
 return resp;
 }
}
4、应用

4.1、freemarker模板(html模板)



 
 
 
 body {
  font-family: SimSun
 }
 
 html模板



 

html模板

姓名:${name}

证件号码:${cardNo}

日期:${date}

4.2、接口调用生成pdf

5、说明

1、根据参数后缀名可以生成pdf或jpg文件,生成的pdf文件默认为A4大小,也可以通过请求参数设置大小。

2、pdf文件会根据html模板内容大小自动分页。

3、如果生成图片,多页不会生成多张图片,可以把高度设置大一些,最后会生成长图。

4、水印每页都会自动添加。

5、为了提高代码的复用性和可维护性,工程内渲染html模板、生成pdf文件、添加水印都有单独的接口实现。

代码地址

github:https://github.com/senlinmu1008/spring-boot/tree/master/html2pdf

gitee:https://gitee.com/ppbin/spring-boot/tree/master/html2pdf

以上为个人经验,希望能给大家一个参考,也希望大家多多支持考高分网。如有错误或未考虑完全的地方,望不吝赐教。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/129159.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号