SpringBoot OSS实战之用户头像上传

时间:2022-10-20 10:57:02

前言

已经开始对写接口产生厌烦了,毫无技术含量,不过也是最近把用户的比较核心的功能做出来了。准备开始写一些主要功能了,其实这个更好写,我打算搞两个版本,一个是lite版本就是能用,技术实现简单,但是资源消耗低,还有就是完整版本,适合有软妹币的时候玩玩。

那么十月十更的第九更就要出来了。那么第十更自然就是咱们的TSP的这个不会鸽的,但是发布的话要等,等下个礼拜,一方面是我最近没写(其实写也快,顶多一上午)还有一方面是作为作业交上去的。

那么还是不废话吧,发车了。

OSS整合

首先的话要玩这个先对OSS服务进行整合,这个的话,在懒人系列–文件上传之OSS使用案例已经说的很明白了。其实当时的使用流程其实我也说明白了:
SpringBoot OSS实战之用户头像上传
只不过当时是由于咱们整个的玩意还没搞起来(当时我甚至连前端都木有写好)现在的话早就搭好了,只是懒得写而已。

前端

老规矩我们先看到前端。这个前端的话其实,一开始咱们是直接使用element-ui的图片上传组件的。但是在咱们的这里的话:
SpringBoot OSS实战之用户头像上传

咱们这个是自己搞的,所以的话,得自己重写一些东西。
然后也是看看了那个element-ui的上传图片的组件源码,然后对这里面的东西进行了实现,从而完成了咱们完整的一个步骤。

获取授权

首先的话,我们需要获取到授权

   pullImg(filename) {
      let _self = this;
        // 获取认证码
        this.axios
          .get('/third-part/oss/userSpaceUpImgPolicy')
          .then(response => {
            response = response.data;
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+"_"+filename;
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            //推送到OSS
            this.uploadImg();
          }).catch(function (error) {
            alert(error)
            console.log("出错了...",err)
          })
      },

这个获取授权的后端代码其实和我们先前的那个是一样的,只是我这里改了接口罢了。

上传图片

这里的上传图片的话其实是指上传到咱们的这个OSS里面。

    uploadImg(){
      //组装数据
      let formData = new FormData();
      Object.keys(this.dataObj).forEach(key => {
        // 添加一个新值到 formData 对象内的一个已存在的键中,如果键不存在则会添加该键。
        formData.append(key, this.dataObj[key]);
      });
      formData.append('file',this.f64)
      //此时发送请求去给到OSS
      this.axios({
        url: this.dataObj.host,
        method: 'post',
        data: formData
      }).then((res) => {
        let imgpath = this.dataObj.host + '/' + this.dataObj.key;
        //将得到的图片地址返回到我们的服务器
        this.upImgPath(imgpath)
      })
    },

当上传到OSS之后的话,如果上传成功的话,那么此时我们就可以将对应的图片的地址给返回到我们的后端服务器进行存储那个URL了。

上传URL到服务端


    upImgPath(imgpath){
      //将图片的地址上传到我们的服务器
      this.axios({
        url: "/user/user/space/userUpImg",
        method: 'post',
        headers: {
          "userid": this.userid,
          "loginType": "PcType",
          "loginToken": this.loginToken,
        },
        data: {
          'userid': this.userid,
          'imgpath': imgpath
        }
      }).then((res) => {
        res = res.data;
        if (res.code === 0) {
          alert("头像上传成功,一天后才可以重新上传哟~")
        } else {
          this.$message.error(res.msg);
        }
      });
    },

完整代码

ok, 那么这个就是我们的完整的代码了:

<template>
  <div>
    <div class="show">
      <div class="show1" >
        <img ref="showing" src="" id="showimg" style="margin-left: 1px;margin-top: 3px">
      </div>
      <br>
      <div class="upload">图片选择
      <input multiple="multiple" id="file" ref="file"
             accept=".jpg,.png"
             @click="changepic(this)" type="file" name="userpic"
             style="
              position: absolute;
              overflow: hidden;
              right: 0;
              top: 0;
              opacity: 0;
             width: 100%;
             height: 32px;
             "
      >
      </div>
      <el-tooltip content="一天只允许提交一次哟~" placement="top">
      <button @click="subchangepic()" style="height: 40px;position: relative; margin-left:35%;">确定</button>
      </el-tooltip>
    </div>
  </div>
</template>

<script>
import {getUUID} from "../../components/upload/uuid";

export default {
  name: "imageUp",
  data(){
    return {
      userid: null,
      loginToken: null,
      filename: null,
      f64: null,
      loadImage: "",
      dataObj: {
        policy: '',
        signature: '',
        key: '',
        ossaccessKeyId: '',
        dir: '',
        host: '',
        // callback:'',
      },
    }
  },
  created() {
    let loginToken = localStorage.getExpire("LoginToken");
    let userid = localStorage.getExpire("userid");
    //这个只有用户自己才能进入,自己只能进入自己对应的MySpace
    if(loginToken==null && userid==null) {
      alert("检测到您未登录,请先登录")
      this.$router.push({path: "/login"});
    }else {
      this.userid=userid;
      this.loginToken = loginToken;
    }
  },
  methods: {

    pullImg(filename) {
      let _self = this;
        // 获取认证码
        this.axios
          .get('/third-part/oss/userSpaceUpImgPolicy')
          .then(response => {
            response = response.data;
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+"_"+filename;
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            //推送到OSS
            this.uploadImg();
          }).catch(function (error) {
            alert(error)
            console.log("出错了...",err)
          })
      },

    upImgPath(imgpath){
      //将图片的地址上传到我们的服务器
      this.axios({
        url: "/user/user/space/userUpImg",
        method: 'post',
        headers: {
          "userid": this.userid,
          "loginType": "PcType",
          "loginToken": this.loginToken,
        },
        data: {
          'userid': this.userid,
          'imgpath': imgpath
        }
      }).then((res) => {
        res = res.data;
        if (res.code === 0) {
          alert("头像上传成功,一天后才可以重新上传哟~")
        } else {
          this.$message.error(res.msg);
        }
      });
    },

    uploadImg(){
      //组装数据
      let formData = new FormData();
      Object.keys(this.dataObj).forEach(key => {
        // 添加一个新值到 formData 对象内的一个已存在的键中,如果键不存在则会添加该键。
        formData.append(key, this.dataObj[key]);
      });
      formData.append('file',this.f64)
      //此时发送请求去给到OSS
      this.axios({
        url: this.dataObj.host,
        method: 'post',
        data: formData
      }).then((res) => {
        let imgpath = this.dataObj.host + '/' + this.dataObj.key;
        //将得到的图片地址返回到我们的服务器
        this.upImgPath(imgpath)
      })
    },

    subchangepic(){
      /**
      * 更换头像,现在的情况是:
       * 1.拿到第三方OSS服务的授权
       * 2.通过授权,去上传图片
       * 3.拿到授权后的图片,并将链接上传到服务端
      * */
      if(this.$refs.file.files[0]!=null) {
        this.f64 = this.$refs.file.files[0];
        let filename = this.f64.name;
        //此时先拿到授权
        this.pullImg(filename)
      }
    },

    changepic() {
      document.getElementById('file').onchange = function () {
        var imgFile = this.files[0];
        var fr = new FileReader();

        fr.onload = function () {
          let showing = document.getElementById('showimg')
          let img = fr.result;
          this.f64 = img;
          this.filename = imgFile.name
          showing.src = img;
          showing.style.height = "220px";
          showing.style.width = "220px";
          showing.style.borderRadius = "200px"
        };
        fr.readAsDataURL(imgFile);
      }
    },
  }
}
</script>

<style scoped>

.upload{
  margin-left: 20%;
  width: 12%;
  text-align: center;
  color: white;
  height: 32px;
  border-radius: 3px;
  background: #1E90FF;
  cursor: pointer;
  outline: none;
  border-width: 0px;
  font-size: 17px;
  display:inline-block;
  padding: 4px 10px;
  line-height:30px;
  position: relative;
  text-decoration: none;

}

button {
  margin-left: 70%;
  width: 15%;
  height: 35px;
  border-width: 0px;
  border-radius: 3px;
  background: #1E90FF;
  cursor: pointer;
  outline: none;
  color: white;
  font-size: 17px;
}
.show{
  margin: 100px auto;
  width: 80%;
  height: 450px;
  border: 5px solid #18a0ec;
  transition: all 0.9s;
  border-radius: 10px;

}
.show1{
  margin: 50px auto;
  width: 222px;
  height: 226px;
  border: 5px solid #18a0ec;
  transition: all 0.9s;
  border-radius: 150px;

}

.show1:hover{
  box-shadow: 0px 15px 30px rgba(0, 0, 0, 0.4);
  margin-top: 45px;
}

.show:hover{
  box-shadow: 0px 15px 30px rgba(0, 0, 0, 0.4);
  margin-top: 45px;

}

.texti{
  border: 1px solid #ccc;
  padding: 13px 14px;
  width: 30%;

  font-size: 14px;
  font-weight: 300;

  border-radius: 5px; /* 边框半径 */
  background: white; /* 背景颜色 */
  cursor: pointer; /* 鼠标移入按钮范围时出现手势 */
  outline: none; /* 不显示轮廓线 */


}
.texti:focus{
  border-color: #1e88e1;
  outline: 0;
  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
  box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
}
textarea {
  resize: none;

}
</style>

后端

首先这个授权这块,我就不说了,先前说过,就在OSS整合里面!
那么我们这块就主要是保存好我们的这个图片地址就好了。

图片URL接收

 @Override
    public R userUpImg(UserHandImgEntity entity) {
        if(redisUtils.hasKey(RedisTransKey.getUserUpHeadImgKey(entity.getUserid()))){
            return R.error(BizCodeEnum.OVER_REQUESTS.getCode(), BizCodeEnum.OVER_REQUESTS.getMsg());
        }
        UserEntity User = userService.getOne(
                new QueryWrapper<UserEntity>().eq("userid", entity.getUserid())
        );
        if(User!=null){
            HeadimgEntity headimgEntity = new HeadimgEntity();
            BeanUtils.copyProperties(entity,headimgEntity);
            headimgEntity.setCreatTime(DateUtils.getCurrentTime());
            headimgService.save(headimgEntity);
            redisUtils.set(RedisTransKey.setUserUpHeadImgKey(entity.getUserid())
                    ,1,1, TimeUnit.DAYS
            );
            return R.ok(BizCodeEnum.SUCCESSFUL.getMsg());
        }else {
            return R.error(BizCodeEnum.NO_SUCHUSER.getCode(),BizCodeEnum.NO_SUCHUSER.getMsg());
        }
    }

补充

这里的话,值得一提的是这个BeanUtils,这个玩意咱们先前也说过,不过我这里还是要说的就是,先前那个如果进行网络传输的话,其实还是需要序列化的,这个我当时没说,忘了,那么这里的话给出我用的工具类拿出来吧:


public class SerializeUtil {

    /**
     * 字节数组转换为字符串
     */
    public static String bytesToString(byte[] bytes) {
        return org.apache.commons.codec.binary.Base64.encodeBase64String(bytes);
    }

    /**
     * 字符串转换为字节数组
     * @param str
     * @return
     */
    public static byte[] stringToByte(String str) throws DecoderException {
        return org.apache.commons.codec.binary.Base64.decodeBase64(str);
    }

    /**
     * @param obj 序列化对象
     * @return  对象序列化之后的字符串
     */
    public static String serialize(Serializable obj) throws Exception{
        if(obj!=null) {
            byte[] bytes = SerializationUtils.serialize(obj);
            return bytesToString(bytes);
        }
        return null;
    }

    /**
     * @param str   反序列化字符串
     * @return      反序列化之后的对象
     */
    public static <T extends Serializable> T deserialize(String str) throws Exception{
        if(StringUtils.isNotEmpty(str)){
            return SerializationUtils.deserialize(stringToByte(str));
        }
        return null;
    }
}

效果演示

之后的话我们来看到效果:
上传图片
SpringBoot OSS实战之用户头像上传
上传成功
SpringBoot OSS实战之用户头像上传

实际效果
SpringBoot OSS实战之用户头像上传
OSS控制台
SpringBoot OSS实战之用户头像上传
可以看到完整的效果