據說微信搜索《Java魚仔》會變動強哦!java
本文收錄於JavaStarter ,裏面有我完整的Java系列文章,學習或面試均可以看看哦mysql
(一)概述
文件上傳下載一直都是一個系統最經常使用也是最基本的功能點,恰好最近公司的項目上有用到這個功能,因而本身就用SpringBoot也寫了一個簡化的版本,已實現文件的上傳和下載功能。git
(二)建立項目
首先建立一個SpringBoot的項目,接着引入相關的依賴,由於涉及到數據庫的操做,因此依賴會比較多一些。github
2.1 依賴引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
2.2 接口通用返回類編寫
編寫一個接口的通用返回體,這個在以前的博客中我專門寫過,如今就直接拿來用了:web
public enum ResponseCode { // 系統模塊 SUCCESS(0, "操做成功"), ERROR(1, "操做失敗"), SERVER_ERROR(500, "服務器異常"), // 通用模塊 1xxxx ILLEGAL_ARGUMENT(10000, "參數不合法"), REPETITIVE_OPERATION(10001, "請勿重複操做"), ACCESS_LIMIT(10002, "請求太頻繁, 請稍後再試"), MAIL_SEND_SUCCESS(10003, "郵件發送成功"), // 用戶模塊 2xxxx NEED_LOGIN(20001, "登陸失效"), USERNAME_OR_PASSWORD_EMPTY(20002, "用戶名或密碼不能爲空"), USERNAME_OR_PASSWORD_WRONG(20003, "用戶名或密碼錯誤"), USER_NOT_EXISTS(20004, "用戶不存在"), WRONG_PASSWORD(20005, "密碼錯誤"), // 文件模塊 3xxxx FILE_EMPTY(30001,"文件不能空"), FILE_NAME_EMPTY(30002,"文件名稱不能爲空"), FILE_MAX_SIZE(30003,"文件大小超出"), ; ResponseCode(Integer code, String msg) { this.code = code; this.msg = msg; } private Integer code; private String msg; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
返回體:面試
@Data @AllArgsConstructor @NoArgsConstructor public class Result { private int code; private String message; private Object data; }
2.3 配置一下解決跨域問題的配置類
在SpringBoot中有多種解決跨域的方法,這裏選擇其中一種spring
public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .maxAge(3600) .allowCredentials(true); } }
到這裏爲止,基本的項目配置就算結束了,接下來就是功能的實現了。sql
(三)實現文件上傳下載
3.1 建立表
首先建立一張表來記錄文件的路徑、名稱、後綴等信息:數據庫
CREATE TABLE `file` ( `id` int(11) NOT NULL AUTO_INCREMENT, `filePath` varchar(255) DEFAULT NULL, `fileName` varchar(255) DEFAULT NULL, `fileSuffix` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
3.2 編寫實體類
寫一個文件對象,和數據庫中的字段相對應:apache
@Data @AllArgsConstructor @NoArgsConstructor @Getter @Setter @EqualsAndHashCode public class Files implements Serializable { private static final long serialVersionUID=1L; /** * 文件存儲路徑 */ private String filePath; /** * 文件名稱 */ private String fileName; /** * 文件後綴名 */ private String fileSuffix; }
3.3 配置application.properties
在配置文件中將服務端口,數據庫鏈接方式以及文件的保存路徑配置一下:
server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/test7?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver mybatis.mapper-locations=classpath:mapper/*.xml file.save-path=E:/temp/files
3.4 編寫Controller
新建一個類叫FileController,用來寫接口,文件上傳下載接口的代碼已經給了註釋,Spring中提供了一個MultipartFile類,用來接收前臺傳過來的文件,這裏直接使用便可。
@RestController @RequestMapping("/api") public class FileController { @Autowired private FileService fileService; //文件上傳接口 @RequestMapping(value = "/upload",method = RequestMethod.POST) public Result upLoadFiles(MultipartFile multipartFile){ //若是文件爲空,直接返回錯誤信息 if (multipartFile.isEmpty()){ return new Result(ResponseCode.FILE_EMPTY.getCode(),ResponseCode.FILE_EMPTY.getMsg(),null); } //不然調用service上傳文件 return fileService.upLoadFiles(multipartFile); } @RequestMapping(value = "/download/{id}",method = RequestMethod.GET) public void downloadFiles(@PathVariable("id") String id, HttpServletRequest request, HttpServletResponse response){ OutputStream outputStream=null; InputStream inputStream=null; //先根據id查到文件信息 Files files = fileService.getFileById(id); String fileName = files.getFileName(); //經過文件信息將文件轉化爲inputStream inputStream=fileService.getFileInputStream(files); //下載文件須要設置的header response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); // 獲取輸出流 try { outputStream = response.getOutputStream(); } catch (IOException e) { e.printStackTrace(); }finally { //不要忘記關閉流 try { if (inputStream!=null){ inputStream.close(); } if (outputStream!=null){ outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
全部的業務都寫在service中,所以須要有fileService接口以及fileServiceImpl實現類:
public interface FileService { /** * 文件上傳接口 * @param file * @return */ Result upLoadFiles(MultipartFile file); /** * 根據id獲取文件 * @param id * @return */ Files getFileById(String id); /** * 根據id獲取數據流 * @param files * @return */ InputStream getFileInputStream(Files files); }
fileServiceImpl實現類:
@Service public class FileServiceImpl implements FileService { @Value("${file.save-path}") private String savePath; @Autowired private FileMapper fileMapper; @Override public Result upLoadFiles(MultipartFile file) { //設置支持最大上傳的文件,這裏是1024*1024*2=2M long MAX_SIZE=2097152L; //獲取要上傳文件的名稱 String fileName=file.getOriginalFilename(); //若是名稱爲空,返回一個文件名爲空的錯誤 if (StringUtils.isEmpty(fileName)){ return new Result(ResponseCode.FILE_NAME_EMPTY.getCode(),ResponseCode.FILE_NAME_EMPTY.getMsg(),null); } //若是文件超過最大值,返回超出可上傳最大值的錯誤 if (file.getSize()>MAX_SIZE){ return new Result(ResponseCode.FILE_MAX_SIZE.getCode(),ResponseCode.FILE_MAX_SIZE.getMsg(),null); } //獲取到後綴名 String suffixName = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : null; //文件的保存從新按照時間戳命名 String newName = System.currentTimeMillis() + suffixName; File newFile=new File(savePath,newName); if (!newFile.getParentFile().exists()){ newFile.getParentFile().mkdirs(); } try { //文件寫入 file.transferTo(newFile); } catch (IOException e) { e.printStackTrace(); } //將這些文件的信息寫入到數據庫中 Files files=new Files(newFile.getPath(),fileName,suffixName); fileMapper.insertFile(files); return new Result(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),"數據上傳成功"); } //根據id獲取文件信息 @Override public Files getFileById(String id) { Files files = fileMapper.selectFileById(id); return files; } //將文件轉化爲InputStream @Override public InputStream getFileInputStream(Files files) { File file=new File(files.getFilePath()); try { return new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } }
3.5 對數據庫的操做
須要將數據寫入到數據庫中,這裏用到的是mybatis,新建一個FileMapper接口:
@Mapper @Repository public interface FileMapper { /** * 將數據信息插入到數據庫 * @param files */ void insertFile(Files files); /** * 根據id獲取文件 * @param id * @return */ Files selectFileById(String id); }
編寫對應的xml文件
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.javayz.fileuploadanddownload.mapper.FileMapper"> <insert id="insertFile" parameterType="com.javayz.fileuploadanddownload.entity.Files"> insert into file(filepath,filename,filesuffix) values(#{filePath},#{fileName},#{fileSuffix}); </insert> <select id="selectFileById" parameterType="string" resultType="com.javayz.fileuploadanddownload.entity.Files"> select * from file where id=#{id}; </select> </mapper>
代碼已上傳至github,歡迎自取:github
(四)測試
將項目運行起來,首先測試文件上傳,經過postman直接上傳一個文件
點擊send後獲得操做成功的返回值,咱們能夠在本身設置的路徑下看到這個文件,同時在數據庫中也存在該文件的信息:
接下來測試文件下載,由於是get請求,直接在瀏覽器中訪問: http://localhost:8080/api/download/4 便可調用下載。