首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >SpringBoot入门建站全系列(九)文件上传功能与下载方式

SpringBoot入门建站全系列(九)文件上传功能与下载方式

作者头像
品茗IT
发布2019-09-12 10:33:02
发布2019-09-12 10:33:02
7980
举报
文章被收录于专栏:品茗IT品茗IT

SpringBoot入门建站全系列(九)文件上传功能与下载方式

Spring对文件上传做了简单的封装,就是用MultipartFile这个对象去接收文件,当然有很多种写法,下面会一一介绍。

文件的下载很简单,给一个链接就行,而这个链接怎么生成,也有很多方式,下面也会讲解下常用的方式。

**如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以<a

href="https://jq.qq.com/?_wv=1027&k=52sgH1J"

target="_blank">

加入我们的java学习圈,点击即可加入

</a>

,共同学习,节约学习时间,减少很多在学习中遇到的难题。**

一、配置

本文假设你已经引入spring-boot-starter-web。已经是个SpringBoot项目了,如果不会搭建,可以打开这篇文章看一看《SpringBoot入门建站全系列(一)项目建立》。因为文件上传和下载不需要引入额外的jar包了。但是需要做如下配置:

application.properties 中需要添加下面的配置:

代码语言:javascript
复制
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=50MB

这里,

  • spring.servlet.multipart.max-file-size是对单个文件大小的限制。
  • spring.servlet.multipart.max-request-size是对单次请求的大小进行限制

至此,已经可以正常的进行上传下载了,就剩下写代码了。

二、文件上传的几种方式

2.1 单个文件上传

在Controller的RequestMapping注解的方法参数中,直接将MultipartFile作为参数传递进来。

代码语言:javascript
复制
package com.cff.springbootwork.web.file;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.cff.springbootwork.dto.ResultModel;
import com.cff.springbootwork.service.UploadService;

@RestController
@RequestMapping("/file")
public class FileRest {
	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Value("${upload.static.url}")
	private String uploadStaticUrl;

	@Autowired
	UploadService uploadService;

	@RequestMapping("/upload")
	public ResultModel upload(@RequestParam("files") MultipartFile file) {
		try {
			if (file.isEmpty()) {
				return ResultModel.error("文件不能为空!");
			}
			String fileName = uploadService.saveUploadFile(file);
			return ResultModel.ok(uploadStaticUrl + fileName);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}
}

测试的时候,使用postman可以这样传参:

在这里插入图片描述

2.2 多个文件上传

在Controller的RequestMapping注解的方法参数中,直接将MultipartFile作为list传递进来。在FileRest中增加uploadList方法。

代码语言:javascript
复制
package com.cff.springbootwork.web.file;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.cff.springbootwork.dto.ResultModel;
import com.cff.springbootwork.service.UploadService;

@RestController
@RequestMapping("/file")
public class FileRest {
	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Value("${upload.static.url}")
	private String uploadStaticUrl;

	@Autowired
	UploadService uploadService;

