根据word模版生成新的word直接把流输出 下载
进行改造的作为笔记 记录一下 大佬勿喷!!!
下面展示完整的代码
1.controller层
@RequestMapping(value = "/report",method = RequestMethod.POST)
@ApiOperation(value = "生成word",notes = "生成word")
@ResponseBody
public ResponseVo report(@RequestBody WordReportVo wordReportVo, HttpServletResponse response) throws IOException {
dataQdService.report(wordReportVo,response);
return new ResponseVo();
}
2.service层
提前把模版设计好放到resources
@Override
public void report(WordReportVo wordReportVo, HttpServletResponse response) throws IOException {
if (StringUtils.isEmpty(wordReportVo.getXmName()) || StringUtils.isEmpty(wordReportVo.getTzdName())
|| StringUtils.isEmpty(wordReportVo.getTzdCode()) || StringUtils.isEmpty(wordReportVo.getContent())) {
throw new BaseException(CoreErrorCode.REQUIRED_PARAM_EMPTY.getCode());
}
InputStream resourceAsStream = DataQdServiceImpl.class.getResourceAsStream("/xxx.docx");
XWPFDocument document = new XWPFDocument(resourceAsStream);
Map<String, Object> map = new HashMap<>();
map.put("xmName", wordReportVo.getXmName());
map.put("tzdName", wordReportVo.getTzdName());
map.put("tzdCode", wordReportVo.getTzdCode());
map.put("content", wordReportVo.getContent());
//这里复选框直接写死了
map.put("tzData", "0".equals(wordReportVo.getTzData()) ? "YES ☑ NO□" : "YES□ NO ☑");
// 处理文档数据
WordReportUtils.parseDocument(document, map);
DataQdServiceImpl.downloadFile(document, response);
}
3.是前端传过来的 我直接定义vo
@Data
public class WordReportVo {
/**
* 项目名称
*/
private String xmName;
/**
* 提资单名称
*/
private String tzdName;
/**
* 提资单编码
*/
private String tzdCode;
/**
* 资料内容
*/
private String content;
/**
* 是否包含假定提资数据
* 是 0 否 1
*/
private String tzData;
}
4.用到的工具类自己定义WordReportUtils有一些方法没有用到
public class WordReportUtils {
/**
* @param document 文档文件
* @param dataMap 数据Map集合
* @return java.lang.String
* @description:
* @author GPeng
* @time 2022/11/09 15:34
**/
public static String parseDocument(XWPFDocument document, Map<String, Object> dataMap) {
// 获取文档中所有对象 (段落 + 表格)
List<IBodyElement> bodys = document.getBodyElements();
// 模板文件(段落 + 表格) 总个数
int templateSize = bodys.size();
// 最终结果
String result = "";
// 遍历文档内容
// 当前操作表格对象的索引
int curT = 0;
// 当前操作段落对象的索引
int curP = 0;
for (int i = 0; i < templateSize; i++) {
// 单个 段落 或 表格
IBodyElement body = bodys.get(i);
// 表格类型
try {
if (BodyElementType.TABLE.equals(body.getElementType())) {
// 处理表格内容
table(body, curT, dataMap);
} else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {
paragraph(body, curP, dataMap);
}
} catch (Exception e) {
e.printStackTrace();
result = e.getMessage();
}
}
result = "文档内容处理完成";
return result;
}
/**
* @param body 单个表格个体
* @param index 表格所处文档索引
* @param dataMap 所有数据内容
* @return java.lang.String
* @description: 处理表格内容
* @author GPeng
* @time 2022/11/09 16:18
**/
public static String table(IBodyElement body, int index, Map<String, Object> dataMap) {
// 通过tables集合获取对应索引位置table
List<XWPFTable> tables = body.getBody().getTables();
XWPFTable table = tables.get(index);
if (table != null) {
// 获取所有行
List<XWPFTableRow> rows = table.getRows();
// 表格标题不容更改,只需替换相关内容
for (XWPFTableRow row : rows) {
// 获取单元格
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
// 判断单元格是否有需要替换数据
// 有,返回相关段落位置 没有,返回0
// 记录段落位置,防止对所需更换数据进行样式、格式操作时,对模板中设置好的段落文字进行改动
List<Integer> integers = checkText(cell);
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (int i = 0; i < paragraphs.size(); i++) {
if (integers.contains(i)) { // 存在的段落更换文本
List<XWPFRun> runs = paragraphs.get(i).getRuns();
for (XWPFRun run : runs) {
run.setFontFamily("宋体"); // 设置字体
run.setFontSize(12); // 小五号字体 如需其他字体自行查对应大小
Object ob = changeValue(run.toString(), dataMap);// 替换内容
if (ob instanceof String) {
run.setText((String) ob, 0);
} else if (ob instanceof Map) {
// run.setText("", 0); //清空段落文字内容,方便填充图片`
Map o = (Map) ob;
// 获取元素
int width = (int) o.get("width");
int height = (int) o.get("height");
int picType = getPictureType((String) o.get("type"));
byte[] bs = (byte[]) o.get("con");
try {
// 写入图片
// run.addPicture(new ByteArrayInputStream(bs), picType, "Xiong.jpg", width, height);
} catch (Exception e) {
e.printStackTrace();
return "元素替换失败:" + e.getMessage();
}
}
}
}
}
}
}
}
return "元素替换完成";
}
/**
* @param body 单个段落个体
* @param index 段落所处文档索引
* @param dataMap 所有数据内容
* @return java.lang.String
* @description: 处理段落内容
* @author GPeng
* @time 2022/11/09 16:19
**/
public static String paragraph(IBodyElement body, int index, Map<String, Object> dataMap) {
// 目前我个人需求未接触段落,后期补充
return null;
}
/**
* @param type 图片类型
* @return int
* @description: 获取各类型图片对应字典值
* @author GPeng
* @time 2022/11/10 11:17
**/
private static int getPictureType(String type) {
int res = XWPFDocument.PICTURE_TYPE_PICT;
if (type != null) {
if (type.equalsIgnoreCase("png")) {
res = XWPFDocument.PICTURE_TYPE_PNG;
} else if (type.equalsIgnoreCase("dib")) {
res = XWPFDocument.PICTURE_TYPE_DIB;
} else if (type.equalsIgnoreCase("emf")) {
res = XWPFDocument.PICTURE_TYPE_EMF;
} else if (type.equalsIgnoreCase("jpg") || type.equalsIgnoreCase("jpeg")) {
res = XWPFDocument.PICTURE_TYPE_JPEG;
} else if (type.equalsIgnoreCase("wmf")) {
res = XWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
/**
* @param value 模板需要替换的区域
* @param dataSource 传入信息集合
* @return java.lang.String 模板需要替换区域信息集合对应值
* @description: 更换模板中所需替换信息
* @author GPeng
* @time 2022/11/09 16:47
**/
private static Object changeValue(String value, Map<String, Object> dataSource) {
Set<Map.Entry<String, Object>> entries = dataSource.entrySet();
Object val = "";
for (Map.Entry<String, Object> entry : entries) {
// 匹配格式 ${key}
String key = "${" + entry.getKey() + "}";
// 判断是否存在可替换内容
if (value.indexOf(key) != -1) {
val = entry.getValue();
}
// 判断该区域是否有需替换内容 (大概率无用,checkText()已综合所需替换段落)
// if (value.indexOf("$") == -1) {
// value = "";
// }
}
return val;
}
/**
* @param cell 单元格
* @return void
* @description: 判断是否有数据需要进行更换
* @author GPeng
* @time 2022/11/09 16:31
**/
private static List<Integer> checkText(XWPFTableCell cell) {
List<Integer> integers = new ArrayList<>();
List<XWPFParagraph> paragraphs = cell.getParagraphs();
int par = 0; // 记录段落位置
for (XWPFParagraph paragraph : paragraphs) {
// 获取段落文本
String text = paragraph.getText();
// 段落如有 $ 标明 , 则需更换数值
if (text.indexOf("$") != -1) {
// 记录段落位置
integers.add(par);
}
par++;
}
return integers;
}
/**
* @param imageUrl 图片文件路径地址
* @return byte[]
* @description: 将图片转换为字节数组
* @author GPeng
* @time 2022/11/10 10:52
**/
public static byte[] getImageByteArray(String imageUrl) {
try {
File file = new File(imageUrl);
InputStream in = new FileInputStream(file);
byte[] bytes = IOUtils.toByteArray(in);
// 可以打印输出查看是否有误
// System.out.println(Arrays.toString(bytes));
return bytes;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
5.我直接输出这个文件
public static String downloadFile(XWPFDocument document, HttpServletResponse response) {
OutputStream out = null;
try {
response.setStatus(200);
//配置导出的word名称&后缀
response.addHeader("Content-Disposition", "attachment; filename=" + "xxx.docx");
// response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setContentType("application/octet-stream");
out = response.getOutputStream();
document.write(out);
} catch (Exception e) {
e.printStackTrace();
// response.setContentType("application/json;charset=utf-8");
} finally {
try {
if (document != null) {
document.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "下载成功";
}