vue+java创建word和pdf文档(XWPFDocument)
作者:互联网
A前端代码
1.在线查看按钮和方法
在诊断报告管理中,添加在线查看的按钮,添加点击事件@click="lookUp"
<template slot="menuLeft">
<!--在线查看的按钮-->
<el-button size="small"
class="el-button--primary"
v-if="see"
@click="lookUp"
icon="el-icon-view">{{$t('button.reportView')}}</el-button>
</template>
后面的methods里,有在线查件具体的方法:this.$router.resolve是固定写法,就是打开一个新页面。
//在线查看方法
lookUp:function(){
if (!this.radio) {
this.$message.error(this.$t('tips.messageDel'));
}else{
let routeData = this.$router.resolve({
path:'/showDiagnose',//因为后面配置了路由,所以就这样写就行
query:{ id : this.radio }//这个是传递的参数,ID值
});
window.open(routeData.href, '_blank')
}
},
2.配置路由路径
像这种打开新页面,要配置路由路径
{
path: '/forgetpassword',
name: '忘记密码',
component: () =>
import( /* webpackChunkName: "page" */ '@/page/login/forgetpassword'),
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
},
{
path: '/showDiagnose',
name: '诊断报告',
component: () =>
import( /* webpackChunkName: "page" */ '@/page/showDiagnose'),
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
},
3.打开的新页面接受参数
新页面showDiagnose,新写一个新页面并接受之前页面传递过来的ID
新页面:
<template>
<div class="dashboard-editor-container">//右侧滚动条
<!--报告正文内容-->
//左上角的logo图片
<img src="../../public/img/logo.png" crossorigin="anonymous" height="114" width="147" alt="" style="text-align: left">
<!--两个下载按钮,放在了文章前面-->
<el-row style="text-align:center;margin-left: 1200px">
//注意,el-row中的内容如果居中的话,用style="text-align:center;
<el-button type="danger" size="small" @click="downLoadWord">WORD下载</el-button>
<el-button type="danger" size="small" @click="downLoadPdf">PDF下载</el-button>
</el-row>
<h1 style="text-align: center;
font-size: 38px;
color: rgba(17,19,19,0.77);">设备诊断报告书</h1>
<br/>
<h2 style="margin-left: 20px;
font-size: 30px;
color: rgba(17,19,19,0.77)">Observations of failure 问题描述:</h2>
<ul>
/*设备名称后面接的form是底下return {}里面的form表单,但是这个form表单没有数据,
因为后面页面创建的时候,就会走getDetail(id)这个方法,查出来的数据,和
*/
<li style="font-size:20px; margin-bottom: 5px;">设备SN:{{form.sn}}</li>
<li style="font-size:20px; margin-bottom: 5px;">设备名称:{{form.deviceName}}</li>
<li style="font-size:20px; margin-bottom: 5px;">问题描述:{{form.problemDescription}}</li>
</ul>
<h2 style="margin-left: 20px;
font-size: 30px;
color: rgba(17,19,19,0.77)">Estimation of reason原因分析:</h2>
<ul>
<li style="font-size:20px; margin-bottom: 5px;">{{form.estimationReason}}</li>
</ul>
<h2 style="margin-left: 20px;
font-size: 30px;
color: rgba(17,19,19,0.77)">Spare parts备件:</h2>
<ul>
<li style="font-size:20px; margin-bottom: 5px;">{{form.spareParts}}</li>
</ul>
<h2 style="margin-left: 20px;
font-size: 30px;
color: rgba(17,19,19,0.77)">Final result结果/反馈:</h2>
<ul>
<li style="font-size:20px; margin-bottom: 5px;">{{form.finalResult}}</li>
</ul>
<h2 style="margin-left: 20px;
font-size: 30px;
color: rgba(17,19,19,0.77)">Recommendation建议:</h2>
<ul>
<li style="font-size:20px; margin-bottom: 5px;">{{form.recommendation}}</li>
</ul>
</div>
</template>
<script>
import {getDetail, downloadWord, downloadPdf} from '../api/monitor/diagnose'
export default {
data() {
return {
htmlTitle: "设备诊断报告书",
form: {
}
}
},
//页面创建的时候,会走这个里面,生命周期方法,也就是说这个页面刚创建的时候,ID就传过来了,
//同时也会走getDetail(id)这个方法
created() {
//用this.$route点后面的参数,接受上一个页面传递过来的id
let id = this.$route.query.id
/*把ID传到getDetail方法中,得到结果res,把查询到的内容附到
form: {
}
这个表单中,相当于这个表单中转一下。
*/
getDetail(id).then(res => {
this.form = res.data.data;
})
},
methods: {
//下载word的方法
downLoadWord() {
//先是把id引过来
let id = this.$route.query.id
downloadWord(id).then(res => {
//先判断res.data有没有这个数据,然后判断code等不等于200,因为成功是200,失败是400
if (res.data && res.data.code === 200) {
window.location.href = "/api" + res.data.data;
/*windows.location.href="/url" 当前页面打开URL页面
详细记录是:https://blog.csdn.net/sdta25196/article/details/78799338
经过测试:res.data.data: /upload/1596791395547.docx,也就是说后端传回来的就是:
/upload/1596791395547.docx这个路径
而打开的路径就是:/api/upload/1596791395547.docx
在vue.config.jswe文件中设置:
devServer: {
port: 1888,
proxy: {
'/api': {
//本地服务接口地址
target: 'http://localhost:8088',
//远程演示服务地址,可用于直接启动项目
//target: 'https://saber.bladex.vip/api',
ws: true,
pathRewrite: {
'^/api': '/'
}
}
}
}
*/
后台的路径,前台转换成/api
}
//
})
},
// 下载pdf,和之前下载word也是一样的
downLoadPdf() {
let id = this.$route.query.id
downloadPdf(id).then(res => {
console.log(res)
if (res.data && res.data.code === 200) {
window.location.href = "/api" + res.data.data;
}
//
})
}
}
}
</script>
<!--右侧滚动条-->
//这是网上查到的右侧滚动条的代码
<style rel="stylesheet/scss" lang="scss" scoped>
.dashboard-editor-container {//这个是滚动条的类的设置
padding: 15px;
background-color: #ffffff;
overflow-y: auto;
height: 672px;
.chart-wrapper {
background: #ffffff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
</style>
4.在src/api中
//get方法,参数只有一个,即id
export const downloadWord = (id) => {
return request({
url: '/api/diagnose/downloadWord',
method: 'get',
params: {id}
})
};
export const downloadPdf = (id) => {
return request({
url: '/api/diagnose/downloadPdf',
method: 'get',
params: {id}
})
};
5.vue.config.js文件
devServer: {
port: 1888,
proxy: {
'/api': {
//本地服务接口地址
target: 'http://localhost:8088',
//远程演示服务地址,可用于直接启动项目
//target: 'https://saber.bladex.vip/api',
ws: true,
pathRewrite: {//反向代理
'^/api': '/'
}
}
}
}
B后端代码
1.在控制器层:DiagnoseController
返回的类型是String类型
而返回的是路径
/**
* 下载报告word版本
*/
@GetMapping("/downloadWord")
public R<String> downloadWord(@RequestParam Long id) {
String path = diagnoseService.downloadWord(id);
//返回的是地址
return R.data(path);
}
/**
* 下载报告PDF版本
*/
@GetMapping("/downloadPdf")
public R<String> downloadPdf(@RequestParam Long id) {
String path = diagnoseService.downloadPdf(id);
return R.data(path);
}
点击方法,进入业务层接口
2.在业务层接口:IDiagnoseService
/**
* 下载word版诊断报告
* @param id 诊断报告id
* @return 诊断报告word文件路径
*/
String downloadWord(Long id);
/**
* 下载Pdf版诊断报告
* @param id 诊断报告id
* @return 诊断报告Pdf文件路径
*/
String downloadPdf(Long id);
点击抽象方法,进入业务层实现类
3.在业务层实现类DiagnoseServiceImpl
package com.tcb.monitor.service.impl;
/**
* 诊断报告业务层实现类
*
* @author Charles
* @since 2020/07/21
*/
@Service
@Slf4j
public class DiagnoseServiceImpl extends BaseServiceImpl<DiagnoseMapper, Diagnose> implements IDiagnoseService {
@Resource
IDepartmentService departmentService;
@Resource
DiagnoseMapper diagnoseMapper;
@Value("${upload.path}")
private String uploadPath;
//下载word 的方法
@Override
public String downloadWord(Long id) {
//用之前的查询详情的方法,根据id返回的是VO
DiagnoseDetailVo vo = getDiagDetail(id);
//generateWordFile为自己写的方法,在后面
//根据VO,返回的是文件名
String fileName = generateWordFile(vo);
// 3. 将文件路径返回给服务器
return "/upload/" + fileName;
}
@Override
public String downloadPdf(Long id) {
//根据id返回VO类的对象
DiagnoseDetailVo vo = getDiagDetail(id);
//这里是因为抛出异常
String fileName = "";
try {
fileName = generatePdfFile(vo);
} catch (Exception e) {
e.printStackTrace();
}
// 3. 将文件路径返回给服务器
return "/upload/" + fileName;
}
private String generatePdfFile(DiagnoseDetailVo vo) throws DocumentException, IOException, FontFormatException {
// 1. 生成pdf文档
/*https://www.runoob.com/java/java-bytearrayoutputstream.html
字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。创建字节数组输出流对象有以下几种方式。下面的构造方法创建一个32字节(默认大小)的缓冲区。
OutputStream bOut = new ByteArrayOutputStream();*/
//字节数组输出流,输出流名称:stream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//此处根据excel大小设置pdf纸张大小
Document document = new Document(PageSize.A4);
//将PDF文档对象写入到流
PdfWriter.getInstance(document, stream);
//设置页边距
document.setMargins(30, 30, 15, 15);
/*
Write对象创建之后
首先打开documet(这个过程就像我们创建一个空的pdf文件,然后打开来创作一样)
然后开始写入数据
设置文档属性
最后关闭
*/
document.open();
//设置基本字体
URL resource = DiagnoseServiceImpl.class.getClassLoader().getResource("font/simsun.ttc");
//后缀是.ttc的都是字体文件
//simsun.ttc:这个字体是宋体,ttc后缀的文bai件一般是一套字体,多数就是du包含了一种字体的正常zhi体,黑体,和斜体。
BaseFont baseFont = BaseFont.createFont(Objects.requireNonNull(resource).toString() + ",0", BaseFont.IDENTITY_H,BaseFont.EMBEDDED);
PdfPTable table = new PdfPTable(1);
table.setWidthPercentage(20f);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
InputStream logo = DiagnoseServiceImpl.class.getClassLoader().getResourceAsStream("logo.png");
BufferedImage image = null;
if (logo != null) {
image = ImageIO.read(logo);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image, "png", out);
byte[] data = out.toByteArray();
PdfPCell cell = new PdfPCell(Image.getInstance(data), true);
cell.setBorder(0);
table.addCell(cell);
document.add(table);
}
// 标题
Font pdFont = new Font(baseFont, 20, Font.BOLD, BaseColor.BLACK);
Paragraph p = new Paragraph("设备诊断报告书", pdFont);
p.setAlignment(Element.ALIGN_CENTER);
document.add(p);
// 问题描述
pdFont = new Font(baseFont, 18, Font.BOLD, BaseColor.BLACK);
p = new Paragraph("Observations of failure 问题描述:", pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph("设备SN:" + vo.getSn(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph("设备名称:" + vo.getDeviceName(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph("问题描述:" + vo.getProblemDescription(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
// 原因分析
pdFont = new Font(baseFont, 18, Font.BOLD, BaseColor.BLACK);
p = new Paragraph("Estimation of reason原因分析:", pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph(vo.getEstimationReason(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
// 备件
pdFont = new Font(baseFont, 18, Font.BOLD, BaseColor.BLACK);
p = new Paragraph("Spare parts备件:", pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph(vo.getSpareParts(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
// 结果/反馈
pdFont = new Font(baseFont, 18, Font.BOLD, BaseColor.BLACK);
p = new Paragraph("Final result结果/反馈:", pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph(vo.getFinalResult(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
// 建议
pdFont = new Font(baseFont, 18, Font.BOLD, BaseColor.BLACK);
p = new Paragraph("Recommendation建议:", pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
pdFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
p = new Paragraph(vo.getRecommendation(), pdFont);
p.setAlignment(Element.ALIGN_LEFT);
document.add(p);
document.add(p);
document.newPage();
document.close();
// 2. 将文档输出到本地
String fileName = System.currentTimeMillis() + ".pdf";
String filePath = uploadPath + fileName;
writeToFile(filePath, stream);
return fileName;
}
private static void writeToFile(String pdfPath, ByteArrayOutputStream stream) throws IOException {
byte[] pdfByte = stream.toByteArray();
stream.flush();
stream.reset();
stream.close();
FileOutputStream outputStream = new FileOutputStream(pdfPath);
outputStream.write(pdfByte);
outputStream.flush();
outputStream.close();
}
private String generateWordFile(DiagnoseDetailVo vo) {
// 1. 根据模板生成word文档
// logo
//创建word文件,document是“文件”的英文。创建Pdf文件的是,括号内就要设置PageSize.A4
//而这里如果括号内加入PageSize.A4,则报错
XWPFDocument document = new XWPFDocument();
//新建一个段落p
XWPFParagraph p = document.createParagraph();
// 设置段落的对齐方式,ParagraphAlignment,中文意思是段落对其,是枚举类,在后续有记录
//此处为左侧对齐
p.setAlignment(ParagraphAlignment.LEFT);
//创建段落文本
XWPFRun run = p.createRun();
//字节输入流InputStream
/*
class是指当前类的class对象.
getClassLoader()是获取当前的类加载器,什么是类加载器?简单点说,就是用来加载java类的,类加载器负责把class文件加载进内存中,并创建一个java.lang.Class类的一个实例,也就是class对象,并且每个类的类加载器都不相同。
getResourceAsStream(path)是用来获取资源的,而类加载器默认是从classPath下获取资源的,因为这下面有class文件,所以这段代码总的意思是通过类加载器在classPath目录下获取资源.并且是以流的形式。
*/
//logo
try (InputStream logo = DiagnoseServiceImpl.class.getClassLoader().getResourceAsStream("logo.png")) {
//Class.getClassLoader.getResourceAsStream(String path) :默认则是从ClassPath根下获取,path不能以’/'开头,因为是相对路径,是相对的,如果前面加/则是绝对路径,最终是由ClassLoader获取资源。
//说明classpath和resources是一个位置
//源代码:public XWPFPicture addPicture(InputStream pictureData, int pictureType, String filename, int width, int height),参数有 输入流、图片类型、文件名、宽度、高度
run.addPicture(logo, org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG, "a.png", Units.toEMU(147), Units.toEMU(114));
} catch (InvalidFormatException | IOException e) {
e.printStackTrace();
}
// 标题
// 新建一个段落
p = document.createParagraph();
//这个是居中对齐
p.setAlignment(ParagraphAlignment.CENTER);
generateRun(p, "设备诊断报告书", true, 20);
/*generateRun是自己生产的一个方法,把重复的几个方法放在了一个方法里,如下:
private XWPFRun generateRun(XWPFParagraph p, String text, boolean bold, int fontSize) {
这个方法中,
XWPFRun run = p.createRun();//为创建段落文本
run.setText(text);//为输入 word中的文本
run.setBold(bold);//设置为粗体,bold是boolean属性
run.setFontSize(fontSize);//应该是设置字号,即设置字体大小,font即字体的意思
run.setFontFamily("微软雅黑");//设置字体样式
return run;
}
*/
// 问题描述
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "Observations of failure 问题描述:", true, 18);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "设备SN:" + vo.getSn(), false, 14);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "设备名称:" + vo.getDeviceName(), false, 14);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "问题描述:" + vo.getProblemDescription(), false, 14);
// 原因分析
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "Estimation of reason原因分析:", true, 18);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, vo.getEstimationReason(), false, 14);
// 备件
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "Spare parts备件:", true, 18);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, vo.getSpareParts(), false, 14);
// 结果/反馈
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "Final result结果/反馈:", true, 18);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, vo.getFinalResult(), false, 14);
// 建议
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, "Recommendation建议:", true, 18);
p = document.createParagraph();
p.setAlignment(ParagraphAlignment.LEFT);
generateRun(p, vo.getRecommendation(), false, 14);
// 2. 将word输出到本地目录
String fileName = System.currentTimeMillis() + ".docx";
//文件名 = 当前系统时间+docx后缀
//文件地址 =uploadPath +filename
/*uploadPath就是前面的:
@Value("${upload.path}")
private String uploadPath;
应该是对应的配置文件的 path: E:/upload/。
所以文件地址 = E:/upload/+时间+docx后缀*/
String filePath = uploadPath + fileName;//这个是电脑上地址
//根据电脑上的文件地址创建文件
File file = new File(filePath);
try {
//创建文件
document.write(new FileOutputStream(file));
} catch (IOException e) {
e.printStackTrace();
}
//返回文件名
return fileName;
}
//自己生成的一个方法,因为只是这个类用,所以权限为private
private XWPFRun generateRun(XWPFParagraph p, String text, boolean bold, int fontSize) {
XWPFRun run = p.createRun();
run.setText(text);
run.setBold(bold);
run.setFontSize(fontSize);
run.setFontFamily("微软雅黑");
return run;
}
}
在网上的创建PDF笔记
https://cloud.tencent.com/developer/article/1636609
创建Document对象,三种方式:
Document document =new Document(); // 默认页面大小是A4
Document document =new Document(PageSize.A4); // 指定页面大小为A4
Document document =new Document(PageSize.A4,50,50,30,20); // 指定页面大小为A4,且自定义页边距(marginLeft、marginRight、marginTop、marginBottom)
4.application.yml:
在配置中,有(application:应用)
upload:
path: E:/upload/
5.BladeConfiguration文件
@Value("${upload.path}")
private String uploadPath;
附:
ParagraphAlignment:段落对齐枚举类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.poi.xwpf.usermodel;
import java.util.HashMap;
import java.util.Map;
public enum ParagraphAlignment {
LEFT(1),
CENTER(2),
RIGHT(3),
BOTH(4),
MEDIUM_KASHIDA(5),
DISTRIBUTE(6),
NUM_TAB(7),
HIGH_KASHIDA(8),
LOW_KASHIDA(9),
THAI_DISTRIBUTE(10);
private static Map<Integer, ParagraphAlignment> imap = new HashMap();
private final int value;
private ParagraphAlignment(int val) {
this.value = val;
}
public static ParagraphAlignment valueOf(int type) {
ParagraphAlignment err = (ParagraphAlignment)imap.get(type);
if (err == null) {
throw new IllegalArgumentException("Unknown paragraph alignment: " + type);
} else {
return err;
}
}
public int getValue() {
return this.value;
}
static {
ParagraphAlignment[] arr$ = values();
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
ParagraphAlignment p = arr$[i$];
imap.put(p.getValue(), p);
}
}
}
标签:vue,java,Font,setAlignment,XWPFDocument,new,document,id,LEFT 来源: https://www.cnblogs.com/longyoudahai/p/15899520.html