前后端交互—文件上传功能实现

  • Post author:
  • Post category:其他


后台部分

①代码实现

package main.com.jt.firstsb.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import main.com.jt.firstsb.config.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.stream.Stream;

@RestController
@RequestMapping("/files")
public class FileController {

    @Value("${server.port}")
    private String port;

    private static final String ip="http://localhost";

    /*
    * 上传接口
    * */
    @PostMapping("/upload")
    public Result<?> upload(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename(); //获取源文件的名称
        //定义文件的唯一标识(前缀)
        String flag = IdUtil.fastSimpleUUID();
        String rootFilePath = System.getProperty("user.dir") + "/first-sb/src/main/resources/files/"+flag+"_"+originalFilename; //获取上传的路径
        FileUtil.writeBytes(file.getBytes(),rootFilePath); //把文件写入到上传的路径
        return Result.success(ip+":"+port+"/files/"+flag); //返回结果 url
    }


    /*
    * 下载接口
    * */
    @GetMapping("/{flag}")
    public void getFiles(HttpServletResponse response, @PathVariable String flag){
        OutputStream os;
        String basePath = System.getProperty("user.dir") + "/first-sb/src/main/resources/files/"; //定义文件下载的根路径
        List<String> fileNames = FileUtil.listFileNames(basePath); //获取所有的文件名称
        String fileName = fileNames.stream().filter(name -> name.contains(flag)).findAny().orElse("");
        try{
            if(StrUtil.isNotEmpty(fileName)){
                response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
                response.setContentType("application/octet-stream");
                byte[] bytes=FileUtil.readBytes(basePath+fileName); //通过文件的路径读取文件字节流
                os=response.getOutputStream(); //通过输出流返回文件
                os.write(bytes);
                os.flush();
                os.close();
            }
        } catch (Exception e){
            System.out.println("文件下载失败");
        }

    }
}

②代码细节剖析:

@Value

该注解的作用是将我们配置文件的属性读出来,有

@Value(“${}”)



@Value(“#{}”)

两种方式。

  • @Value(“#{}”) 表示SpEl

    表达式

    通常用来获取bean的属性,或者调用bean的某个方法。当然还有可以表示常量

  • 用 @Value(“${xxxx}”)注解从配置文件读取值的用法

==>@Value(“${server.port}”) 可以读出配置文件中服务器的端口号

上传接口

1.接收文件需要使用MultipartFile类

2.文件的getOriginalName方法可以获取文件本身的名字

String originalFilename = file.getOriginalFilename(); //获取源文件的名称

3.IdUtil工具类由插件Hutool提供,可以快速获取uuid==>防止上传的文件名重复

String flag = IdUtil.fastSimpleUUID();

4.System.getProperty(“user.dir”) 获取的是启动项目的容器位置,用IDEA是项目的根目录,部署在tomcat上是tomcat的启动路径,即tomcat/bin的位置

String rootFilePath = System.getProperty("user.dir") + "/first-sb/src/main/resources/files/"+flag+"_"+originalFilename; //获取上传的路径

5.FileUtil由插件Hutool提供支持,writeBytes可以把文件写入到上传的路径

FileUtil.writeBytes(file.getBytes(),rootFilePath); //把文件写入到上传的路径

6.返回上传成功后文件所在的url,只要用户点击url,配合下载接口就可以下载文件

return Result.success(ip+":"+port+"/files/"+flag); //返回结果 url

下载接口

1. 定义文件下载的根路径

String basePath = System.getProperty("user.dir") + "/first-sb/src/main/resources/files/"; //定义文件上传的根路径

2.根据根路径找到所有的文件名

List<String> fileNames = FileUtil.listFileNames(basePath); //获取所有的文件名称

3.找到包含flag的文件名

因为flag是唯一标识,可以通过flag来确定唯一一个文件

findAny():findAny() 方法是获取流中任意一个,存在随机性,其实里面也是获取元素中的第一个。

orElse():如果不存在,则返回为空,可以指定默认值

String fileName =
 fileNames.stream().filter(name->name.contains(flag)).findAny().orElse("");

4.利用Hutool提供的工具类StrUtil的工具方法isNotEmpty()判空

if(StrUtil.isNotEmpty(fileName)){

5.添加响应头

Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。

attachment为以附件方式下载

disposition-parm为默认保存时的文件名

URLEncoder:对URL进行编码,用一种规则替换掉特殊字符

response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));

6.application/octet-stream:遇到content-type为application/octet-stream的文件时,浏览器会直接把它下载下来。

这个类型一般会配合另一个响应头Content-Disposition,该响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者网页的一部分),还是以附件的形式下载并保存到本地。

response.setContentType("application/octet-stream");

7.FileUtil为Hutool提供的工具类,使用工具方法readBytes,通过文件的路径读取文件字节流

byte[] bytes=FileUtil.readBytes(basePath+fileName); //通过文件的路径读取文件字节流

8.通过输出流返回文件

os=response.getOutputStream(); //通过输出流返回文件
os.write(bytes);
os.flush();
os.close();

③跨域处理:


@Configuration
public class CorsConfig {

    // 当前跨域请求最大有效时长,默认为1天
    private static final long MAX_AGE=24*60*60;

    private CorsConfiguration buildConfig(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); //设置访问源地址
        corsConfiguration.addAllowedHeader("*"); //设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); //设置访问源请求方法
        corsConfiguration.setMaxAge(MAX_AGE);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",buildConfig()); //对接口配置跨域设置
        return new CorsFilter(source);
    }

}

前台部分

只需要使用elementUI提供的Upload组件即可

          <el-form-item label="封面">
            <el-upload
                action="http://localhost:9090/files/upload"
                :on-success="filesUploadSuccess"
                v-model="form.cover"
                >
              <el-button size="small" type="primary">点击上传</el-button>
              <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
            </el-upload>

          </el-form-item>

对应的filesUploadSuccess方法:

    filesUploadSuccess(response){
      this.form.cover=response.data
    },

实现效果:

展示封面:

注意对于文件类型,不能使用prop属性,而应该使用模板

加上属性preview-src-list,有大图预览效果

      <el-table-column
        label="封面"
      >
      <template #default="scope">
        <el-image
            style="width: 100px; height: 100px"
            :src="scope.row.cover"
            :preview-src-list="[scope.row.cover]"></el-image>
      </template>
      </el-table-column>

实现效果:

最后:可以通过下列语句清除已经上传成功的文件列表

this.$refs['upload'].clearFiles()



版权声明:本文为Father_Of_Soft原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。