前面文章已经分享了如何创建导出word需要用到的xml/ftl模板了,接下来这里要给大家分享的是如何用后台制作导出word的代码工具和controller实现。
1、首先是工具类,没有工具,谈何实现呢?下面贴我这边导出word的utils,大家可以直接复制粘贴到你们项目就可以引用了。
package com.*.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import Decoder.BASE64Encoder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
/**
* 类名称:DocUtil
* 类描述:导出word工具类
*/
public class DocUtil {
public Configuration configure=null;
public DocUtil(){
configure= new Configuration(Configuration.getVersion());
configure.setDefaultEncoding("utf-8");
}
/**
* 根据Doc模板生成word文件
* @param dataMap 需要填入模板的数据
* @param downloadType 文件名称
* @param savePath 保存路径
*/
public File createDoc(Map dataMap,String modelPath,String downloadType,HttpServletRequest request){
String name = "temp" + (int) (Math.random() * 100000) + ".doc";
File f = new File(name);
//加载需要装填的模板
Template template=null;
try {
//设置模板装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。
//加载模板文件,放在/uploadFiles/file/demoDoc下
configure.setServletContextForTemplateLoading(request.getServletContext(), modelPath);
//设置对象包装器
// configure.setObjectWrapper(new DefaultObjectWrapper());
//设置异常处理器
configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
//定义Template对象,注意模板类型名字与downloadType要一致
template=configure.getTemplate(downloadType);
Writer out = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
template.process(dataMap, out);
out.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
return f;
}
/**
* 根据Doc模板生成word文件
* @param dataMap 需要填入模板的数据
* @param downloadType 文件名称
* @param savePath 保存路径
*/
public void createXls(Map dataMap,String downloadType,String webPath,String fileName,String savePath){
System.out.println(savePath.substring(savePath.length()-1));
if(savePath.substring(savePath.length()-1).equals(File.separator)) {
savePath = savePath + "uploadFiles" + File.separator + "file" + File.separator + "jdhDailySheet"+ File.separator;
}else {
savePath = savePath + File.separator + "uploadFiles" + File.separator + "file" + File.separator + "jdhDailySheet"+ File.separator;
}
File f = new File(savePath+fileName);
//加载需要装填的模板
Template template=null;
try {
if(!f.getParentFile().exists()){
f.getParentFile().mkdirs();
}
if(f.exists() && f.isFile()){
f.delete();
} else {
f.createNewFile();
}
//设置模板装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。
//加载模板文件,放在/uploadFiles/file/demoDoc下
configure.setDirectoryForTemplateLoading(new File(webPath + "uploadFiles" + File.separator + "file" + File.separator));
//设置对象包装器
// configure.setObjectWrapper(new DefaultObjectWrapper());
//设置异常处理器
configure.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
//定义Template对象,注意模板类型名字与downloadType要一致
template=configure.getTemplate(downloadType);
Writer out = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
template.process(dataMap, out);
out.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
2、接下来是处理图片的工具类,这里导出word包含导出图片到word,所以需要对图片进行处理,是怎么个原理呢,在这里和大家简单介绍下,具体在后续我会具体详细另外写一篇文章分享。
(1)图片我们可以在前台将要的图片转成base64编码,然后提交给后台接收
(2)后台接收base64编码后使用工具类将base64解码成图片然后保存到本地中
(3)在要导出word的时候读取下本地存储图片的路径然后把图片导出来就行了。
工具类如下:同第一条一样可直接复制到你们项目中使用。
package com.*.util;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import javax.imageio.ImageIO;
import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;
/**
* 类名称:ImageUtil
* 类描述:图片处理工具类
*/
public class ImageUtil {
/**
* 从path这个地址获取一张图片然后转为base64码
* @param imgName 图片的名字 如:123.png(是带后缀的)
* @param path 123.png图片存放的路径
* @return
* @throws Exception
*/
public static String getImageFromServer(String imgName,String path)throws Exception{
BASE64Encoder encoder = new BASE64Encoder();
File f = new File(path+imgName);
if(!f.exists()){
f.createNewFile();
}
BufferedImage bi = ImageIO.read(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", baos);
byte[] bytes = baos.toByteArray();
return encoder.encodeBuffer(bytes).trim();
}
/**
* 将一个base64转换成图片保存在 path文件夹下 ,命名随机
* @param base64String
* @param path 是一个文件夹路径
* @param imgName 图片名字(没有后缀)
* @throws Exception
*/
public static String savePictoServer(String base64String,String path)throws Exception{
BASE64Decoder decoder = new BASE64Decoder();
//要把+在上传时变成的空格再改为+
base64String = base64String.replaceAll(" ", "+");
//去掉“data:image/png;base64,”后面才是base64编码,去掉之后才能解析
base64String = base64String.replace("data:image/png;base64,","");
//在本地指定位置建立文件夹,path由控制台那边进行定义
String realPath = path+"/"+"echarts";
File dir=new File(realPath);
if(!dir.exists()){
dir.mkdirs();
}
String fileName=path+"\\"+"echarts"+"\\"+UUID.randomUUID().toString()+".png";
try {
byte[] buffer = decoder.decodeBuffer(base64String);
OutputStream os = new FileOutputStream(fileName);
for(int i =0;i
if(buffer[i]<0){//调整异常数据
buffer[i]+=256;
}
}
os.write(buffer);
os.close();
} catch (IOException e) {
throw new RuntimeException();
}
return fileName;
}
/**
* 读取图片在本地存储的位置
* @param imgFile
* @throws Exception
*/
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 (IOException e) {
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);
}
}
3、接下来就要介绍下在控制台怎么使用工具类实现导出word啦,详细细节看注释
static String MODELPATH = "/uploadFiles/…";
@RequestMapping(value = { "/downloadDoc" }, produces = "text/html;charset=UTF-8")
public void downloadDoc(HttpServletRequest request, HttpServletResponse response) {
//引入导出word的工具类
DocUtil docUtil = new DocUtil();
//引入处理图片的工具类,包含将base64编码解析为图片并保存本地,获取图片本地路径
ImageUtil imageUtil = new ImageUtil();
//建立map存储所要导出到word的各种数据和图像,不能使用自己项目封装的类型,例如PageData
Map dataMap = new HashMap();
/*
* 这一步,请求所需要导出到word的数据quotaList,把你们的数据处理放到这里就行了
*/
//这一步,进行图片的处理,获取前台传过来的图片base64编码,在利用工具类解析图片保存到本地,然后利用工具类获取图片本地地址
String barBase64Info = request.getParameter("barBase64Info");
String path = "D:";
String image1 = ImageUtil.savePictoServer(barBase64Info, path);
image1 = imageUtil.getImageStr(image1);
//将以上处理的数据都存入dataMap 中
//以下都是进行word文件的处理,直接复制,然后细节按需修改就行了
request.setCharacterEncoding("utf-8");
File file = null;
InputStream fin = null;
OutputStream out = null;
String filename = "文件名.doc";
//dataMap是上面处理完的数据,MODELPATH是模板文件的存储路径,"模板.xml"是相应的模板文件
file = docUtil.createDoc(dataMap, MODELPATH, "模板.xml", request);
fin = new FileInputStream(file);
response.setContentLength((int) file.length());//需要传递这个长度,不然下载文件后,打开提示内容有问题,如docx等
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
response.setHeader("Content-disposition", "attachment;filename=" + new String(filename.getBytes("utf-8"), "iso8859-1"));
out = response.getOutputStream();
byte[] buffer = new byte[1024]; // 缓冲区
int bytesToRead = -1;
// 通过循环将读入的Word文件的内容输出到浏览器中
while ((bytesToRead = fin.read(buffer)) != -1) {
out.write(buffer, 0, bytesToRead);
}
if (fin != null)
fin.close();
if (out != null)
out.close();
if (file != null)
file.delete(); // 删除临时文件
}
注意:模板的list在后台构造的时候必须是实体类或者有属性类型的,如果是自己项目封装的类型,如在我的项目中有自己封装的PageData类型的,在模板的list是识别不出list里面的数据的。
各位看官看在本仙女这么辛苦分享的份上随手点个赞呗^_^!!!