1 changed files with 141 additions and 0 deletions
@ -0,0 +1,141 @@ |
|||||||
|
|
||||||
|
package apelet.tenantadmin.tenant.controller; |
||||||
|
|
||||||
|
import apelet.common.core.annotation.MyRequestBody; |
||||||
|
import apelet.common.core.exception.MyRuntimeException; |
||||||
|
import apelet.common.core.object.ObjectValue; |
||||||
|
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||||
|
import cn.hutool.core.io.IoUtil; |
||||||
|
import org.apache.poi.xwpf.usermodel.*; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.core.io.ClassPathResource; |
||||||
|
import org.springframework.web.bind.annotation.*; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.io.*; |
||||||
|
import java.net.URLEncoder; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("/api/template") |
||||||
|
public class DocxTemplateController { |
||||||
|
|
||||||
|
|
||||||
|
@Autowired |
||||||
|
private OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||||
|
|
||||||
|
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)\\}"); |
||||||
|
|
||||||
|
/** |
||||||
|
* 替换字符串中 ${key},JDK8兼容 |
||||||
|
*/ |
||||||
|
private String replaceContent(String text, Map<String, Object> dataMap) { |
||||||
|
if (text == null) return ""; |
||||||
|
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||||
|
StringBuffer sb = new StringBuffer(); |
||||||
|
while (matcher.find()) { |
||||||
|
String key = matcher.group(1).trim(); |
||||||
|
Object val = dataMap.get(key); |
||||||
|
String realVal = val == null ? "" : val.toString(); |
||||||
|
matcher.appendReplacement(sb, Matcher.quoteReplacement(realVal)); |
||||||
|
} |
||||||
|
matcher.appendTail(sb); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@GetMapping("/downloadDocx") |
||||||
|
public void downloadDocx(@RequestParam("id") String quotationId, HttpServletResponse response) { |
||||||
|
XWPFDocument document = null; |
||||||
|
InputStream templateIs = null; |
||||||
|
OutputStream out = null; |
||||||
|
try { |
||||||
|
// 1. 查数据
|
||||||
|
ObjectValue objectValue = ormGenDataSourceUtil.queryOne("quotation", quotationId); |
||||||
|
Map<String, Object> hashMap = new HashMap<>(); |
||||||
|
hashMap.put("name", objectValue.getString("name")); |
||||||
|
hashMap.put("number", objectValue.getString("number")); |
||||||
|
hashMap.put("create_time", objectValue.getString("create_time")); |
||||||
|
hashMap.put("qty", objectValue.getObjectValue("qty")); |
||||||
|
ObjectValue managerperson = objectValue.getObjectValue("managerperson"); |
||||||
|
if(managerperson != null){ |
||||||
|
managerperson = ormGenDataSourceUtil.queryOne(managerperson.getTableName(), managerperson.getString("id")); |
||||||
|
hashMap.put("managerperson",1); |
||||||
|
} |
||||||
|
// 2. 读模板
|
||||||
|
File file = new File("D:\\work\\xykj-project\\xhgl\\zz-resource\\quotation_template.docx"); |
||||||
|
templateIs = new FileInputStream(file); |
||||||
|
document = new XWPFDocument(templateIs); |
||||||
|
// 3. 替换占位符
|
||||||
|
replaceParagraph(document, hashMap); |
||||||
|
replaceTable(document, hashMap); |
||||||
|
// 4. 设置响应头 —— 关键!
|
||||||
|
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); |
||||||
|
response.setCharacterEncoding("UTF-8"); |
||||||
|
String fileName = URLEncoder.encode("报价单.docx", StandardCharsets.UTF_8.name()) |
||||||
|
.replaceAll("\\+", "%20"); |
||||||
|
// 兼容各浏览器的文件名写法
|
||||||
|
response.setHeader("Content-Disposition", |
||||||
|
"attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + fileName); |
||||||
|
response.setHeader("Pragma", "no-cache"); |
||||||
|
response.setHeader("Cache-Control", "no-cache"); |
||||||
|
response.setDateHeader("Expires", 0); |
||||||
|
// 5. 写出
|
||||||
|
out = response.getOutputStream(); |
||||||
|
document.write(out); |
||||||
|
out.flush(); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
throw new MyRuntimeException("导出失败: " + e.getMessage()); |
||||||
|
} finally { |
||||||
|
IoUtil.close(document); |
||||||
|
IoUtil.close(templateIs); |
||||||
|
IoUtil.close(out); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void replaceParagraph(XWPFDocument document, Map<String, Object> dataMap) { |
||||||
|
for (XWPFParagraph paragraph : document.getParagraphs()) { |
||||||
|
String text = paragraph.getText(); |
||||||
|
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||||
|
if (!matcher.find()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
//清空原有run
|
||||||
|
for (XWPFRun run : paragraph.getRuns()) { |
||||||
|
run.setText("", 0); |
||||||
|
} |
||||||
|
String newText = replaceContent(text, dataMap); |
||||||
|
paragraph.createRun().setText(newText); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void replaceTable(XWPFDocument document, Map<String, Object> dataMap) { |
||||||
|
for (XWPFTable table : document.getTables()) { |
||||||
|
for (XWPFTableRow row : table.getRows()) { |
||||||
|
for (XWPFTableCell cell : row.getTableCells()) { |
||||||
|
for (XWPFParagraph paragraph : cell.getParagraphs()) { |
||||||
|
String text = paragraph.getText(); |
||||||
|
Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); |
||||||
|
if (!matcher.find()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
for (XWPFRun run : paragraph.getRuns()) { |
||||||
|
run.setText("", 0); |
||||||
|
} |
||||||
|
String newText = replaceContent(text, dataMap); |
||||||
|
paragraph.createRun().setText(newText); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue