实战13 上传文件、个人中心头像更新

目录

一、上传文件

1、SpringBoot实现文件上传,查询、删除、批量删除和更新

2、Vue实现上传、下载、删除、批量删除、更新、查询

二、头像更新

1、Person.vue 

2、header头像信息更新:子组件Person-》父Manage=》 子组件Header


一、上传文件

1、SpringBoot实现文件上传,查询、删除、批量删除和更新

package com.example.demo.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Result;
import com.example.demo.entity.Files;
import com.example.demo.entity.User;
import com.example.demo.mapper.FileMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

@RestController
@RequestMapping("/file")
public class FileController {
    @Value("${files.upload.path}")
    private String fileUploadPath;

    @Resource
    private FileMapper fileMapper;

    /**
     * 文件上传
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException {
        String originalFileName = file.getOriginalFilename();
        String type = FileUtil.extName(originalFileName);
        long size = file.getSize();
        //存储磁盘
        File uploadParentFile = new File(fileUploadPath);
        if (!uploadParentFile.exists()) {
            uploadParentFile.mkdir();
        }
        String uuid = IdUtil.fastSimpleUUID();
        String fileUuid = uuid + StrUtil.DOT + type;

        File uploadFile = new File(fileUploadPath + fileUuid);
        //当文件存在的时候获取文件的md5
        String url;
        String md5;
        file.transferTo(uploadFile);
        md5 = SecureUtil.md5(uploadFile);
        //获取文件的md5,避免相同文件重复上传
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5);
        //从数据库查询,避免相同文件记录
        List<Files> filesList = fileMapper.selectList(queryWrapper);
        Files dbFiles = filesList.size() == 0 ? null : filesList.get(0);
        if (dbFiles != null) {
            url = dbFiles.getUrl();
            //由于文件已存在,删除刚才上传重复的文件
            uploadFile.delete();
        } else {
            //文件不存在重复文件,不删除刚才上传文件
            url = "http://localhost:9090/file/" + fileUuid;
        }

        //存储数据库
        Files saveFile = new Files();
        saveFile.setName(originalFileName);
        saveFile.setType(type);
        saveFile.setSize(size / 1024);
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        fileMapper.insert(saveFile);
        return url;
    }

    /**
     * 文件下载接口
     *
     * @param fileUuid
     * @param response
     * @throws IOException
     */
    @GetMapping("/fileUuid")
    public void download(@PathVariable String fileUuid, HttpServletResponse response) throws IOException {
        File uploadFile = new File(fileUploadPath + fileUuid);
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUuid, "UTF-8"));
        response.setContentType("application/octet-Stream");
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    /**
     * 分页查询
     *
     * @param pageNum
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize,
                           @RequestParam String name) {
        IPage<Files> page = new Page<>(pageNum, pageSize);
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete", false);
        if (!"".equals(name)) {
            queryWrapper.like("name", name);
        }
        queryWrapper.orderByDesc("id");
        return Result.success(fileMapper.selectPage(page, queryWrapper));
    }

    /**
     * 文件删除
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        Files files = fileMapper.selectById(id);
        files.setIsDelete(true);
        return Result.success(fileMapper.updateById(files));
    }

    /**
     * 文件批量删除
     *
     * @param ids
     * @return
     */
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        List<Files> lf = fileMapper.selectList(queryWrapper);
        for (Files file : lf) {
            file.setIsDelete(true);
            fileMapper.updateById(file);
        }
        return Result.success();
    }

    /**
     * 文件更新
     *
     * @param files
     * @return
     */
    @PostMapping("/update")
    public Result update(@RequestBody Files files) {
        return Result.success(fileMapper.updateById(files));
    }
}
public interface FileMapper extends BaseMapper<Files> {
}

2、Vue实现上传、下载、删除、批量删除、更新、查询

File.vue

<template>
  <div>
    <div style="margin: 10px 0;">
      <el-input suffix-icon="el-icon-search" style="width: 200px;" placeholder="请输入名称" class="search" v-model="name" clearable></el-input>
      <el-button class="ml-5" type="primary" @click="load">查询</el-button>
      <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
    </div>
    <div style="margin: 10px 0">
      <el-upload action="http://localhost:9090/file/upload" :show-file-list="false" :on-success="handleFileUploadSuccess" style="display: inline-block;">
        <el-button type="primary" class="ml-5" >上传文件<i class="el-icon-top"></i></el-button>
      </el-upload>
      <el-popconfirm
        class="ml-5"
        confirm-button-text='确认'
        cancel-button-text='我再想想'
        icon="el-icon-info"
        icon-color="red"
        title="您确定删除吗?"
        @confirm ="delBatch" >
        <el-button type="danger" slot="reference">批量删除<i class="el-icon-remove-outline"></i></el-button>
      </el-popconfirm>
    </div>
    <el-table :data="tableData"  border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange">
>
      <el-table-column type="selection" width="55"> </el-table-column>
      <el-table-column prop="id" label="ID" >
      </el-table-column>
      <el-table-column prop="name" label="文件名称">
      </el-table-column>
      <el-table-column prop="type" label="文件类型" >
      </el-table-column>
      <el-table-column prop="size" label="文件大小">
      </el-table-column>
      <el-table-column label="下载">
        <template slot-scope="scope">
          <el-button type="primary" @click="download(scope.row.url)"></el-button>
        </template>

      </el-table-column>
      <el-table-column prop="enable" label="启用">
        <template slot-scope="scope">
          <el-switch v-model="scope.row.enable" active-color="#13ce66" inactive-color="#ccc" @change="changeEnable(scope.row)"></el-switch>

        </template>
      </el-table-column>
      <el-table-column label="操作" width="200px" align="center">
        <template slot-scope="scope">
          <el-popconfirm
            class="ml-5"
            confirm-button-text='确认'
            cancel-button-text='我再想想'
            icon="el-icon-info"
            icon-color="red"
            title="您确定删除吗?"
            @confirm ="del(scope.row.id)" >
            <el-button type="danger" slot="reference">删除<i class="el-icon-remove-outline"></i></el-button>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
    <div style="padding: 10px 0;">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="pageNum"
        :page-sizes="[2, 5, 10, 20]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total">
      </el-pagination>
    </div>
  </div>

