相信点击来看文章的都是被公司业务折磨的小伙伴,某个风和日丽的下午,你的老大:“给我搞个word批量导入,这么简单你不会不会吧?,不是吧不是吧这年头居然有人不会做word批量导入…balabala~"。
哈哈,不开玩笑了,下面进入正题。
其实对文档进行读取有很多包可以解决,像Jacob,Docx4j,OpenOffice,PageOffice,FreeMarker等等,总之方式有很多种有精力的话可以去深度学习一下,这里说一下作者使用的是POI组件,原因是百度上有很多关于poi操作word、excel的博文(虽然有很多都是雷同文章),相比较其他的方式来说有参考性。
下面列举下一些常见包的优缺点:
- Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。通过Jacob实现了在Java平台上对微软Office的COM接口进行调用。
优点: 调用微软Office的COM接口,生成的word文件格式规范。
缺点: 服务器只能是windows平台,不支持unix和linux,且服务器上必须安装微软Office。
- Apache POI包括一系列的API,它们可以操作基于MicroSoft OLE 2 Compound Document Format的各种格式文件,可以通过这些API在Java中读写Excel、Word等文件。
优点:跨平台支持windows、unix和linux。
缺点:相对与对word文件的处理来说,POI更适合excel处理,对于word实现一些简单文件的操作凑合,不能设置样式且生成的word文件格式不够规范。
- FreeMarker生成word文档的功能是由XML+FreeMarker来实现的。先把word文件另存为xml,在xml文件中插入特殊的字符串占位符,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板,编码调用FreeMarker实现文本替换并输出Doc。
优点:比Java2word功能强大,也是纯Java编程。
缺点:生成的文件本质上是xml,不是真正的word文件格式,有很多常用的word格式无法处理或表现怪异,比如:超链、换行、乱码、部分生成的文件打不开等。
- PageOffice生成word文件。PageOffice封装了微软Office繁琐的vba接口,提供了简洁易用的Java编程对象,支持生成word文件,同时实现了在线编辑word文档和读取word文档内容。
优点:跨平台支持windows、unix和linux,生成word文件格式标准,支持文本、图片、表格、字体、段落、颜色、超链、页眉等各种格式的操作,支持多word合并,无需处理并发,不耗费服务器资源,运行稳定。
缺点:必须在客户端生成文件(可以不显示界面),不支持纯服务器端生成文件。
由于作者在公司负责的项目是运行在linux上的,加之也没有太多时间就选择了poi,按照大佬们的方式去完成了业务,起初对这个一点都不了解,做的让人头秃。好在后面完成了比较简单的功能实现,能满足基本的需求。
POI读取操作步骤
1.导入poi相关jar包
第一步当然是先上maven仓库找到poi的依赖了(什么?你的项目不用maven?那你要上去下载jar包呀),直接上去搜poi。下面是作者使用的jar包依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
</dependency>
读取的话只需要上面的就够了,下面是将字符写到word上需要的。关于版本,选择使用次数比较多的稳定版本就行,不需要追求高版本,作者这里是项目之前使用了excel导出,选择3.15是为了跟之前的保持一致。
2.得到文件的输入流
依赖导入后,那么就可以正式来读取word了,我的方式是采用表单对象获取文件输入流,再根据XWPFDocument对象获取文档内容。它的构造方法里是有输入流这中方式的。那我们直接使用MultipartFile对象的getInputStream方法来获取输入流。
@PostMapping("templates/question/wordFileImport")
public BaseResult wordFileImport(@RequestParam("word") MultipartFile file, UserInfoVO userInfoVO) {
InputStream inputStream = null;
try {
inputStream = file.getInputStream();
XWPFDocument xDocument = new XWPFDocument(inputStream);
获取XWPFDocument对象我们就可以获取文档的段落和图片了,分别是getParagraphs()和getAllPictures()这两个方法。如下:
//段落对象列表
List<XWPFParagraph> paragraphs = xDocument.getParagraphs();
//图片对象列表
List<XWPFPictureData> pictures = xDocument.getAllPictures();
注意:poi中获取的图片都是没有直接获取位置的,只有一个索引值,我们需要根据索引值去确定位置。
我保存图片的方式是定义一个map去存储。如下:
Map<String, String> map = new HashMap<String, String>();
for (XWPFPictureData picture : pictures) {
//索引值
String id = picture.getParent().getRelationId(picture);
//文件名
String rawName = picture.getFileName();
//获取图片的字节数据
byte[] data = picture.getData();
//这里是将获取的图片数据上传到阿里云,可以看我的另一篇文章
OssUploadDTO dto = new OssUploadDTO(data,rawName,"-1", FileCategoryEnum.QUESTION.getValue());
OssFileInfoDTO ossFileInfoDTO = aliyunOssFileManageService.uploadOnePicFile(dto);
String cloudSrc = ossFileInfoDTO.getCloudSrc();
//将索引值作为键 url链接作为值存入map
map.put(id, cloudSrc);
}
下面直接获取所有的段落,图片在原段落中是以特殊xml标签存储的,每一个标签都有上面说到的索引值,下面要利用索引值获取图片在段落中的位置,代码如下:
String text = "";
for (XWPFParagraph paragraph : paragraphs) {
//System.out.println(paragraph.getParagraphText());
//段落分为多个XWPFRun对象
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//XWPFRun是POI对xml元素解析后生成的自己的属性,无法通过xml解析,需要先转化成CTR
boolean flag = false;
CTR ctr = run.getCTR();
//对子元素进行遍历
XmlCursor c = ctr.newCursor();
//这个就是拿到所有的子元素:
c.selectPath("./*");
while (c.toNextSelection()) {
XmlObject o = c.getObject();
//如果子元素是<w:drawing>这样的形式,使用的是CTDrawing保存图片
if (o instanceof CTDrawing) {
CTDrawing drawing = (CTDrawing) o;
CTInline[] ctInlines = drawing.getInlineArray();
for (CTInline ctInline : ctInlines) {
CTGraphicalObject graphic = ctInline.getGraphic();
XmlCursor cursor = graphic.getGraphicData().newCursor();
cursor.selectPath("./*");
while (cursor.toNextSelection()) {
XmlObject xmlObject = cursor.getObject();
if (xmlObject instanceof CTPicture) {
org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) xmlObject;
//拿到元素的属性 picture.getBlipFill().getBlip().getEmbed() 是获取索引值
String url = map.get(picture.getBlipFill().getBlip().getEmbed());
//拼接
text = text + url;
flag = true;
}
}
}
} else if (o instanceof CTObject) {//另一种则是CTObject类型 类似于上面
CTObject object = (CTObject) o;
System.out.println(object);
XmlCursor w = object.newCursor();
w.selectPath("./*");
while (w.toNextSelection()) {
XmlObject xmlObject = w.getObject();
if (xmlObject instanceof CTShape) {
CTShape shape = (CTShape) xmlObject;
String url = map.get(shape.getImagedataArray()[0].getId());
text = text + url;
flag = true;
}
}
}
}
if (!flag) {
text = text + run;
}
}
}
下面放出完整代码:
/**
* Word(图片)导入题目到题库
*
* @return
*/
@PostMapping("templates/question/wordFileImport")
public BaseResult wordFileImport(@RequestParam("word") MultipartFile file, UserInfoVO userInfoVO) {
InputStream inputStream = null;
try {
inputStream = file.getInputStream();
XWPFDocument xDocument = new XWPFDocument(inputStream);
List<XWPFParagraph> paragraphs = xDocument.getParagraphs();
List<XWPFPictureData> pictures = xDocument.getAllPictures();
Map<String, String> map = new HashMap<String, String>();
for (XWPFPictureData picture : pictures) {
String id = picture.getParent().getRelationId(picture);
String rawName = picture.getFileName();
byte[] data = picture.getData();
OssUploadDTO dto = new OssUploadDTO(data,rawName,"-1", FileCategoryEnum.QUESTION.getValue());
OssFileInfoDTO ossFileInfoDTO = aliyunOssFileManageService.uploadOnePicFile(dto);
String cloudSrc = ossFileInfoDTO.getCloudSrc();
map.put(id, cloudSrc);
}
String text = "";
for (XWPFParagraph paragraph : paragraphs) {
//System.out.println(paragraph.getParagraphText());
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//XWPFRun是POI对xml元素解析后生成的自己的属性,无法通过xml解析,需要先转化成CTR
boolean flag = false;
CTR ctr = run.getCTR();
//对子元素进行遍历
XmlCursor c = ctr.newCursor();
//这个就是拿到所有的子元素:
c.selectPath("./*");
while (c.toNextSelection()) {
XmlObject o = c.getObject();
//如果子元素是<w:drawing>这样的形式,使用CTDrawing保存图片
if (o instanceof CTDrawing) {
CTDrawing drawing = (CTDrawing) o;
CTInline[] ctInlines = drawing.getInlineArray();
for (CTInline ctInline : ctInlines) {
CTGraphicalObject graphic = ctInline.getGraphic();
XmlCursor cursor = graphic.getGraphicData().newCursor();
cursor.selectPath("./*");
while (cursor.toNextSelection()) {
XmlObject xmlObject = cursor.getObject();
if (xmlObject instanceof CTPicture) {
org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) xmlObject;
//拿到元素的属性
String url = map.get(picture.getBlipFill().getBlip().getEmbed());
text = text + url;
flag = true;
}
}
}
} else if (o instanceof CTObject) {
CTObject object = (CTObject) o;
System.out.println(object);
XmlCursor w = object.newCursor();
w.selectPath("./*");
while (w.toNextSelection()) {
XmlObject xmlObject = w.getObject();
if (xmlObject instanceof CTShape) {
CTShape shape = (CTShape) xmlObject;
String url = map.get(shape.getImagedataArray()[0].getId());
text = text + url;
flag = true;
}
}
}
}
if (!flag) {
text = text + run;
}
}
}
questionWordManageService.wordImportQuestion(text, userInfoVO.getUserId());
} catch (IOException e) {
LOG.error("WORD导入获取流异常:" + e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LOG.error("WORD导入关闭流异常:" + e.getMessage());
}
}
}
return BaseResult.getSuccessResult();
}
3.对处理好的字符串进行操作
经过上面的操作就可以将获取的内容转成字符串格式了,接下来就是对字符进行操作,根据自己需要的方式去截取需要的内容即可,这样就大功告成了。是不是很简单呢?当然这只是比较简单的,而且图片的获取也不是100%能截取到,不过只要用户不是用奇奇怪怪的图片格式就行,反正我的项目没出现过什么奇怪问题。
注意:上传的文档不要包含重复图片,貌似是poi自动对图片文件的md5进行处理了,会过滤掉重复的图片。Word本质也是一个压缩包嘛,图片都是存储在包下的某个路径的,感兴趣的可以自己试试。
最后运行速度就看你的字符处理得不得当了,听说新版本的java有很多高效的字符处理方法。
下面讲一下word导出的形式:
操作POI导出字符到word
1.获取HttpServletResponse
作者的导出是在后台对数据操作然后进行导出的,所以使用了HttpServletResponse对象将最后的文件流输出。
2.重写XWPFDocument的方法
直接拷贝下面的代码到自己项目中,建议类名跟我保持一致,方便排查。
package com.yijiupi.himalaya.word;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import java.io.IOException;
import java.io.InputStream;
/**
* @author LiJunJie
* @Descripiton:
* @create 2020-08-20 16:30
*/
public class CustomXWPFDocument extends XWPFDocument {
public CustomXWPFDocument() {
super();
}
public CustomXWPFDocument(OPCPackage opcPackage) throws IOException {
super(opcPackage);
}
public CustomXWPFDocument(InputStream in) throws IOException {
super(in);
}
public void createPicture(String blipId, int id, int width, int height) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
//String blipId = getAllPictures().get(id).getPackageRelationship().getId();
CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();
String picXml = "" +
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
" <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
" <pic:nvPicPr>" +
" <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
" <pic:cNvPicPr/>" +
" </pic:nvPicPr>" +
" <pic:blipFill>" +
" <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
" <a:stretch>" +
" <a:fillRect/>" +
" </a:stretch>" +
" </pic:blipFill>" +
" <pic:spPr>" +
" <a:xfrm>" +
" <a:off x=\"0\" y=\"0\"/>" +
" <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
" </a:xfrm>" +
" <a:prstGeom prst=\"rect\">" +
" <a:avLst/>" +
" </a:prstGeom>" +
" </pic:spPr>" +
" </pic:pic>" +
" </a:graphicData>" +
"</a:graphic>";
//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");
}
}
在需要使用的地方创建刚刚写的CustomXWPFDocument对象,由于作者是做的业务功能是导出试卷,所以对文档操作比较少,详细的格式大家可以百度下,下面放出我的格式:
private static void setDefaultStyle(XWPFRun run) {
run.setTextPosition(3);//设置行间距
run.setBold(false);//加粗
run.setColor("000000");//设置颜色--十六进制
run.setFontFamily("宋体");//字体
run.setFontSize(12);//字体大小
}
private static void setOtherStyle(XWPFRun run) {
run.setTextPosition(3);//设置行间距
run.setBold(false);//加粗
run.setColor("000000");//设置颜色--十六进制
run.setFontFamily("宋体");//字体
run.setFontSize(10);//字体大小
}
利用CustomXWPFDocument对象创建段落:
CustomXWPFDocument document = new CustomXWPFDocument();
//创建段落对象
XWPFParagraph paragraph = document.createParagraph();
//设置对齐方式
paragraph.setAlignment(ParagraphAlignment.LEFT);//对齐方式为左对齐
//段落中创建 XWPFRun 对象
XWPFRun runHead = paragraph.createRun();
//设置格式
setDefaultStyle(runHead);
//获取你要导出的内容
String content = "放入你需要导出的内容";
//内容设置
runHead.setText(questionHeader);
以上是普通字符内容创建的方式,下面说一下图片的创建方式:
//获取图片链接
String imageUrl = dto.getImageUrl();
if (StringUtils.hasText(imageUrl)) {
//图片类型数字获取 poi只支持部分图片格式
int fileType = getFileType(imageUrl.substring(imageUrl.lastIndexOf(".")));
if (fileType < 2) {
continue;
}
//获取图片的字节数组
byte[] imageByteArr = uFileService.getImageByteArr(imageUrl);
if (imageByteArr != null) {
//转化成ByteArrayInputStream
in = new ByteArrayInputStream(imageByteArr);
//读取图片 方便获取图片尺寸
BufferedImage buff = ImageIO.read(in);
if (buff != null) {
//获取图片宽度
int width = buff.getWidth();
//这里是客户对尺寸有要求 可自行处理
if (width > 556) {
width = 556;
}
int height = buff.getHeight();
//加入图片
String picId1 = document.addPictureData(imageByteArr, fileType);
document.createPicture(picId1, document.getNextPicNameNumber(fileType), width, height);
} else {
//如果读取图片读取不了就采用固定样式
String picId1 = document.addPictureData(imageByteArr, fileType);
document.createPicture(picId1, document.getNextPicNameNumber(fileType), 556, 200);
}
}
}
图片类型数字获取:
private static int getFileType(String suffix) {
int fileType = 1;
if (StringUtils.hasText(suffix)) {
switch (suffix) {
case ".emf":
fileType = 2;
break;
case ".wmf":
fileType = 3;
break;
case ".pict":
fileType = 4;
break;
case ".jpeg":
fileType = 5;
break;
case ".png":
fileType = 6;
break;
case ".dib":
fileType = 7;
break;
case ".gif":
fileType = 8;
break;
}
}
return fileType;
}
到这里就差不多了,剩下的就是按照自己的需求修改部分代码,最后我们需要将文件流返回:
BufferedOutputStream out = null;
CustomXWPFDocument document = new CustomXWPFDocument();
InputStream in = null;
//具体操作。。。。。
// 设置文件名
response.reset();
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
out = new BufferedOutputStream(response.getOutputStream());
document.write(out);
out.flush();
下面附上我自己的完整代码:
控制器:
/**
* 导出题目信息
* @param userInfoVO
* @param response
* @return
*/
@PostMapping(value = "/templates/question/exportQuestion")
public BaseResult exportByCourseSignUpId(@RequestBody QuestionLibraryQuery query, UserInfoVO userInfoVO, HttpServletResponse response) {
List<QuestionDTO> list = questionLibraryQueryService.listQuestion(query).getDataList();
AssertUtils.notEmpty(list, "暂无数据,无法导出");
AuditInfoDTO auditInfoDTO = new AuditInfoDTO();
auditInfoDTO.setContent("导出题目信息");
auditInfoDTO.setFunction("题库管理");
auditInfoDTO.setCreateTime(new Date());
auditInfoDTO.setUserId(userInfoVO.getUserId());
auditInfoDTO.setUserName(userInfoVO.getUserName());
try {
questionWordExportHandleApiService.export(list, "题目信息列表", response);
auditInfoDTO.setResult(AuditResultEnum.SUCCESS.ordinal());
} catch (Exception ex) {
auditInfoDTO.setResult(AuditResultEnum.FAIL.ordinal());
LOG.error("Word导出异常:", ex);
throw new RuntimeException("导出Word失败,服务器错误!");
} finally {
auditInfoService.insert(auditInfoDTO);
}
return BaseResult.getSuccessResult();
}
package com.yijiupi.himalaya.apiservice.boaomath.word;
import com.alibaba.dubbo.config.annotation.Reference;
import com.yijiupi.himalaya.boaomath.activity.dto.question.QuestionDTO;
import com.yijiupi.himalaya.boaomath.activity.dto.question.SelectOptionDTO;
import com.yijiupi.himalaya.boaomath.activity.enums.QuestionTypeEnum;
import com.yijiupi.himalaya.boaomath.basic.service.ufile.UFileService;
import com.yijiupi.himalaya.word.CustomXWPFDocument;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
/**
* @author LiJunJie
* @Descripiton:题目word导出处理服务
* @create 2020-08-19 15:48
*/
@Service
public class QuestionWordExportHandleApiService {
private static final Logger LOG = LoggerFactory.getLogger(QuestionWordExportHandleApiService.class);
@Reference
private UFileService uFileService;
public void export(List<QuestionDTO> list, String filename, HttpServletResponse response) {
BufferedOutputStream out = null;
CustomXWPFDocument document = new CustomXWPFDocument();
InputStream in = null;
try {
for (int i = 0; i < list.size(); i++) {
QuestionDTO dto = list.get(i);
Integer questionType = dto.getQuestionType();
XWPFParagraph paragraph = document.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);//对齐方式
XWPFRun runHead = paragraph.createRun();
setDefaultStyle(runHead);
String question = dto.getQuestion() != null ? dto.getQuestion() : "";
String questionHeader = "";
if (Objects.equals(questionType, QuestionTypeEnum.JUDGMENT_QUESTION.getValue()) || Objects.equals(questionType, QuestionTypeEnum.CHOICE_QUESTION.getValue())) {
questionHeader = (i + 1) + ".[" + QuestionTypeEnum.values()[dto.getQuestionType()].getDescription() + "] ( )";
} else {
questionHeader = (i + 1) + ".[" + QuestionTypeEnum.values()[dto.getQuestionType()].getDescription() + "] ";
}
runHead.setText(questionHeader);
XWPFParagraph paragraphBody = document.createParagraph();
XWPFRun runQuestion = paragraphBody.createRun();
setDefaultStyle(runQuestion);
String questionBody = "题目:" + question;
runQuestion.setText(questionBody);
String imageUrl = dto.getImageUrl();
if (StringUtils.hasText(imageUrl)) {
int fileType = getFileType(imageUrl.substring(imageUrl.lastIndexOf(".")));
if (fileType < 2) {
continue;
}
byte[] imageByteArr = uFileService.getImageByteArr(imageUrl);
if (imageByteArr != null) {
in = new ByteArrayInputStream(imageByteArr);
BufferedImage buff = ImageIO.read(in);
if (buff != null) {
int width = buff.getWidth();
if (width > 556) {
width = 556;
}
int height = buff.getHeight();
String picId1 = document.addPictureData(imageByteArr, fileType);
document.createPicture(picId1, document.getNextPicNameNumber(fileType), width, height);
} else {
String picId1 = document.addPictureData(imageByteArr, fileType);
document.createPicture(picId1, document.getNextPicNameNumber(fileType), 556, 200);
}
}
}
if (Objects.equals(questionType, QuestionTypeEnum.CHOICE_QUESTION.getValue())) {
List<SelectOptionDTO> selectOptionDTOList = dto.getSelectOptionDTOList();
for (int j = 0; j < selectOptionDTOList.size(); j++) {
SelectOptionDTO selectOptionDTO = selectOptionDTOList.get(j);
XWPFParagraph selectOption = document.createParagraph();
XWPFRun selectOptionRun = selectOption.createRun();
setOtherStyle(selectOptionRun);
String select = selectOptionDTO.getOptionName() + ". " + selectOptionDTO.getOptionContent() + "\t";
selectOptionRun.setText(select);
}
}
if (Objects.equals(questionType, QuestionTypeEnum.SOLVE_QUESTION.getValue())) {
for (int j = 0; j < 3; j++) {
XWPFParagraph selectOption = document.createParagraph();
XWPFRun selectOptionRun = selectOption.createRun();
setOtherStyle(selectOptionRun);
String select = "\t\t";
selectOptionRun.setText(select);
}
}
XWPFParagraph blankOne = document.createParagraph();
XWPFRun blankRun = blankOne.createRun();
setOtherStyle(blankRun);
String select = "\t\t";
blankRun.setText(select);
XWPFParagraph blankTwo = document.createParagraph();
XWPFRun blankRunTwo = blankTwo.createRun();
setOtherStyle(blankRunTwo);
blankRunTwo.setText(select);
}
// 设置文件名
response.reset();
response.setContentType("application/msword");
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
out = new BufferedOutputStream(response.getOutputStream());
document.write(out);
out.flush();
} catch (Exception ex) {
LOG.error("Word导出异常:", ex);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void setDefaultStyle(XWPFRun run) {
run.setTextPosition(3);//设置行间距
run.setBold(false);//加粗
run.setColor("000000");//设置颜色--十六进制
run.setFontFamily("宋体");//字体
run.setFontSize(12);//字体大小
}
private static void setOtherStyle(XWPFRun run) {
run.setTextPosition(3);//设置行间距
run.setBold(false);//加粗
run.setColor("000000");//设置颜色--十六进制
run.setFontFamily("宋体");//字体
run.setFontSize(10);//字体大小
}
private static int getFileType(String suffix) {
int fileType = 1;
if (StringUtils.hasText(suffix)) {
switch (suffix) {
case ".emf":
fileType = 2;
break;
case ".wmf":
fileType = 3;
break;
case ".pict":
fileType = 4;
break;
case ".jpeg":
fileType = 5;
break;
case ".png":
fileType = 6;
break;
case ".dib":
fileType = 7;
break;
case ".gif":
fileType = 8;
break;
}
}
return fileType;
}
}
最后导出效果是这样的,纯文字要好看些,好吧我承认,我弄的太丑了,哈哈~
ok,大功告成~
最后要说的是可能有地方说的不对,欢迎指正,请不要喷我,哈哈。
我是李三岁,一个朝着目标匍匐前进的小攻城狮,加油!