本文使用springboot提供的freemaker技术,通过动态填充数据的方式生成图片。

可满足不同的业务场景如:如模板存储于本地,项目打成jar包,模板文件存储于远程服务器等。

准备工作

maven引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>core-renderer</artifactId>
    <version>R8</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

项目目录结构及模板存放位置

spring boot 生成jar spring boot 生成调用生成图_加载

代码实现

加载模板的三种方式

方式一:模板路径加载

/**
     * 通过指定classpath:templates读取指定模板
     * 如果是打成war包,或者指定服务器绝对路径的时候,可以使用此方法
     *
     * @param template
     * @param map
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    private String getTemplateByTemplatePath(String template, Map<String, Object> map) throws Exception {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
        String templatePath = ResourceUtils.getFile("classpath:templates").getPath();
        cfg.setDirectoryForTemplateLoading(new File(templatePath));
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setClassicCompatible(true);
        Template temp = cfg.getTemplate(template);
        StringWriter stringWriter = new StringWriter();
        temp.process(map, stringWriter);
        stringWriter.flush();
        stringWriter.close();
        String result = stringWriter.getBuffer().toString();
        return result;
    }

方式二:类加载器加载

/**
     * 通过类加载器的方式获取模板
     * springboot项目在部署的时候会打包成jar,打包成jar以后在使用freemaker时会出现以下报错:
     *           cannot be resolved to absolute file path because it does not reside in the file system: jar
     * 通过以下 setClassLoaderForTemplateLoading() 方法设置成类加载器的方式,可以解决上述无法访问模板路径的问题
     * @param template
     * @param map
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    private String getTemplateByClassLoader(String template, Map<String, Object> map) throws Exception {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
        cfg.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "templates");
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setClassicCompatible(true);
        Template temp = cfg.getTemplate(template);
        StringWriter stringWriter = new StringWriter();
        temp.process(map, stringWriter);
        stringWriter.flush();
        stringWriter.close();
        String result = stringWriter.getBuffer().toString();
        return result;
    }

方式三:远程URL的方式加载

/**
     * 通过远程URL地址获取模板
     * 此方法可以通过URL加载存储在远程服务器上的模板
     *
     * @param template
     * @param map
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    private String getTemplateByUrl(String template, Map<String, Object> map, String url) throws Exception {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
        ByteArrayTemplateLoader byteArrayTemplateLoader = new ByteArrayTemplateLoader();
        InputStream initialStream = getInputStreamByGet(url);
        byteArrayTemplateLoader.putTemplate(template, IOUtils.toByteArray(initialStream));
        cfg.setTemplateLoader(byteArrayTemplateLoader);
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setClassicCompatible(true);
        Template temp = cfg.getTemplate(template);
        StringWriter stringWriter = new StringWriter();
        temp.process(map, stringWriter);
        stringWriter.flush();
        stringWriter.close();
        String result = stringWriter.getBuffer().toString();
        return result;
    }

    /**
     * 通过get请求得到读取器响应数据的数据流
     *
     * @param url
     * @return
     * @throws Exception
     */
    public InputStream getInputStreamByGet(String url) throws Exception {
        InputStream inputStream = null;
        HttpURLConnection conn = (HttpURLConnection) new URL(url)
                .openConnection();
        conn.setReadTimeout(5000);
        conn.setConnectTimeout(5000);
        conn.setConnectTimeout(5000);
        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            inputStream = conn.getInputStream();
        }
        return inputStream;
    }

通过模板生成图片

方式一:将图片输出到字节数组

/**
     * ftl模板生成图片接口
     *
     * @param filename    生成图片名称
     * @param templateUrl ftl模板路径
     * @param template    ftl模板名称
     * @param map         模板占位符数据
     * @throws Exception
     */
    public byte[] turnImage(String templateUrl, String template, Map<String, Object> map, String filename) throws Exception {
        // 写出到流
        String html = getTemplateByUrl(template, map, templateUrl);
        byte[] bytes = html.getBytes("UTF-8");
        ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(bin);
        Java2DRenderer renderer = new Java2DRenderer(document, 1000, 500);
        BufferedImage img = renderer.getImage();
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        ImageIO.write(img, filename, outStream);
        return outStream.toByteArray();
    }

方式二:将图片输出到浏览器

/**
     * ftl模板生成图片接口,并输出到浏览器
     * @param template
     * @param map
     * @param response
     * @param url
     * @throws Exception
     */
    public void turnImage(String template, Map<String,Object> map, HttpServletResponse response,String url) throws Exception {
        //方式一:指定模板文件路径加载模板
//        String html = getTemplateByTemplatePath(template, map);
        //方式二:指定类加载器加载模板
//        String html = getTemplateByClassLoader(template, map);
        //方式三:指定远程模板文件存储路径加载模板
        String html = getTemplateByUrl(template, map,url);
        byte[] bytes=html.getBytes();
        ByteArrayInputStream bin=new ByteArrayInputStream(bytes);
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
        DocumentBuilder builder=factory.newDocumentBuilder();
        Document document=builder.parse(bin);
        Java2DRenderer renderer = new Java2DRenderer(document,1000,800);
        BufferedImage img = renderer.getImage();
        response.setContentType("image/jpeg");
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        ImageIO.write(img, "jpg", response.getOutputStream());
    }

图片合成

/**
     * 图片盖章
     *
     * @param stampedImageUrl 图片
     * @param sealImageUrl    印章图片
     * @param filename        图片名称
     * @return
     * @throws Exception
     */
    public byte[] imageSynthesis(String stampedImageUrl, String sealImageUrl, String filename) {
        try {
            InputStream stampedImageIn = getInputStreamByGet(stampedImageUrl);
            BufferedImage stampedImage = ImageIO.read(stampedImageIn);
            Graphics g = stampedImage.getGraphics();
            InputStream sealImageIn = getInputStreamByGet(sealImageUrl);
            BufferedImage sealImage = ImageIO.read(sealImageIn);
            //加盖图片章
            int x = stampedImage.getWidth() - sealImage.getWidth() - 100;
            int y = stampedImage.getHeight() - sealImage.getHeight() - 100;
            g.drawImage(sealImage, x, y, null);
            g.dispose();
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            ImageIO.write(stampedImage, filename, outStream);
            return outStream.toByteArray();
        } catch (FileNotFoundException e) {
            log.error("文件找不到:{},{}", e.getMessage(), e);
        } catch (IOException e) {
            log.error("文件转图片IO异常:{},{}", e.getMessage(), e);
        } catch (Exception e) {
            log.error("图片盖章异常:{},{}", e.getMessage(), e);
        }
        return null;
    }

效果展示

spring boot 生成jar spring boot 生成调用生成图_生成图片_02


spring boot 生成jar spring boot 生成调用生成图_生成图片_03

spring boot 生成jar spring boot 生成调用生成图_生成图片_04