首先动手之前整理下思路:
2.1.获取数据库图片链接(这个简单跟数据一样处理)
2.2.根据链接从服务器获取图片并保存到本地
2.2.1.注意:数据库得到的图片链接,要想从服务器获取,有的字符是需要转义的,这个需要操作的
2.3.读取本地的图片,将图片信息转为base64,存入跟普通数据一起的实体类中
2.4.将这个实体类导出到指定的word模板中
上述仅仅为简单分析,实际的编写过程中肯定会遇到很多需要额外操作的内容,后面为大家分析.
那么现在就开始编写代码吧:
我们用到的技术为freemarker,其实有好多导出文档的技术,这边就不多说了.
第一步:添加pom.xml 我们所需要的依赖,这边我就把我差不多要用的拿出来了,代码太多了就不全粘了.
当然重点就是freemarker.
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.16version>
<scope>providedscope>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.3version>
dependency>
<dependency>
<groupId>commons-collectionsgroupId>
<artifactId>commons-collectionsartifactId>
<version>3.2.1version>
dependency>
<dependency>
<groupId>commons-langgroupId>
<artifactId>commons-langartifactId>
<version>2.6version>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>net.sf.ezmorphgroupId>
<artifactId>ezmorphartifactId>
<version>1.0.6version>
dependency>
<dependency>
<groupId>net.sf.json-libgroupId>
<artifactId>json-libartifactId>
<version>2.2.3version>
<classifier>jdk15classifier>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>2.8.5version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.47version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-supportartifactId>
<version>2.1.9version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.23version>
dependency>
dependencies>
首先我们需要数据,也就是从数据库里面获取到的数据,这个我就不写了,就是简单的从数据库获取数据而已,数据的格式为List< Map< String,Object>> resList 集合.
现在就相当于我们已经有数据了,它就是resList,里面有很多字段信息,包括图片的链接(我这边就先给出两个图片字段 jjyp,yjtp链接吧),http://192.168.0.101:1110/GPRS/Ⅰ临无40 (1).jpg ,http://192.168.0.101:1110/GPRS/Ⅰ临无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;ichar temp = ch[i];
if(isChinese(temp)){
try {
// 遇到中文给中文转码
String encode = URLEncoder.encode(String.valueOf(temp), "utf-8");
result = result + encode;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else{
// 判断是不是空格,是空格时转为 %20
if(temp==' '){
result = result + "%20";
}else{
// 判断字符是否为全角字符
if((int)temp>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<String,Object> JsonToMap(String jsondata,Map<String,Object> map,String starturl,String imagepath) throws UnsupportedEncodingException {
// starturl="http://101.37.20.41:9004/";
Map<String,Object> 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;
@RestController
public 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
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文档
* */
@Service
public 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 **