ivew组件上传图片文件的功能:

解决的问题:

  1、使用view的<Upload>组件实现图片文件的上传。

  2、<Upload>组件action请求地址无法到自己写的后台。

  3、前台base64的图片展示。

  4、文件伪造。(修改文件的后缀为图片格式的后缀)。

需求很简单:

  将某一模块的编辑页面的"XX图片"字段由文本框输入改成上传图片。或者新增一个图片上传的属性。

  要求:

  1、 前端图片展示用BASE64格式的形式展示。

一、完成后的效果图:

1、上传前

2、点击相机,选择图片文件进行上传。

2.1 文件格式的校验

2.2 文件大小的限制

3、上传后

 4、点击图片中的眼睛图标,可以对图片进行放大查看。

 5、点击图片中的垃圾筒的图标,可以对图片进行删除。回到上传前。

二、前端vue组件代码。

 官网地址:

https://www.iviewui.com/components/upload

<template>
              <div class="demo-upload-list" v-if="formData.stationPic">
                <template>
                  <img :src="formData.stationPic">
                  <div class="demo-upload-list-cover">
                    <Icon type="ios-eye-outline" @click.native="handleView()"></Icon>
                    <Icon type="ios-trash-outline" @click.native="handleRemove()"></Icon>
                  </div>
                </template>
              </div>
              <Upload
                ref="upload"
                :show-upload-list="false"
                :on-success="handleSuccess"
                :format="['jpg','jpeg']"
                :max-size="2048"
                :on-format-error="handleFormatError"
                :on-exceeded-size="handleMaxSize"
                :before-upload="handleBeforeUpload"
                :headers="headers"
                type="drag"
                action="/api/zclanes/upload"
                style="display: inline-block;width:58px;">
                <div style="width: 58px;height:58px;line-height: 58px;">
                  <Icon type="ios-camera" size="20"></Icon>
                </div>
              </Upload>
              <Modal title="View Image" v-model="visible">
                <img :src="formData.stationPic" v-if="visible" style="width: 100%">
              </Modal>
            </template>
    data() {
      return {
        headers: {'Sonep-Token': CacheUtil.getSession('access-token')},
        visible: false,
    },
    methods: {
      handleView() {
        this.visible = true;
      },
      handleRemove() {
        this.formData.stationPic = null;
      },
      handleSuccess(res, file) {
        if (res.status === 200) {//上传成功
          this.$Message.success('上传成功');
          this.formData.stationPic = res.data;
        } else {
          this.$Message.error('上传失败');
        }
      },
      handleFormatError(file) {
        this.$Notice.warning({
          title: '文件格式不正确',
          desc: file.name + '的文件格式不正确, 请选择jpg或者jpeg格式的图片'
        });
      },
      handleMaxSize(file) {
        this.$Notice.warning({
          title: '超出文件大小限制',
          desc: file.name + '文件太大,不能超过2M.'
        });
      },
      handleBeforeUpload() {//上传文件之前的钩子,参数为上传的文件,若返回 false 或者 Promise 则停止上传

      }

    },

 三、后端代码

3.1 controller

    /**
     * 图片上传
     * @param file
     * @return
     */
    @RequestMapping("/upload")
    public ResponsePayload upload(MultipartFile file){

        return service.upload(file);
    }

3.2 service

    @Override
    public ResponsePayload upload(MultipartFile file) {

        try {
            //判断文件是不是图片
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0) {
                return ResponseUtil.getFailResponse(HttpStatus.SC_BAD_REQUEST, "你上传的不是图片文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseUtil.getFailResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "上传异常, 请稍后再试...");
        }

        //获取文件的路径
        String filePath = IOHelper.checkPath(System.getProperty("java.io.tmpdir")) + "\\img";
//        String filePath = FileUtils.getDataFilePath("d:/img");
        //1. 获取文件的原始名称
        String originalFilename = file.getOriginalFilename();//timg (1).jpg
        //1.1 获取最后一个.的位置
        int lastIndexOf = file.getOriginalFilename().lastIndexOf(".");
        //1.2 获取文件的后缀名 .jpg
        String suffix = originalFilename.substring(lastIndexOf);
        //2. 重命名文件名称
        String fileName = UUID.randomUUID().toString() + suffix;
        File savedFile = new File(filePath, fileName);
        try {
            file.transferTo(savedFile);
            //转BASE64
            String path = savedFile.getPath();
            //返回BASE64图片字符串
            return ResponseUtil.success(ImageBase64Utils.toBase64(path));
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseUtil.getFailResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR,"上传异常, 请稍后再试...");
        } finally {
            //删除本地保存的图片
            savedFile.delete();
        }

    }

四、问题回顾及解决

我们依次看下文章开头提到的4个问题

4.1 使用view的<Upload>组件实现图片文件的上传。

可以看下本文的第二部分:前端vue组件代码。

同时也给出官网地址:

https://www.iviewui.com/components/upload

4.2 <Upload>组件action请求地址无法到自己写的后台。

这个问题很恶心。

4.2.1 action地址的写法

官网用的是自己写的请求地址:action="//jsonplaceholder.typicode.com/posts/"。仔细一看是什么鬼,怎么有两个斜杠。

运行下官网的例子:

我们看到发送的请求是:https://jsonplaceholder.typicode.com/posts/。

 仔细分析下:发现地址前面是带域名的:jsonplaceholder.typicode.com

这里有几种写法:

写法一:如果域名是不变的。

action="//localhost:8080/api/zclanes/upload"  ---> http://localhost:8080/api/zclanes/upload

写法二:不加域名的写法。(本文用的是这种)

action="/api/zclanes/upload"   ---> http://localhost:8080/zclanes/api/upload

4.2.2 请求的发送

填写完正确的地址后,后台代码也写好了。重启项目后,请求发送不出去。

我这里最后查出来是少加了个请求头。猜测:项目有auth功能,每个请求都必须加鉴权的请求头进行鉴权。如果有跟我一样的问题,找到要加的请求头,把请求头加上去就ok了。部分代码如下,详细代码上文有。其实想说明的是,<Upload>组件请求头如何添加。 其实还可以添加请求参数,具体参考官网API。

:headers="headers"
headers: {'Sonep-Token': CacheUtil.getSession('access-token')},

4.2.3 前台base64的图片展示。

参考地址:https://www.cnblogs.com/hjw-zq/p/8821898.html

其实就一句代码:

formData.stationPic: 就是后台返回的BASE64的字符串。
<img :src="formData.stationPic">

base图片展示原理: https://www.cnblogs.com/zdz8207/p/web-image-base64.html

个人理解:将图片文件转成BASE64格式的字符串。由页面自动会解析BASE64格式的图片文件。跟图片文件所在路径的没有关系。

4.2.4 文件伪造。(修改文件的后缀为图片格式的后缀)。

其实解决完上面三个问题,这个功能完成的就八九不离十了。 当我在测文件大小限制的时候,我电脑里没找到2M的图片,于是我就找了个2M的excel文件,把它的后缀名改成了图片格式进行上传。测试通过。于是我就想到了,如果小于2M的文件改了会上传成功么。 我的答案肯定是不允许的,因为它本质就不是图片。测试也能上传成功,但就是显示不出图案来。这肯定是不对的。

于是我就想到了还少个判断文件是否是图片的逻辑。

Java判断文件是否是图片:
参考地址:https://blog.csdn.net/itjauser/article/details/97395034

五、小结:

图片上传看似简单的一个动作,其实过程很复杂。

流程大致如下:

1、选择上传的文件,发送请求。(这里请求的业务逻辑有很多种解决方案,可以把图片上传到服务器(七牛云、阿里云、本地的数据库等)。或者转成BASE64格式的字符串。不管哪种实现方式,目的都是为了把图片以某种形式存放起来,并将图片地址存放的地址返回,在前台进行显示)。

2、 将图片以BASE64的形式存储。

3、 返回BASE64字符串。

4、 拿到后台响应的图片地址,进行展示。

猜你喜欢

转载自www.cnblogs.com/yuanke-blog/p/11928013.html