Java如何向Word模板中插入Base64图片和数据信息
作者:霁月清风与谁同
这篇文章主要介绍了Java如何向Word模板中插入Base64图片和数据信息问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
需求
在服务端提前准备好Word模板文件,并在用户请求接口时服务端动态获取图片。
数据等信息插入到模板当中,然后返回包含数据信息的Word文件流。
一、准备模板文件
在需要插入图片的地方使用:{{@参数名}},文本信息使用:{{参数名}},进行占位,占位格式将会被保留,经过处理后格式不变
将准备好的模板文件放在resources目录下
二、引入Poi-tl、Apache POI依赖
poi-tl(poi template language)是Word模板引擎,基于Apache POI,提供更友好的API,使用起来更加简单
版本对应关系参考Poi-tl官网
<!-- 替换自己使用的版本 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.*</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.*</version> </dependency> <!-- Word模板引擎 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.7.*</version> </dependency>
三、创建实体类(用于保存向Word中写入的数据)
参数名必须同Word模板中的参数名称保持一致
import com.deepoove.poi.data.PictureRenderData; @Data public class DownloadDate { //图片使用PictureRenderData类型 private PictureRenderData image; private String name; private String a; private String b; private String c; private String d; private String e; private String f; private String g; private String h; private String i; }
四、实现Service接口
public interface DownloadService { void download(HttpServletResponse response, DownloadDTO downloadDTO) throws IOException; }
@Service @Slf4j public class DownloadServiceImpl implements DownloadService { @Resource //远程调用服务 private FeignService feignService; @Override public void download(HttpServletResponse response, DownloadDTO downloadDTO) throws IOException {BufferedImage、字节数组),Base64可以转字节数组后使用 //通过调用其它接口获取待写入的数据信息 WordData wordData = feignService.getData(downloadDTO); /** * 图片可以是多种格式------------------------ * 图片路径:PictureRenderData(int width, int height, String path) * File:PictureRenderData(int width, int height, File picture) * InputStream:PictureRenderData(int width, int height, String format, InputStream input) * BufferedImage:PictureRenderData(int width, int height, String format, BufferedImage image) * 字节数组:PictureRenderData(int width, int height, String format, byte[] data) * Base64可以转字节数组后使用 */ //以Base64为例,先获取图片的Base64编码(wordData.getImg是原始图片Base64数据) String base64ImageData = wordData.getImg.substring(data.indexOf(",") + 1); //获取图片类型 String format = getBase64Type(base64ImageData); // 将base64数据转为字节数组 byte[] imageBytes = Base64.getDecoder().decode(base64ImageData); // 将字节数组包装成PictureRenderData PictureRenderData pictureRenderData = new PictureRenderData(690,530,format,imageBytes); //待写入Word的数据 DownloadDate downloadDate = new DownloadDate(); //图片信息 downloadDate.setImage(pictureRenderData); //其它信息 downloadDate.setName(wordData.getName()); //... XWPFTemplate template = null; BufferedOutputStream bufferedOutputStream = null; ServletOutputStream outputStream = null; try { /** * 该方法会导致在部分环境中资源找不到的情况,不推荐使用 */ //获得resource路径+模板路径 //String path = Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("")).getPath() + "word/template.docx"; // 读取Word模板 //FileInputStream templateInputStream = new FileInputStream(path); // 模板绑定数据 //template = XWPFTemplate.compile(templateInputStream).render(imageDownloadDate); // 从资源中加载Word模板 try (InputStream templateInputStream = getClass().getClassLoader().getResourceAsStream("word/template.docx")) { if (templateInputStream != null) { // 模板绑定数据 template = XWPFTemplate.compile(templateInputStream).render(imageDownloadDate); } else { // 处理模板资源未找到的情况 log.error("Word模板资源未找到"); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } //文件名 String encodedFileName = URLEncoder.encode(System.currentTimeMillis()+"", "utf-8"); //设置响应信息 response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName + ".docx"); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setCharacterEncoding("utf-8"); outputStream = response.getOutputStream(); bufferedOutputStream = new BufferedOutputStream(outputStream); template.write(bufferedOutputStream); //清空流 bufferedOutputStream.flush(); outputStream.flush(); } catch (Exception e) { log.info(e.getMessage()); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } finally { //关闭资源 PoitlIOUtils.closeQuietlyMulti(template, bufferedOutputStream, outputStream); } } //根据base64编码获取图片格式信息 private String getBase64Type(String base64) { byte[] b = Base64.getDecoder().decode(base64); String type = ".png"; if (0x424D == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) { type = ".bmp"; } else if (0x8950 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) { type = ".png"; } else if (0xFFD8 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) { type = ".jpg"; } else if (0x49492A00 == ((b[0] & 0xff) << 24 | (b[1] & 0xff) << 16 | (b[2] & 0xff) << 8 | (b[3] & 0xff))) { type = ".tif"; } return type; } }
五、Controller层实现
@RestController @RequestMapping("/test") @Api(tags = "获取商品图片") public class GetImageController { @Resource DownloadService downloadService; @PostMapping("/download") @ApiOperation(value = "下载Word") void download(HttpServletResponse response,@RequestBody DownloadDTO downloadDTO) throws IOException { //鉴权或其它处理 //.... downloadService.download(response,downloadDTO); } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。