项目中遇到简历导出成Word文档,利用poi和freemark都能实现, 但是poi对于循环处理一些数据会有难度,最终采用freemarker实现
准备工作
maven 添加依赖
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>RELEASE</version>
</dependency>
由于是springboot
工程,freemarker的jar包要引对,之前引的不对,浪费很多时间
思路
1.创建docx模板样式
2.将docx转成word xml文件
3.将xml文件的变量占位符换成freekmarker的语法
4.java程序通过freemarker技术替换变量,生成word文件
5.前端下载word文件
实现
WordUtils
/**
* @author mengqa
* @date 2018-03-29
**/
public class WordUtils {
private static Configuration configuration;
private static String TEMPLATE_PATH = System.getProperty("user.dir") + File.separator + "template" + File.separator;
static {
configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
try {
configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
} catch (IOException e) {
e.printStackTrace();
}
}
private WordUtils() {
throw new AssertionError();
}
public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response, Map map,
String title, String ftlFile) throws IOException {
Template freemarkerTemplate = configuration.getTemplate(ftlFile);
File file = null;
InputStream fin = null;
ServletOutputStream out = null;
try {
// 调用工具类的createDoc方法生成Word文档
file = createDoc(map, freemarkerTemplate);
fin = new FileInputStream(file);
response.setCharacterEncoding("utf-8");
// 设置浏览器以下载的方式处理该文件名
String fileName = title + new Date().getTime() + ".doc";
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
out = response.getOutputStream();
byte[] buffer = new byte[512]; // 缓冲区K
int count = 0;
while ((count = fin.read(buffer)) > 0) {
out.write(buffer, 0, count);
}
} finally {
if (fin != null) fin.close();
if (out != null) out.close();
if (file != null) file.delete(); // 删除临时文件
}
}
private static File createDoc(Map<?, ?> dataMap, Template template) {
String name = "sellPlan.doc";
File f = new File(name);
Template t = template;
try {
Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");
t.process(dataMap, w);
w.close();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return f;
}
/*public static 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);
}*/
public static String getImageFormNet(String urlStr) {
//new一个URL对象
URL url = null;
//打开链接
HttpURLConnection conn = null;
try {
url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5 * 1000);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
InputStream in;
byte[] data = null;
try {
in = conn.getInputStream();
data = new byte[in.available()];
in.read(data);
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BASE64Encoder encoder = new BASE64Encoder();
if (data != null) {
return encoder.encode(data);
}
return null;
}
}
WordController
/**
* Word处理器
* @author mengqa
* @date 2018-03-27
**/
@RestController
@RequestMapping("/word")
public class WordController {
@Autowired
private IResumeService resumeService;
@Autowired
private Config config;
private String getDomain() {
return config.getDomain();
}
@GetMapping("/export/{resumeId}")
@ApiOperation(value = "根据resumeId导出")
@ResponseBody
public void export(HttpServletRequest request, HttpServletResponse response, @PathVariable Long resumeId) throws IOException {
ZsWarpResume obj = resumeService.getById(resumeId);
Map<String, Object> dataMap = new HashMap<>();
// 基本信息
dataMap.put("name", obj.getName());
dataMap.put("sex", obj.getSexStr());
dataMap.put("born", DateFormatUtils.format(obj.getBorn(), DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.getPattern()));
dataMap.put("email", obj.getEmail());
dataMap.put("contact", obj.getContact());
dataMap.put("address", obj.getAddress());
String head = obj.getHead();
String imgUrl = getDomain() + head + "?imageMogr2/auto-orient";
dataMap.put("image", WordUtils.getImageFormNet(imgUrl));
// 其他信息
makeStudyList(obj, dataMap);
WordUtils.exportMillCertificateWord(request, response, dataMap,"简历" + obj.getName(),"resume.ftl");
}
private void makeStudyList(ZsWarpResume obj, Map<String, Object> dataMap) {
List<ZsWrapStudyHistory> studyList = obj.getStudyList();
List<Map<String, Object>> studyMapList = new ArrayList<>();
for (ZsWrapStudyHistory studyHistory : studyList) {
Map<String, Object> mObj = new HashMap<>();
mObj.put("name", studyHistory.getName());
mObj.put("begindate", studyHistory.getBegindate());
mObj.put("enddate", studyHistory.getEnddate());
mObj.put("education", studyHistory.getEducation());
studyMapList.add(mObj);
}
dataMap.put("studyList", studyMapList);
}
}
前端js
function exportWord(id) {
window.location.href = "/word/export/" + id;
}
坑总结
*.ftl文件,springboot jar方式运行程序, 读取resource只能通过流的形式,导致会读不到ftl文件,所以用思路是用流的形式读出resourc文件,然后复制到外部文件目录。(在springboot项目启动时复制模板文件)
/**
* 启动方法类
* @author mengqa
* @date 2018-03-29
**/
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... var1) {
// 因为jar运行方式无法读取resource模板文件,必须先创建外部资源文件
String path = System.getProperty("user.dir") + File.separator + "template" + File.separator;
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
installTemplate();
}
/**
* 向外部写resume文件
*/
private static void installTemplate() {
System.out.println("创建word模板文件");
String path = System.getProperty("user.dir") + File.separator + "template" + File.separator;
Resource resource = new ClassPathResource("generate/resume.ftl");
File targetFile = new File(path + "resume.ftl");
try {
FileUtils.copyInputStreamToFile(resource.getInputStream(), targetFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}