1. 依賴
<!--FreeMarker-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
2. 模板
-
需要放圖片的位置,直接把圖片粘貼進去調整好大小。
<pkg:part pkg:name="/word/media/image1.jpeg" pkg:contentType="image/jpeg"> <pkg:binaryData>${image}</pkg:binaryData> </pkg:part>
-
doc或docx文件另存爲xml,然後將xml文件保存到項目模板位置。
-
pkg:binaryData原本的Base64編碼</pkg:binaryData>,替換爲${變量名}
3. 具體實現
- 將需要填充的數據查詢,填充模板,本地生成,返回流給前端,瀏覽器自動下載。
@GetMapping("/exportPersonalInformation")
@ApiOperation("廉政檔案模板導出")
@LogAnnotation("廉政檔案模板導出")
public Result exportPersonalInformation(HttpServletResponse response, String oid) {
try {
Map<String,Object> map = personalInformationService.exportPersonalInformation(oid);
//創建文件名稱 +String.valueOf(System.currentTimeMillis())
String fileName = "D:\\" + File.separator + "幹部任免審批表.doc";
String templateFileName = this.getClass().getResource("/").getPath() + "templates" + File.separator;
//1、創建Configuration對象,傳參freemarker的版本號
Configuration configuration = new Configuration(Configuration.VERSION_2_3_22);
configuration.setClassicCompatible(true); //解決空值問題,必不可少
configuration.setDefaultEncoding("UTF-8");
//2、設置模板文件所在的路徑
// configuration.setClassForTemplateLoading(this.getClass(), "E:\\workspace\\Java\\company\\cg-server-project\\enterprise-vertical\\vertical-system\\src\\main\\resources\\templates\\leader.ftl");//File.separator
//3、設置模板文件所用的字符集,一般設置爲utf-8
configuration.setDefaultEncoding("utf-8");
// 設置存放路徑
configuration.setDirectoryForTemplateLoading(new File(templateFileName));//File.separator
//4、根據獲取到的名稱加載一個模板,獲取一個模板對象'
Template template = configuration.getTemplate("personalInfomation.xml", "utf-8");
//6、創建一個Writer對象,指定生成的文件名
File outFile = new File(fileName);
//若是路徑不存在則創建
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
Writer out = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outFile);
OutputStreamWriter oWriter = new OutputStreamWriter(fos, "UTF-8");
//這個地方對流的編碼不可或缺,使用main()單獨調用時,應該可以,但是如果是web請求導出時導出後word文檔就會打不開,並且包XML文件錯誤。主要是編碼格式不正確,無法解析。
//out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
out = new BufferedWriter(oWriter);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
template.process(map, out);
out.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
response.setContentType("application/force-download");// 設置強制下載不打開
response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("幹部任免審批表.doc", "UTF-8"));// 設置文件名
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(outFile);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
outFile.delete();
}
return null;
} catch (Exception e) {
log.error("廉政檔案模板導出失敗", e);
return Result.error().message("廉政檔案模板導出失敗");
}
}
-
獲得圖片的base64碼(我的有解密,正常用下面的就行。
//獲得圖片的base64碼 public static String getImageBase(String src) throws Exception { if (src == null || src == "") { return ""; } File file = new File(src); if (!file.exists()) { return ""; } InputStream in = null; byte[] data = null; try { in = new FileInputStream(file); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); }
-
遍歷表格我用的 stringBuffer 拼接的數據,僅供參考。
[@Override](https://my.oschina.net/u/1162528) public Map<String, Object> exportPersonalInformation(String oid) throws IOException { HashMap<String, Object> map = new HashMap<>(); LzdaPersonalInformation personalInformation = personalInformationMapper.selectById(oid); if (personalInformation != null) { SimpleDateFormat ymdFormat = new SimpleDateFormat("yyyy年MM月dd日"); // 姓名 map.put("personName", personalInformation.getPersonName()); // 性別 map.put("sexName", personalInformation.getSexName()); // 出生年月 if (personalInformation.getBirthday() != null) { map.put("birthday", ymdFormat.format(personalInformation.getBirthday())); } else { map.put("birthday", ""); } // 民族 map.put("nationName", personalInformation.getNationName()); // 籍貫 map.put("censusRegisterProvinceName", personalInformation.getCensusRegisterProvinceName()); // 出生地 map.put("birthplace", personalInformation.getBirthplace()); // 入黨時間 if (personalInformation.getPartyTime() != null) { map.put("partyTime", ymdFormat.format(personalInformation.getPartyTime())); } else { map.put("partyTime", ""); } if (personalInformation.getWorkTime() != null) { // 參加工作時間 map.put("workTime", ymdFormat.format(personalInformation.getWorkTime())); } else { map.put("workTime", ""); } // 健康狀況 map.put("healthConditionNameOne", personalInformation.getHealthConditionNameOne()); // 專業技術職務 map.put("professionalTechnical", personalInformation.getProfessionalTechnical()); // 熟悉專業有何專長 map.put("specialSkill", personalInformation.getSpecialSkill()); // 學歷 全日制 map.put("allEducationBackgroundFirstName", personalInformation.getAllEducationBackgroundFirstName()); map.put("allEducationBackgroundSecondName", personalInformation.getAllEducationBackgroundSecondName()); // 學歷 在職教育 map.put("inEducationBackgroundFirstName", personalInformation.getInEducationBackgroundFirstName()); map.put("inEducationBackgroundSecondName", personalInformation.getInEducationBackgroundSecondName()); // 全日制 畢業院校系及專業 map.put("allEducationGraduateInstitutions", personalInformation.getAllEducationGraduateInstitutions()); // 在職教育 畢業院校系及專業 map.put("inEducationGraduateInstitutions", personalInformation.getInEducationGraduateInstitutions()); // 現任職務 map.put("presentOccupation", personalInformation.getPresentOccupation()); // 擬任職務 map.put("designatedPosition", personalInformation.getDesignatedPosition()); // 擬免職務 map.put("toFreeOccupation", personalInformation.getToFreeOccupation()); // 簡歷 map.put("resume", personalInformation.getResume()); // 獎懲情況 map.put("rewardsPunishment", personalInformation.getRewardsPunishment()); // 年度考覈結果 map.put("annualAssessment", personalInformation.getAnnualAssessment()); // 任免理由 map.put("appointReason", personalInformation.getAppointReason()); // 家庭成員及重要社會關係 List<LzdaFamilyRelationInfo> familyRelationInfos = familyRelationInfoMapper.selectList(Wrappers.<LzdaFamilyRelationInfo>lambdaQuery().eq(LzdaFamilyRelationInfo::getBusinessId, oid).orderByAsc(LzdaFamilyRelationInfo::getSerialNumber)); if (CollectionUtils.isNotEmpty(familyRelationInfos)) { StringBuffer family = new StringBuffer(); List<LzdaFamilyRelationInfo> familyList = new ArrayList<>(); familyList.addAll(familyRelationInfos); // 不到6行添加空數據 if (familyRelationInfos.size() < 6) { for (int i = 0; i < 7 - familyRelationInfos.size(); i++) { LzdaFamilyRelationInfo lzdaFamilyRelationInfo = new LzdaFamilyRelationInfo(); // 稱謂 lzdaFamilyRelationInfo.setFamilyRelationAppellation(""); // 姓名 lzdaFamilyRelationInfo.setFamilyName(""); // 年齡 lzdaFamilyRelationInfo.setAge(""); // 政治面貌 lzdaFamilyRelationInfo.setFamilyPartyName(""); // 工作單位及職務 lzdaFamilyRelationInfo.setFamilyWorkUnit(""); familyList.add(lzdaFamilyRelationInfo); } } for (LzdaFamilyRelationInfo lzdaFamilyRelationInfo : familyList) { family.append("<w:tr>\n" + " <w:tblPrEx>\n" + " <w:tblBorders>\n" + " <w:top w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" + " <w:left w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" + " <w:bottom w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" + " <w:right w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" + " <w:insideH w:val=\"single\" w:color=\"auto\" w:sz=\"8\" w:space=\"0\"/>\n" + " <w:insideV w:val=\"single\" w:color=\"auto\" w:sz=\"8\" w:space=\"0\"/>\n" + " </w:tblBorders>\n" + " <w:tblCellMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"0\" w:type=\"dxa\"/>\n" + " </w:tblCellMar>\n" + " </w:tblPrEx>\n" + " <w:trPr>\n" + " <w:cantSplit/>\n" + " <w:trHeight w:val=\"697\" w:hRule=\"exact\"/>\n" + " </w:trPr>\n" + " <w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"742\" w:type=\"dxa\"/>\n" + " <w:vMerge w:val=\"continue\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:textDirection w:val=\"tbRlV\"/>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:spacing w:line=\"0\" w:lineRule=\"atLeast\"/>\n" + " <w:ind w:left=\"113\" w:right=\"113\"/>\n" + " <w:jc w:val=\"center\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:sz w:val=\"24\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " </w:p>\n" + " </w:tc>\n" + "<w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"1092\" w:type=\"dxa\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:tcMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"60\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"40\" w:type=\"dxa\"/>\n" + " </w:tcMar>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" + " <w:jc w:val=\"center\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋體\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " <w:r>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " <w:t>" + lzdaFamilyRelationInfo.getFamilyRelationAppellation() + "</w:t>\n" + " </w:r>\n" + " </w:p>\n" + "</w:tc>\n" + "<w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"1274\" w:type=\"dxa\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:tcMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"60\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"40\" w:type=\"dxa\"/>\n" + " </w:tcMar>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:kinsoku w:val=\"0\"/>\n" + " <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" + " <w:jc w:val=\"center\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋體\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " <w:r>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " <w:t>" + lzdaFamilyRelationInfo.getFamilyName() + "</w:t>\n" + " </w:r>\n" + " </w:p>\n" + "</w:tc>\n" + "<w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"574\" w:type=\"dxa\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:tcMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"0\" w:type=\"dxa\"/>\n" + " </w:tcMar>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" + " <w:jc w:val=\"center\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋體\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " <w:r>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " <w:t>" + lzdaFamilyRelationInfo.getAge() + "</w:t>\n" + " </w:r>\n" + " </w:p>\n" + "</w:tc>\n" + "<w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"1008\" w:type=\"dxa\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:tcMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"60\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"40\" w:type=\"dxa\"/>\n" + " </w:tcMar>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" + " <w:jc w:val=\"center\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋體\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " <w:r>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " <w:t>" + lzdaFamilyRelationInfo.getFamilyPartyName() + "</w:t>\n" + " </w:r>\n" + " </w:p>\n" + "</w:tc>\n" + "<w:tc>\n" + " <w:tcPr>\n" + " <w:tcW w:w=\"4731\" w:type=\"dxa\"/>\n" + " <w:gridSpan w:val=\"3\"/>\n" + " <w:noWrap w:val=\"0\"/>\n" + " <w:tcMar>\n" + " <w:top w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:left w:w=\"60\" w:type=\"dxa\"/>\n" + " <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" + " <w:right w:w=\"40\" w:type=\"dxa\"/>\n" + " </w:tcMar>\n" + " <w:vAlign w:val=\"center\"/>\n" + " </w:tcPr>\n" + " <w:p>\n" + " <w:pPr>\n" + " <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" + " <w:jc w:val=\"left\"/>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋體\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " </w:pPr>\n" + " <w:r>\n" + " <w:rPr>\n" + " <w:rFonts w:hint=\"eastAsia\"/>\n" + " <w:szCs w:val=\"28\"/>\n" + " <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" + " </w:rPr>\n" + " <w:t>" + lzdaFamilyRelationInfo.getFamilyWorkUnit() + "</w:t>\n" + " </w:r>\n" + " </w:p>\n" + "</w:tc>" + "</w:tr>"); } map.put("family", family); } // 呈報單位 map.put("regionName", SessionUtils.getRegionName()); map.put("date", ymdFormat.format(new Date())); // 填表人 map.put("preparer", SessionUtils.getUserName()); // 圖片 MultiMediaInfo multiMediaInfo = multiMediaInfoMapper.selectOne(Wrappers.<MultiMediaInfo>lambdaQuery().eq(MultiMediaInfo::getBusinessOid, oid)); // 解密圖片文件,並生成64編碼 if (multiMediaInfo != null) { byte[] decrypt = MultiMediaUtils.decrypt(multiMediaConfig.getProfile(), multiMediaInfo.getFilePath(), multiMediaConfig.getSecretKey()); BASE64Encoder encoder = new BASE64Encoder(); if (decrypt != null) { map.put("image", encoder.encode(decrypt)); } else { map.put("image", ""); } } } return map; }