一:word处理图片功能,插入一张图片,并且设置大小,然后添加一段文字,测试图片和文字之间的换行效果:
public class ImgToWordTest {
public static void main(String[] args) throws Exception {
writeToWord();
}
/**
* Word中写入图片示例
* @throws Exception
*/
public static void writeToWord() throws Exception {
FileOutputStream fos = new FileOutputStream("D:\\downWord\\temp.docx");
String imgPath = "D:\\downWord\\test\\tianlong.png"; // 图片路径
//创建文档对象
XWPFDocument document = new XWPFDocument();
//创建段落对象
XWPFParagraph paragraph = document.createParagraph();
//创建文本对象(今天的主角:XWPFRun----一段文本对象(就是一段文字))
XWPFRun run = paragraph.createRun();//这里用的段落里的XWPFRun
//第一种,用base64字符串解码后的base64字节数组
File file = new File(imgPath);
String png = getImageStr(file, "png");
String codedata = png.substring(png.indexOf(",") + 1);
byte[] bytes = new BASE64Decoder().decodeBuffer(codedata);
String picId = document.addPictureData(bytes, CustomXWPFDocument.PICTURE_TYPE_PNG);
//第二种用流的方式
// FileInputStream fileInputStream = new FileInputStream(imgPath);
// String picId = document.addPictureData(fileInputStream, CustomXWPFDocument.PICTURE_TYPE_PNG);
WordocxUtil.addPictureToRun(run,picId,CustomXWPFDocument.PICTURE_TYPE_PNG,600,600);
//当然也可以用表格里面的XWPFRun
// InputStream inStream = WorderToNewWordUtils.class.getClassLoader().getResourceAsStream("templates/工具杀毒检测记录表.docx");
// XWPFDocument doc = new XWPFDocument(inStream);
// List xwpfTables = doc.getTables();
// XWPFTable xwpfTable = xwpfTables.get(4);//这里假设拿下标为四的表
// List rows = xwpfTable.getRows();
// XWPFTableRow xwpfTableRow = rows.get(4);//这里假设拿下标为四的行
// List tableCells = xwpfTableRow.getTableCells();
// XWPFTableCell xwpfTableCell = tableCells.get(1);//这里假设拿下标为一的列
// List paragraphs = xwpfTableCell.getParagraphs();
// XWPFParagraph xwpfParagraph = paragraphs.get(0);//这里假设拿下标为0的段落
// XWPFRun run2 = xwpfParagraph.createRun();//这个段落里创建一段文字
// String picId2 = document.addPictureData(bytes, CustomXWPFDocument.PICTURE_TYPE_PNG);
// WordocxUtil.addPictureToRun(run2,picId2,CustomXWPFDocument.PICTURE_TYPE_PNG,600,600);
//run.addBreak(BreakType.COLUMN)----这里无论是PAGE,还是这个COLUMN,都是换页的效果;
run.addCarriageReturn();//----加一个换行符
//默认:宋体(wps)/等线(office2016) 5号 两端对齐 单倍间距
run.setText("舜发于畎亩之中, 傅说举于版筑之间, 胶鬲举于鱼盐之中, 管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,曾益其所不能。\n");
run.addCarriageReturn();//----加一个换行符
run.setText("人恒过,然后能改,困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡,然后知生于忧患而死于安乐也。");
run.setBold(false);//加粗
run.setColor("BED4F1");//设置颜色--十六进制
run.setDoubleStrikethrough(false);//双删除线
run.setEmbossed(false);//浮雕字体----效果和印记(悬浮阴影)类似
//run.setFontFamily("宋体");
run.setFontSize(14);//字体大小
run.setImprinted(false);//印迹(悬浮阴影)---效果和浮雕类似
run.setItalic(false);//斜体(字体倾斜)
run.setShadow(true);//阴影---稍微有点效果(阴影不明显)
run.setStrikeThrough(false);//单删除线(新的替换Strike)
//run.setSubscript(VerticalAlign.SUBSCRIPT);//下标(吧当前这个run变成下标)---枚举
//run.setUnderline(UnderlinePatterns.DASH_LONG);//各种类型的下划线(枚举)
//ImageUtils.writeImage(run, imgPath)//这是一开始的时候,直接写了一张图片;
document.write(fos);
System.out.println("=========Word文件生成成功==========");
//fileInputStream.close();
fos.close();
}
//图片转化成base64字符串
public static String getImageStr(File file, String fileType) throws IOException {
String fileContentBase64 = null;
String base64Str = "data:" + fileType + ";base64,";
String content = null;
//将图片文件转化为字节数组字符串,并对其进行Base64编码处理
InputStream in = null;
byte[] data = null;
//读取图片字节数组
try {
in = new FileInputStream(file);
data = new byte[in.available()];
in.read(data);
in.close();
//对字节数组Base64编码
if (data == null || data.length == 0) {
return null;
}
//content = Base64.encodeBytes(data);
content = new BASE64Encoder().encode(data);
if (content == null || "".equals(content)) {
return null;
}
fileContentBase64 = base64Str + content;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
}
return fileContentBase64;
}
}
上文中用到的工具类:
/**
* 报告导出
*/
@Component
public class WordocxUtil {
public static void addPictureToRun(XWPFRun run,String blipId,int id,int width, int height){
final int EMU = 9525;
width *= EMU;
height *= EMU;
CTInline inline =run.getCTR().addNewDrawing().addNewInline();
String picXml = "" +
"" +
" " +
" " +
" " +
" + id + "\" name=\"Generated\"/>" +
" " +
" " +
" " +
" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
" + width + "\" cy=\"" + height + "\"/>" +
" " +
" " +
" " +
" " +
" " +
" " +
" " +
"";
//CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch(XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);
//graphicData.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("Picture " + id);
docPr.setDescr("Generated");
}
/*
创建FileItem
*/
public FileItem createFileItem(File file, String fieldName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return item;
}
public static void closeStream(InputStream inStream) {
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writer(XWPFDocument doc, String outSrc, Map<String,Object> map) {
/**
* 替换段落中指定的文本
*/
for(XWPFParagraph p : doc.getParagraphs()){
List<XWPFRun> runs = p.getRuns();
if(runs != null){
for(XWPFRun r : runs){
//需要替换的文本
String text = r.getText(0);
//替换指定的文本
for(String key : map.keySet()){
if(text != null && text.equals(key)){
//替换的时候要注意,setText是有两个参数的
//第一个是替换的文本,第二个是从哪里开始替换
//0是替换全部,如果不设置那么默认就是从原文字
//结尾开始追加
r.setText((String)map.get(key),0);
}
}
}
}
}
/**
* 替换表格中指定的文字
*/
for(XWPFTable tab : doc.getTables()){
for(XWPFTableRow row : tab.getRows()){
for(XWPFTableCell cell : row.getTableCells()){
//注意,getParagraphs一定不能漏掉
//因为一个表格里面可能会有多个需要替换的文字
//如果没有这个步骤那么文字会替换不了
for(XWPFParagraph p : cell.getParagraphs()){
for(XWPFRun r : p.getRuns()){
String text = r.getText(0);
for(String key : map.keySet()){
if(text!=null){
if(text.equals(key)){
r.setText((String)map.get(text),0);
}
}
}
}
}
}
}
}
}
}
二:word表格字段替换和插入功能示例:
//用户资料使用登记表----controller层
//@Scheduled(fixedDelay = 600 * 1000)
@GetMapping("/tEvaluationQueues/upRegister")
public void getUpRegister(){
log.debug("REST request to get upRegister");
tEvaluationQueueService.getUpRegister();
}
//service层
void getUpRegister();
//serviceImpl层
//用户资料使用登记表
@Override
public void getUpRegister() {
TEvaluationQueueExample example = new TEvaluationQueueExample();
TEvaluationQueueExample.Criteria criteria = example.createCriteria();
criteria.andStatusEqualTo(0);//未开始 后期还得一个各自自己的文件标记 6-1
criteria.andEvaluationTypeIdEqualTo("6-1");
List<TEvaluationQueue> que = tEvaluationQueueRepository.selectByExample(example);
if (que!=null&&que.size()>0){
for (TEvaluationQueue tEvaluationQueue : que) {
//进入循环,更改状态为1----执行中
tEvaluationQueue.setStatus(1);//只改动了status,其他的还是tEvaluationQueue的原值
tEvaluationQueueRepository.updateByPrimaryKeySelective(tEvaluationQueue);
//去对应表里查要替换的模板数据
//系统名称
String evaluationtInformationId = tEvaluationQueue.getEvaluationtInformationId();
String evaluationtInformationname = getEvaluationtInformationname(evaluationtInformationId);
//文档名称
String evaluationId = tEvaluationQueue.getEvaluationId();
List<String[]> tableList = getEvaluationtMaterialName(evaluationId);
//最后一行,是走替换
String num = String.valueOf(tableList.size()+1);
//往模板里放数据
String outputUrl = makeOutputUrl();
Map<String, String> testMap = new HashMap<String, String>();
testMap.put("evaluationtInformationname", evaluationtInformationname);
testMap.put("num", num);
InputStream inStream = WorderToNewWordUtils.class.getClassLoader().getResourceAsStream("templates/用户资料使用登记表.docx");
WorderToNewWordUtils.changWord(inStream,outputUrl,testMap,tableList);
System.out.println("success");
//走完这个循环,更改状态为2----结束
tEvaluationQueue.setStatus(2);//只改动了status,只更新status
tEvaluationQueueRepository.updateByPrimaryKeySelective(tEvaluationQueue);
//还得往文件库里插入一条记录
//调用插入文件的方法
File file = new File(outputUrl);
saveTfile(file,"6-1",evaluationId,"用户资料使用登记表.docx");
}
}
}
//serviceImpl层封装的方法
//插入文件的方法----serviceImpl这个业务类方法中封装的拿数据的方法(getEntrustingAddress(evaluationId),getProjectName(evaluationId)),就不在罗列了,没什么实际作用
//这个最后插入一条文件记录的方法,或许有点抛砖引玉的作用,暂且罗列一下
public TFile saveTfile(File file,String evaluationTypeId,String evaluationId,String fileName){
//文件信息保存
TFile tFile = new TFile();
tFile.setFileId(CommonUtils.getUUID());
tFile.setEvaluationTypeId(evaluationTypeId);
tFile.setDependId(evaluationId);
tFile.setAttachmentPath(fileUploadPath);
//文件上传名称
String name = file.getName();//
tFile.setAttachmentName(name);
//原文件名----就是模板的名字
tFile.setFileName(fileName);
//文件后缀
String prefix = file.getName().substring(file.getName().lastIndexOf("."));
tFile.setFileType(prefix);
tFile.setAttachmentSize(new Long(file.length()).floatValue());
tFile.setState(StatusEnum.NORMAL.value());
tFile.setCreateTime(ZonedDateTime.now());
tFile.setCreateUser(SecurityUtils.getCurrentUserName());
tFile.setUpdateTime(ZonedDateTime.now());
tFile.setUpdateUser(SecurityUtils.getCurrentUserName());
TFile insert = tFileService.insert(tFile);
return insert;
}
//还有一个实现类方法中封装的一个有点扯淡的臭方法
//文档名称
List<String[]> getEvaluationtMaterialName(String evaluationId){
//state=1 这里没有删除功能,可以不用考虑这个
//这个考虑到属性的原因,还需要用t_evaluationt_material表里查evaluationt_material_name,直接连表查,返回map
List<Map<String,String>> savedList = tEvaluationtDocumentsRepository.selectSaved(evaluationId);
List<String[]> stringCells = new ArrayList<>();
for (int i = 0; i < savedList.size(); i++) {
Map<String, String> map = savedList.get(i);
ArrayList<String> list = new ArrayList<>();//待会转成数组
list.add(0,String.valueOf(i+1));
if (map.size()<2){
map.put("remark"," ");
for (Map.Entry<String,String> entry : map.entrySet()){
String key = entry.getKey();
String value = entry.getValue();
if ("evaluationtMaterialName".equals(key)){
list.add(1,value);
}
if ("remark".equals(key)){
list.add(2,value);
}
}
}else {
for (Map.Entry<String,String> entry : map.entrySet()){
String key = entry.getKey();
String value = entry.getValue();
if ("remark".equals(key)){
list.add(1,value);
}
if ("evaluationtMaterialName".equals(key)){
list.add(2,value);
String s = list.get(1);
list.remove(s);
list.add(s);
}
}
}
String[] stringcell = new String[]{list.get(0),list.get(1),list.get(2)};
stringCells.add(stringcell);
}
return stringCells;
}
此处用的工具类:
/**
* 通过word模板生成新的word工具类
*/
public class WorderToNewWordUtils {
/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
// * @param inputUrl 模板存放地址
* @param outputUrl 新文档存放地址
* @param textMap 需要替换的信息集合
//* @param tableList 需要插入的表格信息集合
* @return 成功返回true,失败返回false
*/
public static boolean changWord(InputStream inStream,String outputUrl,
Map<String, String> textMap,List<String[]> tableList) {
//模板转换默认成功
boolean changeFlag = true;
try {
//获取docx解析对象
// InputStream inStream = null;
//inStream = WorderToNewWordUtils.class.getClassLoader().getResourceAsStream("templates/网络安全等级保护测评报告评审表.docx");
//POIXMLDocument.openPackage(inputUrl)
XWPFDocument document = new XWPFDocument(inStream);
//解析替换文本段落对象
WorderToNewWordUtils.changeText(document, textMap);
//解析替换表格对象
WorderToNewWordUtils.changeTable(document, textMap,tableList);
//生成新的word
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
inStream.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
changeFlag = false;
}
return changeFlag;
}
/**
* 替换段落文本
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Map<String, String> textMap){
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if(checkText(text)){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
String value = changeValue(run.toString(), textMap);
//run.setText(changeValue(run.toString(), textMap),0);
//分段显示的情况
String[] values = value.split("\n");
if(values.length > 1) {
run.setText(values[0],0);
for (int i = 1; i < values.length; i++) {
//存在分段则新建一个run
XWPFRun newrun = paragraph.insertNewRun(i);
//copy样式
newrun.getCTR().setRPr(run.getCTR().getRPr());
//换行
newrun.addBreak();
//缩进
//newrun.addTab();
newrun.setText(values[i]);
}
break;
}else {
run.setText(value,0);
}
}
}
}
}
/**
* 替换表格对象方法
* @param document docx解析对象
* @param textMap 需要替换的信息集合
//* @param tableList 需要插入的表格信息集合
*/
public static void changeTable(XWPFDocument document, Map<String, String> textMap,List<String[]> tableList){
//获取表格对象集合
List<XWPFTable> tables = document.getTables();
for (int i = 0; i < tables.size(); i++) {
//我的这里没有表头---------------//这是原来的注释:只处理 行数 大于等于2的 表格,且不循环表头
XWPFTable table = tables.get(i);
//if(table.getRows().size()>1){
if(table.getRows().size()>0){
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if(checkText(table.getText())){
List<XWPFTableRow> rows = table.getRows();
//遍历表格,并替换模板
eachTable(rows, textMap);//我的这里不需要插入
}else{
System.out.println("插入"+table.getText());
if (tableList!=null&&tableList.size()>0){
insertTable(table, tableList);
}
}
}
}
}
/**
* 遍历表格
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if(checkText(cell.getText())){
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String value = changeValue(run.toString(), textMap);
//run.setText(value,0);
//分段显示的情况
String[] values = value.split("\n");
if(values.length > 1) {
run.setText(values[0],0);
for (int i = 1; i < values.length; i++) {
//存在分段则新建一个run
XWPFRun newrun = paragraph.insertNewRun(i);
//copy样式
newrun.getCTR().setRPr(run.getCTR().getRPr());
//换行
newrun.addBreak();
//缩进
//newrun.addTab();
newrun.setText(values[i]);
}
break;
}else {
run.setText(value,0);
}
}
}
}
}
}
}
/**
* 为表格插入数据,行数不够添加新行
* @param table 需要插入数据的表格
* @param tableList 插入数据集合
*/
public static void insertTable(XWPFTable table, List<String[]> tableList){
//创建行,根据需要插入的数据添加新行,不处理表头
for(int i = 1; i <= tableList.size(); i++){
XWPFTableRow row =table.createRow();
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
for(int i = 1; i < rows.size(); i++){
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
for(int j = 0; j < cells.size(); j++){
XWPFTableCell cell = cells.get(j);
cell.setText(tableList.get(i-1)[j]);
}
}
}
/**
* 判断文本中时候包含$
* @param text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text){
boolean check = false;
if(text.indexOf("$")!= -1){//这个段落里检索到了$
check = true;//走if()去替换
}
return check;//不走if(),无需替换
}
/**
* 匹配传入信息集合与模板
* @param value 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public static String changeValue(String value, Map<String, String> textMap){
Set<Map.Entry<String, String>> textSets = textMap.entrySet();
for (Map.Entry<String, String> textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = "${"+textSet.getKey()+"}";
if(value.indexOf(key)!= -1){//模板需要替换的区域中检索到了
value = textSet.getValue();//替换成传入信息集合中的value
}
}
//模板未匹配到区域替换为空
if(checkText(value)){
value = "";
}
return value;
}
}