老师开题指导的时候叫加一个vue+springboot在线预览pdf的功能,用pdf.js没搞定,最后用vue-pdf完成了,上代码
一、数据库段
确保你数据库表有相应的字段,如图,字段为pdf(存的时间戳)
二、后端部分
代码如下,直接拿,gpt给的解释
FileController.java
// 文件上传接口
@RestController
@RequestMapping("/files")
public class FileController {
// 文件上传存储路径
private static final String filePath = System.getProperty("user.dir") + "/file/";
@PostMapping("/upload") // 左边:PostMapping注解,右边:方法声明
public Result upload(MultipartFile file) { // 左边:方法声明,右边:方法体开始
synchronized (FileController.class) { // 左边:同步块开始,右边:同步块结束
String flag = System.currentTimeMillis() + ""; // 左边:变量声明,右边:变量赋值
String fileName = file.getOriginalFilename(); // 左边:变量声明,右边:方法调用
try { // 左边:try块开始,右边:try块结束
if (!FileUtil.isDirectory(filePath)) { // 左边:条件判断,右边:方法调用
FileUtil.mkdir(filePath); // 左边:方法调用,右边:方法参数
}
// 文件存储形式:时间戳-文件名
FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName); // 左边:方法调用,右边:方法参数
System.out.println(fileName + "--上传成功"); // 左边:方法调用,右边:字符串拼接
Thread.sleep(1L); // 左边:方法调用,右边:方法参数
} catch (Exception e) { // 左边:catch块开始,右边:catch块结束
System.err.println(fileName + "--文件上传失败"); // 左边:方法调用,右边:字符串拼接
}
return Result.success(flag); // 左边:return语句,右边:方法调用
}
}
/**
* 获取文件
*/
@GetMapping("/{flag}") // 左边:GetMapping注解,右边:方法声明
public void avatarPath(@PathVariable String flag, HttpServletResponse response) { // 左边:方法声明,右边:方法参数
if (!FileUtil.isDirectory(filePath)) { // 左边:条件判断,右边:方法调用
FileUtil.mkdir(filePath); // 左边:方法调用,右边:方法参数
}
OutputStream os; // 左边:变量声明
List<String> fileNames = FileUtil.listFileNames(filePath); // 左边:变量声明,右边:方法调用
String avatar = fileNames.stream().filter(name -> name.contains(flag)).findAny().orElse(""); // 左边:变量声明,右边:Stream操作
try { // 左边:try块开始,右边:try块结束
if (StrUtil.isNotEmpty(avatar)) { // 左边:条件判断,右边:方法调用
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(avatar, "UTF-8")); // 左边:方法调用,右边:方法参数
response.setContentType("application/octet-stream"); // 左边:方法调用,右边:方法参数
byte[] bytes = FileUtil.readBytes(filePath + avatar); // 左边:变量声明,右边:方法调用
os = response.getOutputStream(); // 左边:变量赋值
os.write(bytes); // 左边:方法调用,右边:方法参数
os.flush(); // 左边:方法调用
os.close(); // 左边:方法调用
}
} catch (Exception e) { // 左边:catch块开始,右边:catch块结束
System.out.println("文件下载失败"); // 左边:方法调用,右边:字符串
}
}
/**
* wang-editor编辑器文件上传接口
*/
@PostMapping("/wang/upload") // 左边:PostMapping注解,右边:方法声明
public Map<String, Object> wangEditorUpload(MultipartFile file) { // 左边:方法声明,右边:方法参数
String flag = System.currentTimeMillis() + ""; // 左边:变量声明,右边:变量赋值
String fileName = file.getOriginalFilename(); // 左边:变量声明,右边:方法调用
try { // 左边:try块开始,右边:try块结束
// 文件存储形式:时间戳-文件名
FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName); // 左边:方法调用,右边:方法参数
System.out.println(fileName + "--上传成功"); // 左边:方法调用,右边:字符串拼接
Thread.sleep(1L); // 左边:方法调用,右边:方法参数
} catch (Exception e) { // 左边:catch块开始,右边:catch块结束
System.err.println(fileName + "--文件上传失败"); // 左边:方法调用,右边:字符串拼接
}
Map<String, Object> resMap = new HashMap<>(); // 左边:变量声明
// wangEditor上传文件成功后,需要返回的参数
resMap.put("errno", 0); // 左边:Map赋值
resMap.put("data", CollUtil.newArrayList(Dict.create() // 左边:Map赋值,右边:List创建
.set("url", "http://localhost:8080/api/files/" + flag))); // 左边:Dict创建,右边:字符串拼接
// 添加对pdf文件的处理
if ("pdf".equalsIgnoreCase(FilenameUtils.getExtension(file.getOriginalFilename()))) { // 左边:条件判断,右边:方法调用
resMap.put("pdf", flag); // 左边:Map赋值
}
return resMap; // 左边:return语句,右边:变量
}
}
三、前端部分(最重要)
下载vue-pdf大家自行百度
点击预览可以直接打开pdf ,用的element-ui
上代码
<el-table-column label="图书预览"> <template v-slot="scope"> <el-button type="primary" @click="openPdfPreview(scope.row)">预览</el-button> </template> </el-table-column>
<el-table-column label="操作" min-width="150px"> <template slot-scope="scope"> <el-button type="primary" @click="download(scope.row)">下载</el-button> </template> </el-table-column>
<div> <el-dialog :title="currentBookName" :visible.sync="viewVisible" center width="40%" @close='closePreview'> <el-row :gutter="20"> <span>共{{pageCount}}页, 当前第 {{pdfPage}} 页 </span> <el-button type="text" size="mini" @click.stop="previousPage">上一页</el-button> <el-button type="text" size="mini" @click.stop="nextPage">下一页</el-button> </el-row> <div> <pdf :src="src" :page="pdfPage" @num-pages="pageCount = $event" @page-loaded="pdfPage = $event" style="display: inline-block; width: 100%"></pdf> </div> </el-dialog> </div>
<script>
import request from "@/utils/request";
import { BASE_URL } from "@/utils/common";
import pdf from 'vue-pdf';
export default {
components: {
pdf
},
data() {
return {
params: {
name: '',
author: '',
pageNum: 1,
pageSize: 5,
},
tableData: [],
total: 0,
dialogFormVisible: false,
form: {},
typeObjs: [],
user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {},
currentBookName: '',
src: null,
pdfPage: 1,
pageCount: 0,
viewVisible: false
}
},
created() {
this.findBySearch();
this.findTypes();
},
methods: {
openPdfPreview(book) {
this.currentBookName = book.name;
if (!book.pdf || book.pdf.length == 0) {
this.$message.info('未上传pdf文件,暂无法预览');
return;
}
const url = `${BASE_URL}/files/${book.pdf}`;
this.pdfPreview(url);
},
handlePreview(file) {
this.currentBookName = file.name;
const url = `${BASE_URL}/files/${file.response.data}`;
this.pdfPreview(url);
},
pdfPreview(url) {
this.src = pdf.createLoadingTask({
url
});
this.src.promise.then(pdf => {
this.viewVisible = true;
}).catch(err => {
this.$message.info('未上传pdf或文件加载失败,暂无法预览');
});
},
closePreview() {
this.pdfPage = 1;
},
previousPage() {
let p = this.pdfPage;
p = p > 1 ? p - 1 : this.pageCount;
this.pdfPage = p;
},
nextPage() {
let p = this.pdfPage;
p = p < this.pageCount ? p + 1 : 1;
this.pdfPage = p;
},
findTypes() {
request.get("/type").then(res => {
if (res.code === '0') {
this.typeObjs = res.data;
} else {
this.$message.error(res.msg);
}
});
},
findBySearch() {
request.get("/book/search", {
params: this.params
}).then(res => {
if (res.code === '0') {
this.tableData = res.data.list;
this.total = res.data.total;
} else {
this.$message({
message: res.msg,
type: 'error'
});
}
});
},
// 其他方法省略
}
}
</script>
四、注意问题
大家实体类还要有相应的pdf类
get,set方法自己生成
还要看自己的跨域配置,否则会报500
加一个common.js
五、成功展示
有问题可以关注博主vx公主号:小伍的小屋,获取联系方式,有问题我尽量解决