vue+springboot+vue-pdf组件映射数据库实现pdf在线预览

 老师开题指导的时候叫加一个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公主号:小伍的小屋,获取联系方式,有问题我尽量解决