	@RequestMapping("/upload")
	public ResultModel upload(@RequestParam("files") MultipartFile file) {
		try {
			if (file.isEmpty()) {
				return ResultModel.error("文件不能为空!");
			}
			String fileName = uploadService.saveUploadFile(file);
			return ResultModel.ok(uploadStaticUrl + fileName);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}

	@RequestMapping("/uploadList")
	public ResultModel uploadList(@RequestParam("files") List<MultipartFile> fileList) {
		try {
			List<String> list = new ArrayList<>();
			for (MultipartFile file : fileList) {
				String fileName = uploadService.saveUploadFile(file);
				list.add(uploadStaticUrl + fileName);
			}
			return ResultModel.ok(list);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}
}

测试的时候,使用postman可以这样传参:

在这里插入图片描述

2.3 从HttpServletRequest中取文件

新建uploadByRequest方法,将HttpServletRequest作为参数,Spring自动传入。

Spring对Request做了一层封装,如果有文件,它就是MultipartHttpServletRequest。

然后我们可以从MultipartHttpServletRequest获取到MultipartFile。后面的处理方式一样了。

代码语言:javascript
复制
package com.cff.springbootwork.web.file;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.cff.springbootwork.dto.ResultModel;
import com.cff.springbootwork.service.UploadService;

@RestController
@RequestMapping("/file")
public class FileRest {
	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Value("${upload.static.url}")
	private String uploadStaticUrl;

	@Autowired
	UploadService uploadService;

	@RequestMapping("/upload")
	public ResultModel upload(@RequestParam("files") MultipartFile file) {
		try {
			if (file.isEmpty()) {
				return ResultModel.error("文件不能为空!");
			}
			String fileName = uploadService.saveUploadFile(file);
			return ResultModel.ok(uploadStaticUrl + fileName);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}

	@RequestMapping("/uploadList")
	public ResultModel uploadList(@RequestParam("files") List<MultipartFile> fileList) {
		try {
			List<String> list = new ArrayList<>();
			for (MultipartFile file : fileList) {
				String fileName = uploadService.saveUploadFile(file);
				list.add(uploadStaticUrl + fileName);
			}
			return ResultModel.ok(list);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}

	@RequestMapping("/uploadByRequest")
	public ResultModel uploadByRequest(HttpServletRequest request) {
		try {
			Map<String, MultipartFile> files = new HashMap<>();

			if (request instanceof MultipartHttpServletRequest) {
				MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
				MultiValueMap<String, MultipartFile> multiValueMap = req.getMultiFileMap();
				if (multiValueMap != null && !multiValueMap.isEmpty()) {
					for (String key : multiValueMap.keySet()) {
						files.put(key, multiValueMap.getFirst(key));
					}
				}
			}
			if (files.isEmpty())
				return ResultModel.error("文件木有?");

			List<String> list = new ArrayList<>();
			for (MultipartFile file : files.values()) {
				String fileName = uploadService.saveUploadFile(file);
				list.add(uploadStaticUrl + fileName);
			}
			return ResultModel.ok(list);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("文件上传失败!", e);
			return ResultModel.error("文件上传失败!");
		}
	}
}

测试的时候,传参方式使用上面两种都可以了。

三、文件下载方式

文件上传成功后,我们同时会提供下载功能。下载功能很简单,有以下几种方式:

3.1 Spring配置映射

新建一个WebStaticConfig配置类,实现WebMvcConfigurer接口即可:

代码语言:javascript
复制
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebStaticConfig implements WebMvcConfigurer {
	@Value("${upload.static.local}")
	private String uploadStaticLocal;

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/static/**").addResourceLocations("file:" + uploadStaticLocal);
	}

	public String getUploadStaticLocal() {
		return uploadStaticLocal;
	}

	public void setUploadStaticLocal(String uploadStaticLocal) {
		this.uploadStaticLocal = uploadStaticLocal;
	}

}

这句话将当前服务器(比如是http://127.0.0.1:8080 )的/static路径(http://127.0.0.1:8080/static/ )下的资源,映射到uploadStaticLocal指定的本地路径下的文件。

然后我们就可以直接访问文件了。

3.2 代理(nginx)映射

代理首选nginx了。高性能快捷的代理转发工具。

比如要将http://127.0.0.1:8081/static/ 下的资源,映射到/static/指定的本地路径下的文件,可以这样配置:

代码语言:javascript
复制
server {
    listen       8081;
    server_name  localhost;

	location /static {
		alias /static/;
		index index.html;
	}
}

这里为什么用8081而不是上面的8080了呢?因为上面的8080端口已经被SpringBoot应用占用了。nginx要在另一个端口监听了,如果非要将SpringBoot应用和静态资源在一个端口,可以对SpringBoot应用也做代理,例如:

代码语言:javascript
复制
server {
    listen       8081;
    server_name  localhost;

    location ^~ /api/ {
		proxy_pass   http://127.0.0.1:8080/;
    }
	
	location /static {
		alias /static/;
		index index.html;
	}
}
3.3 ResponseEntity读取文件并返回

比如我们在FileRest的Controller中建立个downloadFile方法,传入文件名,将文件读取为byte,包装成ResponseEntity返回。

代码语言:javascript
复制
	@RequestMapping(value = "/downloadFile", method = { RequestMethod.GET })
	public ResponseEntity<byte[]> downloadFile(@RequestParam("fileName") String fileName) {
		try {
			File file = new File(fileName);
			byte[] body = null;
			InputStream is = new FileInputStream(file);
			body = new byte[is.available()];
			is.read(body);
			is.close();
			HttpHeaders headers = new HttpHeaders();
			headers.add("Content-Disposition", "attchement;filename=" + file.getName());
			HttpStatus statusCode = HttpStatus.OK;
			ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);
			return entity;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

四、过程中用到的实体及Service

UploadService:

代码语言:javascript
复制
package com.cff.springbootwork.service;

import java.io.File;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class UploadService {
	@Value("${upload.static.local}")
	private String uploadStaticLocal;

	public String saveUploadFile(MultipartFile file) throws Exception {
		String fileName = file.getOriginalFilename();

		String localPath = uploadStaticLocal + fileName;
		file.transferTo(new File(localPath));

		return fileName;
	}

}

ResultCode:

代码语言:javascript
复制
package com.cff.springbootwork.dto;

/**
 * 响应码及其描述 Created by txl on 15/7/9.
 */
public enum ResultCode {

	/**
	 * 通用
	 */
	CODE_00000("00000", "操作成功"), CODE_00001("00001", "请求失败"), CODE_00002("00002", "错误的请求方法"), CODE_00003("00003", "非法的参数字段"), CODE_00004("00004", "异常抛出"), CODE_00005("00005", "权限不足"), CODE_00006("00006", "分页limit参数错误"), CODE_00007("00007", "分页offset参数错误"), CODE_00009("00009", "请求过于频繁"), CODE_00010("00010", "数据已存在"), CODE_00011("00011", "数据不存在"), CODE_00012("00012", "参数缺失"), CODE_00013("00013", "系统维护中"), CODE_00014("00014", "token缺失"), CODE_00015("00015", "token失效"), CODE_00016("00016", "签名错误"),

	CODE_10000("10000", "操作部分成功"),
	/**
	 * 系统
	 */
	CODE_30000("30000", "系统ID错误"),

	/**
	 * 授权
	 */
	CODE_40001("40001", "用户未找到"), CODE_40002("40002", "该用户状态异常"), CODE_40003("40003", "该用户已被删除"), CODE_40004("40004", "授权异常"),

	CODE_99999("99999", "签名无效");

	private String code;
	private String desc;

	ResultCode(String code, String desc) {
		this.code = code;
		this.desc = desc;
	}

	public String getCode() {
		return code;
	}

	public String getDesc() {
		return desc;
	}

	/**
	 * 根据code匹配枚举
	 * 
	 * @param code
	 * @return
	 */
	public static ResultCode getResultCodeByCode(String code) {
		for (ResultCode resultCode : ResultCode.values()) {
			if (code.equals(resultCode.getCode())) {
				return resultCode;
			}
		}
		return null;
	}

	public static ResultCode getResultCodeByDesc(String desc) {
		for (ResultCode resultCode : ResultCode.values()) {
			if (desc.equals(resultCode.getDesc())) {
				return resultCode;
			}
		}
		return null;
	}
}

ResultModel :

代码语言:javascript
复制
package com.cff.springbootwork.dto;

/**
 */
public class ResultModel {

	private String errorCode;
	private String message;
	private Object remark;
	private Object data;

	public ResultModel(String errorCode, String message) {
		this.errorCode = errorCode;
		this.message = message;
	}

	public ResultModel() {
	}

	public ResultModel(String errorCode, String message, Object data) {
		this.errorCode = errorCode;
		this.message = message;
		this.data = data;
	}

	public ResultModel(ResultCode resultCodeEnum, Object data) {
		this.errorCode = resultCodeEnum.getCode();
		this.message = resultCodeEnum.getDesc();
		this.data = data;
	}

	public ResultModel(ResultCode resultCodeEnum, Object data, Object remark) {
		this.errorCode = resultCodeEnum.getCode();
		this.message = resultCodeEnum.getDesc();
		this.data = data;
		this.remark = remark;
	}

	public ResultModel(ResultCode resultCodeEnum) {
		this.errorCode = resultCodeEnum.getCode();
		this.message = resultCodeEnum.getDesc();
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public static ResultModel ok() {
		return new ResultModel(ResultCode.CODE_00000);
	}

	public static ResultModel ok(Object data) {
		return new ResultModel(ResultCode.CODE_00000, data);
	}

	public static ResultModel unAuth() {
		return new ResultModel(ResultCode.CODE_00002);
	}

	public static ResultModel unAuth(Object data) {
		return new ResultModel(ResultCode.CODE_00002, data);
	}

	public static ResultModel error(String message) {
		return new ResultModel(ResultCode.CODE_00001.getCode(), message);
	}

	public Object getRemark() {
		return remark;
	}

	public void setRemark(Object remark) {
		this.remark = remark;
	}

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/06/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot入门建站全系列(九)文件上传功能与下载方式
    • 一、配置
    • 二、文件上传的几种方式
      • 2.1 单个文件上传
      • 2.2 多个文件上传
      • 2.3 从HttpServletRequest中取文件
    • 三、文件下载方式
      • 3.1 Spring配置映射
      • 3.2 代理(nginx)映射
      • 3.3 ResponseEntity读取文件并返回
    • 四、过程中用到的实体及Service
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档