博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Springboot 项目导出word文档(文档内容包括数据以及服务器图片)
阅读量:2048 次
发布时间:2019-04-28

本文共 14645 字,大约阅读时间需要 48 分钟。

Springboot 项目freemarker导出word文档(文档内容包括数据以及服务器图片)

前些天有需求要完成导出word文档功能,基础数据导出word文档,网上也能搜到很多源代码,但是我这边要求是服务器上的图片(只给出服务器图片路径,从服务器得到图片),前前后后加起来就不好内容了,网上并没有找到处理这种的代码和解决方式,只好自己写了,弄完了来记录下,防止以后再用.

首先动手之前整理下思路:

第一: 分析下word文档内容: 数据 + 图片
  1. 数据 ——— 数据库获取
  2. 图片 ——— 拿到数据库连接地址,获取服务器图片.(重点)
第二:分析下实现思路
1. 数据部分很好处理,后面代码上直接可以一步完成
2. 图片部分需要注意一下
2.1.获取数据库图片链接(这个简单跟数据一样处理)       2.2.根据链接从服务器获取图片并保存到本地           2.2.1.注意:数据库得到的图片链接,要想从服务器获取,有的字符是需要转义的,这个需要操作的       2.3.读取本地的图片,将图片信息转为base64,存入跟普通数据一起的实体类中       2.4.将这个实体类导出到指定的word模板中

上述仅仅为简单分析,实际的编写过程中肯定会遇到很多需要额外操作的内容,后面为大家分析.

那么现在就开始编写代码吧:

我们用到的技术为freemarker,其实有好多导出文档的技术,这边就不多说了.

第一步:添加pom.xml 我们所需要的依赖,这边我就把我差不多要用的拿出来了,代码太多了就不全粘了.
当然重点就是freemarker.

org.springframework.boot
spring-boot-starter-jdbc
org.projectlombok
lombok
1.16.16
provided
commons-beanutils
commons-beanutils
1.9.3
commons-collections
commons-collections
3.2.1
commons-lang
commons-lang
2.6
commons-logging
commons-logging
1.1.1
net.sf.ezmorph
ezmorph
1.0.6
net.sf.json-lib
json-lib
2.2.3
jdk15
com.google.code.gson
gson
2.8.5
org.apache.httpcomponents
httpclient
4.5
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
com.alibaba
fastjson
1.2.47
com.baomidou
mybatis-plus-support
2.1.9
org.springframework.boot
spring-boot-starter-test
test
org.freemarker
freemarker
2.3.23

首先我们需要数据,也就是从数据库里面获取到的数据,这个我就不写了,就是简单的从数据库获取数据而已,数据的格式为List< Map< String,Object>> resList 集合.

现在就相当于我们已经有数据了,它就是resList,里面有很多字段信息,包括图片的链接(我这边就先给出两个图片字段 jjyp,yjtp链接吧),Ⅰ临无40 (1).jpg ,Ⅰ临无40 (2).jpg (虚拟链接).

拿到了图片的链接地址,我们就要从服务器获取图片了,并且将它保存到本地 .但是呢再次之前我们还要做的就是图片链接转码,可以直接访问图片链接,地址栏上面的链接就是转码之后的链接(浏览器自动转码),但是代码里面并不会自动转的,所以这里我们要手动转下码才行:

public class CnToEncode {
/** * @author 一只会飞的猪 * 将字符串中的中文进行编码 * @param s * @return 返回字符串中汉字编码后的字符串 */ public String charToEncode(String s) throws UnsupportedEncodingException { char[] ch = s.toCharArray(); String result = ""; for(int i=0;i
255){ String encode = URLEncoder.encode(String.valueOf(temp), "utf-8"); result = result + encode; }else { result = result + temp; } } } } return result; } /** * 判断字符是否为汉字 * @param c * @return */ private boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) { return true; } return false; } }

上面是我写好的方法,可以直接拿来用的.转码之后,你的图片链接就可以在代码里面访问服务器图片了,下面就来写访问服务器图片并返回图片输入流:

public static InputStream getUrlImages(String imagesurl) throws UnsupportedEncodingException {             InputStream inputStream = null;             HttpURLConnection httpURLConnection = null;             try {                 URL url = new URL(imagesurl);                 if (url != null) {                     httpURLConnection = (HttpURLConnection) url.openConnection();                     httpURLConnection.setConnectTimeout(9000);                     httpURLConnection.setRequestMethod("GET");                     int responseCode = httpURLConnection.getResponseCode();                     if (responseCode == 200) {                         inputStream = httpURLConnection.getInputStream();                     }                 }             } catch (Exception e) {                 e.printStackTrace();             }             return inputStream;         }

然后保存到本地:

