Java编程实现NBA赛事接口调用实例代码
513
2022-11-04
Java生成pdf文件或jpg图片的案例讲解
在一些业务场景中,需要生成pdf文件或者jpg图片,有时候还需要带上水印。我们可以事先用freemarker定义好html模板,然后把模板转换成pdf或jpg文件。
同时freemarker模板还支持变量的定义,在使用时可以填充具体的业务数据。
1、Maven导包
2、接口定义
2.1、请求
@Data
public class GeneratePdfReq {
/**
* 生成pdf文件的绝对路径
*/
@NotBlank(message = "生成pdf文件的绝对路径不能为空")
@Pattern(regexp = "^.*(\\.pdf|\\.jpg)$", message = "生成的文件必须以.pdf或.jpg结尾")
private String absolutePath;
/**
* 使用html模板的绝对路径
*/
@NotBlank(message = "使用的模板路径不能为空")
private String templateName;
/**
* 渲染模板的业务数据
*/
private Object dataModel;
/**
* 水印信息
*/
private WaterMarkInfo waterMarkInfo;
/**
* pdf文件的宽,默认A4
*/
private float width = 595;
/**
* pdf文件的高,默认A4
*/
private float height = 842;
}
2.2、水印
@Data
public class WaterMarkInfo {
/**
* 如果为null设置水印时会报错
*/
private String waterMark = "";
/**
* 水印透明度,值越小透明度越高
*/
private float opacity = 0.2F;
/**
* 水印字体,如果乱码设置为本地宋体字体:fonts/simsun.ttc,1
*/
private String fontName = "STSong-Light";
/**
* 水印编码格式,如果乱码设置为:BaseFont.IDENTITY_H
*/
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 {
/**
* 生成pdf的绝对路径
*/
private String absolutePath;
}
3、应用代码
3.1、渲染freemarker模板获取html网页
@Service("freeMarkerService")
@Slf4j
public class FreeMarkerServiceImpl implements FreeMarkerService {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
/**
* 渲染html后获取整个页面内容
*
* @param templatePath 模板路径
* @param dataModel 业务数据,一般以map形式传入
* @return
*/
@Override
public String getHtml(String templatePath, Object dataModel) {
log.info("开始将模板{}渲染为html,业务数据{}", templatePath, jsONUtil.toJsonPrettyStr(dataModel));
Configurationhttp:// 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;
/**
* html页面内容转pdf,并给每页附上水印
*
* @param html html页面内容
* @param width pdf的宽
* @param height pdf的高
* @param waterMarkInfo 水印信息
* @return
*/
@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;
}
/**
* html转pdf
*
* @param html html页面内容
* @param width pdf的宽
* @param height pdf的高
* @param out 输出流,pdf文件用此流输出,需要pdf文档关闭后流中才会有数据
*/
@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 {
/**
* 给pdf文件每页添加水印
*
* @param source pdf文件的字节数组形式
* @param waterMarkInfo 水印信息
* @return
*/
@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();
}
/**
* 给pdf文件每页添加水印
*
* @param source pdf文件的字节数组形式
* @param waterMarkInfo 水印信息
* @param out 输出流,pdf文件用此流输出,需要pdf文档关闭后流中才会有数据
*/
@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(), BaseFohttp://nt.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 http://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));
/*
1.根据freemarker模板填充业务数据获取完整的html字符串
*/
String html = freeMarkerService.getHtml(generatePdfReq.getTemplateName(), generatePdfReq.getDataModel());
/*
2.生成pdf文件(内存)
*/
byte[] bytes = pdfService.html2Pdf(html, generatePdfReq.getWidth(), generatePdfReq.getHeight(), generatePdfReq.getWaterMarkInfo());
/*
3.本地保存pdf文件
*/
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());
/*
4.组织返回
*/
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模板
姓名:${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
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~