使用java更新word模板文件的內容和圖片
上一篇博客我實現了更新word模板裏面的文字內容,但是,產品經理又有了新的想法,覺得只有文字的word文檔看起來比較單調,需要穿插一些圖片,師文字看起來更豐富多彩。
代碼實現
模板的定義我們參考上一篇文章:https://blog.csdn.net/lingfeian/article/details/103309379
以下代碼就是我們實現該功能的提取出來的工具類,在代碼中有詳細的註解,再此就不做過多的描述了。
/**
* @author FeianLing
* @date 2019/11/30
* 通過模板生成新的word工具類
*/
@Component
public class WordUtils {
/**
* 根據模板生成word
*
* @param path 模板的路徑
* @param params 需要替換的參數
* @param exportFilePath 生成word文件的文件名
*/
public File getWord(String path, Map<String, Object> params, String exportFilePath) throws Exception {
InputStream is = new FileInputStream(new File(path));
MyXWPFDocument doc = new MyXWPFDocument(is);
replaceInPara(doc, params); //替換文本里面的變量
File exportFile = new File(exportFilePath);
if (!exportFile.getParentFile().exists()) {
exportFile.getParentFile().mkdirs();
}
if (!exportFile.exists()) {
exportFile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(exportFile);
doc.write(fos);
close(fos);
close(is);
return exportFile;
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 替換段落裏面的內容
* @param
* @param doc
* @param params
* @return void
*/
private void replaceInPara(MyXWPFDocument doc, Map<String, Object> params) {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph para;
while (iterator.hasNext()) {
para = iterator.next();
replaceInPara(para, params, doc);
}
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 替換變量的內容
* @param
* @param para
* @param params
* @param doc
* @return void
*/
private void replaceInPara(XWPFParagraph para, Map<String, Object> params, MyXWPFDocument doc) {
List<XWPFRun> runs;
Matcher matcher;
String runText = "";
if (matcher(para.getParagraphText()).find()) {
runs = para.getRuns();
if (runs.size() > 0) {
int j = runs.size();
for (int i = 0; i < j; i++) {
XWPFRun run = runs.get(0);
String i1 = run.toString();
runText = runText + i1;
para.removeRun(0);
}
}
Logs.info("runText: {}", runText);
matcher = matcher(runText);
if (matcher.find()) {
int count = 0;
while ((matcher = matcher(runText)).find()) {
count = matcher.groupCount();
Object val = params.get(matcher.group()) == null ? "" : params.get(matcher.group());
if (val instanceof String) {
Logs.info("{} 替換成 {}", matcher.group(), params.get(matcher.group()));
runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group())));
} else if (val instanceof Map) {
runText = matcher.replaceFirst("");
Map pic = (Map) val;
int width = Integer.parseInt(pic.get("width").toString());
int height = Integer.parseInt(pic.get("height").toString());
int picType = WordUtils.getPictureType(pic.get("type").toString());
byte[] byteArray = (byte[]) pic.get("content");
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
try {
doc.addPictureData(byteInputStream, picType);
doc.createPicture(doc.getAllPictures().size() - 1, width, height, para);
para.createRun().setText("\n", 0);
} catch (Exception e) {
Logs.error(e.getMessage());
}
break;
} else {
Logs.info("參數類型未識別" + val.getClass());
break;
}
}
// 直接調用XWPFRun的setText()方法設置文本時,在底層會重新創建一個XWPFRun,把文本附加在當前文本後面,
// 所以我們不能直接設值,需要先刪除當前run,然後再自己手動插入一個新的run。
para.insertNewRun(0).setText(runText);
}
}
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 正則匹配字符串
* @param
* @param str
* @return java.util.regex.Matcher
*/
private Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 根據圖片類型,取得對應的圖片類型代碼
* @param
* @param picType
* @return int
*/
private static int getPictureType(String picType) {
int res = MyXWPFDocument.PICTURE_TYPE_PICT;
if (picType != null) {
if (picType.equalsIgnoreCase("png")) {
res = MyXWPFDocument.PICTURE_TYPE_PNG;
} else if (picType.equalsIgnoreCase("dib")) {
res = MyXWPFDocument.PICTURE_TYPE_DIB;
} else if (picType.equalsIgnoreCase("emf")) {
res = MyXWPFDocument.PICTURE_TYPE_EMF;
} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
res = MyXWPFDocument.PICTURE_TYPE_JPEG;
} else if (picType.equalsIgnoreCase("wmf")) {
res = MyXWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 將輸入流中的數據寫入字節數組
* @param
* @param is
* @param isClose
* @return byte[]
*/
public static byte[] inputStream2ByteArray(InputStream is, boolean isClose) {
byte[] byteArray = null;
try {
int total = is.available();
byteArray = new byte[total];
is.read(byteArray);
} catch (IOException e) {
Logs.error(e.getMessage(),e);
} finally {
if (isClose) {
try {
is.close();
} catch (Exception e2) {
Logs.error(e2.getMessage(),e2);
}
}
}
return byteArray;
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 關閉輸入流
* @param
* @param is
* @return void
*/
private void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
Logs.error(e.getMessage(),e);
}
}
}
/**
* @author FeianLing
* @date 2019/12/3
* @desc 關閉輸出流
* @param
* @param os
* @return void
*/
private void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
Logs.error(e.getMessage(),e);
}
}
}
}
圖片的變量,我們使用一個map類型封裝,可以參考下面這段代碼,圖片的大小根據情況設定。
Logs.info("markImgPath > " + markImgPath);
Map<String, Object> markImg = new HashMap<String, Object>();
markImg.put("width", 336);
markImg.put("height", 140);
markImg.put("type", "jpg");
markImg.put("content", WordUtils.inputStream2ByteArray(new FileInputStream(markImgPath), true));
dataMap.put("${markImg}", markImg);
done