// 将服务器图片保存到本地  输入流---->转为输出流写到文件中           public void  ImageSaveLocal(String imagepath,String imagename,String imageurl) throws UnsupportedEncodingException {               CnToEncode cntoencode = new CnToEncode();               String imagesurl=cntoencode.charToEncode(imageurl);               int len = 0;               FileOutputStream fileOutputStream = null;               InputStream inputStream = getUrlImages(imagesurl);      // 得到服务器图片的输入流               // 创建文件夹               File file = new File(imagepath);               if (file.exists()) {                   if (!file.isDirectory()) {                       file.mkdir();                   }               } else {                   file.mkdir();               }               try {                   byte[] imagesize = new byte[inputStream.available()];    // 图片长度缓存数组                   fileOutputStream = new FileOutputStream(imagepath + "/" + imagename);   // 将要写入的图片地址                   while ((len = inputStream.read(imagesize)) != -1) {                       fileOutputStream.write(imagesize, 0, len);          // 写入图片                   }               } catch (IOException e) {                   e.printStackTrace();               } finally {                   try {                       // 关闭流                       fileOutputStream.close();                       inputStream.close();                   } catch (IOException e) {                       e.printStackTrace();                   }               }           }

我这边对文件夹的做了一个分类,有需要的可以看下,是按照图片链接的类别分的,比如gps是一类.

这里写图片描述

既然图片已经保存到了本地了,那么接下来就要读取本地的图片信息了.

// 图片数据转Base64字节码 字符串  // imgFile是上面存到本地的图片路径          public String getImageStr(String imgFile){              InputStream in=null;              byte[] data=null;              try {                  in=new FileInputStream(imgFile);                  data=new byte[in.available()];                  in.read(data);                  in.close();              } catch (FileNotFoundException e) {                  e.printStackTrace();              } catch (IOException e) {                  e.printStackTrace();              }              BASE64Encoder encoder=new BASE64Encoder();              return encoder.encode(data);          }
整理下思路我们做了什么.
上面的各种方法让我们能够将服务器上面的图片存到本地,然后得到图片的base64字节码,图片的base64字节码是可以到处   word的也是能够显示的,咦~那我们是不是就可以到处了呢?nonono 现在还差一步,那就是把普通的数据和你处理之后的 图片   base64数据重新封装到一个Map集合中,这样一来,原数据集合中的图片数据就是我们所需要的base64字节码了啊,这样就能  完整的导出啦.

那现在我们在整个用来封装的方法:

// 参数介绍:jsondata 这个参数是json字符串是你的图片字段名,没有这个系统是不会知道你哪些字段是图片的.//         map: 这个当然就是我们的数据了,包括了图片字段数据哦,后面给它替换了就行了           starturl: 这个是服务器图片前缀,这你们根据需要而定           imagespath:图片临时保存地址,也就是我门本地的图片地址了  public Map
JsonToMap(String jsondata,Map
map,String starturl,String imagepath) throws UnsupportedEncodingException { // starturl="http://101.37.20.41:9004/"; Map
resmap = new HashMap<>(); // 解析json字符串 JSONObject jsonObject = JSONObject.fromObject(jsondata); resmap = jsonObject; // 将图片字段名转为map,后面好使用 // 实现源数据的图片数据被base64字节码替换 for ( String key : resmap.keySet()) { if ("".equals(map.get(key)) || map.get(key) == null) { String image = getImageStr(imagepath + "/" + "空白.jpg"); map.put(key,image); } else { String imageurl = starturl + map.get(key); String imagename = (String) map.get(key); String filetype = imagename.substring(0, imagename.indexOf("/")); // 截取字段值"/" 之前的字符串作为二级文件夹 // 创建本地的二级文件夹 File file = new File(imagepath + "/" + filetype); if (file.exists()) { if (!file.isDirectory()) { file.mkdir(); } } else { file.mkdir(); } // 拉取服务器图片存入本地 ImageSaveLocal(imagepath, imagename, imageurl); // 图片转码 String image = getImageStr(imagepath + "/" + imagename); map.put(key, image); } } return map; }

这样以来我们就得到了完美的数据结果了map.

各位观众!接下来就开始导出word文档了.开始之前我们要制作一个xml文档模板,这个至于怎么做网上有好多教程,当然坑也多.

那我们就上代码了:

package com.jshhxx.commontoolsservice.controller;import com.jshhxx.commontoolsservice.common.AbstractController;import com.jshhxx.commontoolsservice.common.FileToZip;import com.jshhxx.commontoolsservice.common.ImagesFileCommon;import com.jshhxx.commontoolsservice.common.MapKeyToLowercase;import com.jshhxx.commontoolsservice.service.ExportWord.ExportWordService;import org.apache.ibatis.annotations.Param;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import java.io.*;import java.util.*;import static com.jshhxx.commontoolsservice.common.FileToZip.fileToZip;@RestControllerpublic class ExportController extends AbstractController {
/** * @Autor 一只会飞猪 * @dis 信息导出word文档 * @param wordType 给文档分类 gps/fcb 等 * @param reslut 数据 * @param wordPath 导出路径 * @param wordname 导出名称(单条数据导出命名有效,多条数据导出zip无效) * @param wordfieldname 批量导出名称字段 * @param templatename 模板名称 * @Param jsondata 图片字段json * * */ @Autowired private ExportWordService exportWordService; private static Logger log = LoggerFactory.getLogger(ExportController.class); @Value("${ToWordPath}") private String ToWordPath; @Value("${ImagePath}") private String ImagePath; @PostMapping("/genWord") public Map
genWord(Model model, @RequestBody List
> resListone, @Param("wordType") String wordType, @Param("wordname") String wordname, @Param("wordfieldname") String wordfieldname, @Param("templatename") String templatename, @Param("jsondata") String jsondata, @Param("starturl") String starturl ) throws UnsupportedEncodingException { boolean ret = false; String msg = null; boolean flag=false; FileToZip fileToZip = new FileToZip(); Map
result=new HashMap<>(); Map
resMap = new HashMap<>(); List
> resList = new ArrayList<>(); MapKeyToLowercase mapKeyToLowercase = new MapKeyToLowercase(); ImagesFileCommon imagesFileCommon = new ImagesFileCommon(); String outputFilePath = ToWordPath; // 获取程序的当前路径 C:/wordgenerator // 创建导出word文档路径 filepath1:文件基础目录路径 C:\wordgenerator, // filepath2:文件分类路径 C:\wordgenerator\gps // filepath3:文件最终导出路径 C:\wordgenerator\gps\gps15341394803391208 String num = String.valueOf((int)(Math.random()*9000+1000)); String filepath1=outputFilePath; String filepath2=filepath1+"/"+wordType; String zzfile="/"+wordType+System.currentTimeMillis(); String filepath3=filepath2+zzfile+num; // 创建文件夹 String wordPath=createfile(filepath1,filepath2,filepath3); String resultPath = "/"+wordType+zzfile; //将map中的key全转为小写,以便模板注入.JsonToMap() 图片数据处理 for(int j=0;j
package com.jshhxx.commontoolsservice.service.ExportWord.Impl;import com.jshhxx.commontoolsservice.service.ExportWord.ExportWordService;import com.jshhxx.commontoolsservice.word.MapperTest;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.io.*;/** * @author 一只会飞的猪 * @dis   查询数据导出word文档 * */@Servicepublic class ExportWordServiceImpl  implements ExportWordService {
@Autowired private MapperTest mapperTestm; private Configuration configuration =new Configuration(); // 将数据导入到模板word中,并生成word文档 public void createWord(String templatePath, String templateName, Object dataMap, Writer out) { try { Template t = getTemplate(templatePath, templateName); t.process(dataMap, out); out.close(); } catch (IOException e) { System.out.println(e); } catch (TemplateException e) { System.out.println(e); } finally { try { out.close(); } catch (IOException e) { System.out.println(e); } } } // 模板加载 private Template getTemplate(String templatePath, String templateName) throws IOException { configuration.setClassForTemplateLoading(this.getClass(), templatePath); Template t = configuration.getTemplate(templateName); t.setEncoding("UTF-8"); return t; }}

这样一来就大功告成了,后面的代码讲解的比较少,因为网上很多,主要讲的就是这整个功能的开发思路.

这里写图片描述
这里写图片描述
功能是做出来了,但是乱码怎么解决呢?
告诉你们一个小技巧,部署的时候制定下编码就行了,java -jar Dfile.encoding=utf-8 **

你可能感兴趣的文章
剑指offer 36.数字在排序数组中出现的次数
查看>>
剑指offer 37.数组中重复的数字
查看>>
剑指offer 38.丑数
查看>>
剑指offer 39.构建乘积数组
查看>>
剑指offer 57. 删除链表中重复的结点
查看>>
剑指offer 58. 链表中环的入口结点
查看>>
剑指offer 59. 把字符串转换成整数
查看>>
剑指offer 60. 不用加减乘除做加法
查看>>
剑指offer 61. 求1+2+3+...+n
查看>>
剑指offer 62. 孩子们的游戏
查看>>
剑指offer 63.扑克牌顺子
查看>>
剑指offer 64. 翻转单词顺序列
查看>>
剑指offer 65. 左旋转字符串
查看>>
剑指offer 66. 和为S的两个数字
查看>>
leetcode 热题 Hot 100-5. 二叉树的最大深度
查看>>
leetcode 热题 Hot 100-2. 有效的括号
查看>>
leetcode 热题 Hot 100-3. 合并两个有序链表
查看>>
leetcode 热题 Hot 100-4. 对称二叉树
查看>>
Leetcode C++《热题 Hot 100-12》226.翻转二叉树
查看>>
Leetcode C++《热题 Hot 100-13》234.回文链表
查看>>