</template>
<script>
export default {
  name: 'File',
  data(){
    return{
      tableData:[],
      name:'',
      multipleSelection:[],
      pageNum: 1,
      pageSize: 10,
      total: 0  
    }
  },
  created(){
    this.load();

  },
  methods: {
    handleSizeChange(pageSize) {
        console.log(pageSize);
        this.pageSize = pageSize;
        this.load();
    },
    handleCurrentChange(pageNum) {
        console.log(pageNum);
        this.pageNum = pageNum;
        this.load();
    },
    load() {
        this.request.get("/file/page", {
            params: {
                pageNum: this.pageNum,
                pageSize: this.pageSize,
                name: this.name
            }
        }).then(res => {
            console.log(res);
            this.tableData = res.data.records;
            this.total = res.data.total;
        })
    },
    reset() {
        this.name = '',
            this.load();
    },

 
    del(id) {
        this.request.delete("/file/" + id).then(res => {
            if (res.code === '200') {
                this.$message.success("删除成功");
                this.load();
            }
            else {
                this.$message.error("删除失败");
            }
        });
    },
    handleSelectionChange(val) {
        console.log(val);
        this.multipleSelection = val;
    },
    delBatch() {
        let ids = this.multipleSelection.map(v => v.id); //[1,2,3]
        this.request.post("/file/del/batch", ids).then(res => {
            if (res.code === '200') {
                this.$message.success("删除成功");
                this.load();
            }
            else {
                this.$message.error("删除失败");
            }
        });
    },
    handleFileUploadSuccess(res){
      this.load()
    },
    download(url){
      window.open(url)
    },
    changeEnable(row){
      this.request.post("/file/update", row).then(res => {
            if (res.code === '200') {
                this.$message.success("操作成功");
            }
  
        });    
      }

  }

}
</script>
<style scoped>
</style>

二、头像更新

1、Person.vue 

<template>
  <el-card style="width: 500px">
    <el-upload class="avatar-uploader" action="http://localhost:9090/file/upload" :show-file-list="false"
      :on-success="handleAvatarSuccess">
      <img v-if="form.avatarUrl" :src="avatarUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>

    <el-form label-width="80px" size="small">
      <el-form-item label="用户名">
        <el-input v-model="form.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="昵称">
        <el-input v-model="form.nickname" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="邮箱">
        <el-input v-model="form.email" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="电话">
        <el-input v-model="form.phone" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="地址">
        <el-input v-model="form.address" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="save">确 定</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>
<script>

export default {
  name: "Person",
  data() {
    return {
      form: {},
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
    this.getUser().then(res => {
      this.form = res
    })
  },
  methods: {
    async getUser() {
      return (await this.request.get("/user/username/" + this.user.username)).data

    },
    save() {
      this.request.post("/user", this.form).then(res => {
        if (res.code === '200') {
          this.$message.success("保存成功");
          //更新浏览器存储的用户信息
          this.getUser().then(res => {
            res.token = JSON.parse(localStorage.getItem("user")).token
            localStorage.setItem("user", JSON.stringify(user))
          })

        } else {
          this.$message.error("保存失败");
        }
      });
    },
    handleAvatarSuccess(res) {
      this.form.avatarUrl = res
    }
  }
}
</script>
<style scoped>
.avatar-uploader {
  text-align: center;
  padding-bottom: 5px;
}

.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

.avatar-uploader .el-upload:hover {
  border-color: #409EFF;
}

.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 138px;
  height: 138px;
  line-height: 138px;
  text-align: center;
}

.avatar {
  width: 138px;
  height: 138px;
  display: block;
}
</style>

2、header头像信息更新:子组件Person-》父Manage=》 子组件Header

1)Person.vue: //触发父级更新User的事件refreshUser

    save() {
      this.request.post("/user", this.form).then(res => {
        if (res.code === '200') {
          this.$message.success("保存成功");
          // //更新浏览器存储的用户信息
          // this.getUser().then(res => {
          //   res.token = JSON.parse(localStorage.getItem("user")).token
          //   localStorage.setItem("user", JSON.stringify(user))
          // })
          //触发父级更新User方法
          this.emit("refreshUser")

        } else {
          this.$message.error("保存失败");
        }
      });
    },

2)Manage.vue:定义refreshUser事件的方法

        <el-main>
          <!-- 当前页面的子路由在当前位置显示 -->
          <router-view @refreshUser="getUser"/>
        </el-main>   
    getUser(){
        let username = JSON.parse(localStorage.getItem("user"))?JSON.parse(localStorage.getItem("user")).username:""
        this.request.get("/user/username/" + username).then(res=>{
          //重新赋值
          this.user = res.data 
        })
      },
    created(){
      //从后台取最新数据
      this.getUser

    },
      
    data() {
        return {
            collapseBtnClass: 'el-icon-s-fold',
            isCollapse: false,
            sideWidth: 200,
            logoTextShow: true,
            user: {}
        };
     },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值