一、项目结构图
二、pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.atzhongruan</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <!--引入druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
三、controller层
package com.atzhongruan.demo.controller; import com.atzhongruan.demo.mapper.UploadfilehistoryMapper; import com.atzhongruan.pojo.UploadFileResponse; import com.atzhongruan.demo.service.FileStorageService; import com.atzhongruan.pojo.Uploadfilehistory; import com.atzhongruan.utils.DateUtil; import com.atzhongruan.utils.UUIDUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @RestController public class FileController { private static final Logger logger = LoggerFactory.getLogger(FileController.class); @Autowired private FileStorageService fileStorageService; @Autowired private UploadfilehistoryMapper uploadfilehistoryMapper; /** * 上传文件 * * @param file * @return */ @PostMapping("/uploadFile") public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file) { String fileName = fileStorageService.storeFile(file); String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath() .path("/downloadFile/") .path(fileName) .toUriString(); //插入数据 Uploadfilehistory uploadfilehistory = new Uploadfilehistory(); uploadfilehistory.setId(UUIDUtil.getUUID2()); uploadfilehistory.setFileurl("D:/Users/callicoder/uploads/"+fileName); uploadfilehistory.setFilename(fileName); uploadfilehistory.setFiletype(file.getContentType()); uploadfilehistory.setUploadtime(DateUtil.formatDateTime(new Date())); uploadfilehistoryMapper.insert(uploadfilehistory); return new UploadFileResponse(fileName, fileDownloadUri, file.getContentType(), file.getSize()); } /** * 上传多个文件 * @param files * @return */ @PostMapping("/uploadMultipleFiles") public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) { return Arrays.asList(files) .stream() .map(file -> uploadFile(file)) .collect(Collectors.toList()); } /** * 下载文件 * * @param fileName * @param request * @return */ @GetMapping("/downloadFile/{fileName:.+}") public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) { // Load file as Resource Resource resource = fileStorageService.loadFileAsResource(fileName); // Try to determine file's content type String contentType = null; try { contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath()); } catch (IOException ex) { logger.info("Could not determine file type."); } // Fallback to the default content type if type could not be determined if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } }
四、FileStorageService层
package com.atzhongruan.demo.service; import com.atzhongruan.Exception.FileStorageException; import com.atzhongruan.Exception.MyFileNotFoundException; import com.atzhongruan.propety.FileStorageProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; import java.util.Date; @Service public class FileStorageService { private final Path fileStorageLocation; @Autowired public FileStorageService(FileStorageProperties fileStorageProperties) { this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir()) .toAbsolutePath().normalize(); try { Files.createDirectories(this.fileStorageLocation); } catch (Exception ex) { throw new FileStorageException("Could not create the directory where the uploaded files will be stored.", ex); } } /** * 上传文件 * @param file * @return */ public String storeFile(MultipartFile file) { // Normalize file name //获取上传文件名 String uploadName = file.getOriginalFilename(); //获取后缀名 String sname = uploadName.substring(uploadName.lastIndexOf(".")); //时间格式化格式 SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyyMMddHHmmssSSS"); //获取当前时间并作为时间戳 String timeStamp=simpleDateFormat.format(new Date()); //拼接新的文件名 String fileName =timeStamp+sname; try { // Check if the file's name contains invalid characters if(fileName.contains("..")) { throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName); } // Copy file to the target location (Replacing existing file with the same name) Path targetLocation = this.fileStorageLocation.resolve(fileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); return fileName; } catch (IOException ex) { throw new FileStorageException("Could not store file " + fileName + ". Please try again!", ex); } } /** * 下载文件 * @param fileName * @return */ public Resource loadFileAsResource(String fileName) { try { Path filePath = this.fileStorageLocation.resolve(fileName).normalize(); Resource resource = new UrlResource(filePath.toUri()); if(resource.exists()) { return resource; } else { throw new MyFileNotFoundException("File not found " + fileName); } } catch (MalformedURLException ex) { throw new MyFileNotFoundException("File not found " + fileName, ex); } } }
五、UploadfilehistoryMapper层
package com.atzhongruan.demo.mapper; import com.atzhongruan.pojo.Uploadfilehistory; import org.springframework.stereotype.Component; @Component public interface UploadfilehistoryMapper { int deleteByPrimaryKey(String id); int insert(Uploadfilehistory record); int insertSelective(Uploadfilehistory record); Uploadfilehistory selectByPrimaryKey(String id); int updateByPrimaryKeySelective(Uploadfilehistory record); int updateByPrimaryKey(Uploadfilehistory record); }
六、mapper的xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.atzhongruan.demo.mapper.UploadfilehistoryMapper" > <resultMap id="BaseResultMap" type="com.atzhongruan.pojo.Uploadfilehistory" > <id column="id" property="id" jdbcType="VARCHAR" /> <result column="fileName" property="filename" jdbcType="VARCHAR" /> <result column="fileUrl" property="fileurl" jdbcType="VARCHAR" /> <result column="fileType" property="filetype" jdbcType="VARCHAR" /> <result column="uploadTime" property="uploadtime" jdbcType="VARCHAR" /> </resultMap> <sql id="Example_Where_Clause" > <where > <foreach collection="oredCriteria" item="criteria" separator="or" > <if test="criteria.valid" > <trim prefix="(" suffix=")" prefixOverrides="and" > <foreach collection="criteria.criteria" item="criterion" > <choose > <when test="criterion.noValue" > and ${criterion.condition} </when> <when test="criterion.singleValue" > and ${criterion.condition} #{criterion.value} </when> <when test="criterion.betweenValue" > and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} </when> <when test="criterion.listValue" > and ${criterion.condition} <foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," > #{listItem} </foreach> </when> </choose> </foreach> </trim> </if> </foreach> </where> </sql> <sql id="Update_By_Example_Where_Clause" > <where > <foreach collection="example.oredCriteria" item="criteria" separator="or" > <if test="criteria.valid" > <trim prefix="(" suffix=")" prefixOverrides="and" > <foreach collection="criteria.criteria" item="criterion" > <choose > <when test="criterion.noValue" > and ${criterion.condition} </when> <when test="criterion.singleValue" > and ${criterion.condition} #{criterion.value} </when> <when test="criterion.betweenValue" > and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} </when> <when test="criterion.listValue" > and ${criterion.condition} <foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," > #{listItem} </foreach> </when> </choose> </foreach> </trim> </if> </foreach> </where> </sql> <sql id="Base_Column_List" > id, fileName, fileUrl, fileType, uploadTime </sql> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" > select <include refid="Base_Column_List" /> from uploadFileHistory where id = #{id,jdbcType=VARCHAR} </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.String" > delete from uploadFileHistory where id = #{id,jdbcType=VARCHAR} </delete> <insert id="insert" parameterType="com.atzhongruan.pojo.Uploadfilehistory" > insert into uploadFileHistory (id, fileName, fileUrl, fileType, uploadTime) values (#{id,jdbcType=VARCHAR}, #{filename,jdbcType=VARCHAR}, #{fileurl,jdbcType=VARCHAR}, #{filetype,jdbcType=VARCHAR}, #{uploadtime,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.atzhongruan.pojo.Uploadfilehistory" > insert into uploadFileHistory <trim prefix="(" suffix=")" suffixOverrides="," > <if test="id != null" > id, </if> <if test="filename != null" > fileName, </if> <if test="fileurl != null" > fileUrl, </if> <if test="filetype != null" > fileType, </if> <if test="uploadtime != null" > uploadTime, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="id != null" > #{id,jdbcType=VARCHAR}, </if> <if test="filename != null" > #{filename,jdbcType=VARCHAR}, </if> <if test="fileurl != null" > #{fileurl,jdbcType=VARCHAR}, </if> <if test="filetype != null" > #{filetype,jdbcType=VARCHAR}, </if> <if test="uploadtime != null" > #{uploadtime,jdbcType=VARCHAR}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.atzhongruan.pojo.Uploadfilehistory" > update uploadFileHistory <set > <if test="filename != null" > fileName = #{filename,jdbcType=VARCHAR}, </if> <if test="fileurl != null" > fileUrl = #{fileurl,jdbcType=VARCHAR}, </if> <if test="filetype != null" > fileType = #{filetype,jdbcType=VARCHAR}, </if> <if test="uploadtime != null" > uploadTime = #{uploadtime,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=VARCHAR} </update> <update id="updateByPrimaryKey" parameterType="com.atzhongruan.pojo.Uploadfilehistory" > update uploadFileHistory set fileName = #{filename,jdbcType=VARCHAR}, fileUrl = #{fileurl,jdbcType=VARCHAR}, fileType = #{filetype,jdbcType=VARCHAR}, uploadTime = #{uploadtime,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} </update> </mapper>
七、异常
1-2
package com.atzhongruan.Exception; public class FileStorageException extends RuntimeException { public FileStorageException(String message) { super(message); } public FileStorageException(String message, Throwable cause) { super(message, cause); } }
1-2
package com.atzhongruan.Exception; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.NOT_FOUND) public class MyFileNotFoundException extends RuntimeException { public MyFileNotFoundException(String message) { super(message); } public MyFileNotFoundException(String message, Throwable cause) { super(message, cause); } }
八、pojo类
8-1
package com.atzhongruan.pojo; import lombok.*; @Setter @Getter @ToString @NoArgsConstructor @AllArgsConstructor public class Uploadfilehistory { private String id; private String filename; private String fileurl; private String filetype; private String uploadtime; }
8-2
package com.atzhongruan.pojo; import lombok.*; @Setter @Getter @ToString @NoArgsConstructor @AllArgsConstructor public class UploadFileResponse { private String fileName; private String fileDownloadUri; private String fileType; private long size; }
九、属性文件
package com.atzhongruan.propety; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "file") public class FileStorageProperties { private String uploadDir; public String getUploadDir() { return uploadDir; } public void setUploadDir(String uploadDir) { this.uploadDir = uploadDir; } }
十、工具类
10-1
package com.atzhongruan.utils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateUtils; import java.util.Date; /** * @Author jose * date 2019 */ public class DateUtil extends DateUtils { private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM" }; /** * 得到当前日期字符串 格式(yyyy-MM-dd) */ public static String getDate() { return getDate("yyyy-MM-dd HH:mm:ss"); } /** * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" */ public static String getDate(String pattern) { return DateFormatUtils.format(new Date(), pattern); } /** * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" */ public static String formatDate(Date date, Object... pattern) { if (date == null) { return null; } String formatDate = null; if (pattern != null && pattern.length > 0) { formatDate = DateFormatUtils.format(date, pattern[0].toString()); } else { formatDate = DateFormatUtils.format(date, "yyyy-MM-dd"); } return formatDate; } /** * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss) */ public static String formatDateTime(Date date) { return formatDate(date, "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前时间字符串 格式(HH:mm:ss) */ public static String getTime() { return formatDate(new Date(), "HH:mm:ss"); } /** * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss) */ public static String getDateTime() { return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前年份字符串 格式(yyyy) */ public static String getYear() { return formatDate(new Date(), "yyyy"); } /** * 得到当前月份字符串 格式(MM) */ public static String getMonth() { return formatDate(new Date(), "MM"); } /** * 得到当天字符串 格式(dd) */ public static String getDay() { return formatDate(new Date(), "dd"); } /** * 得到当前星期字符串 格式(E)星期几 */ public static String getWeek() { return formatDate(new Date(), "E"); } }
10-2
package com.atzhongruan.utils; import java.util.UUID; /** * @Author jose * date 2019 */ public class UUIDUtil { /** * 带-的UUID * * @return 36位的字符串 */ public static String getUUID() { return UUID.randomUUID().toString(); } /** * 去掉-的UUID * * @return 32位的字符串 */ public static String getUUID2() { return UUID.randomUUID().toString().replace("-", ""); } }
十一、application.properties
## MULTIPART (MultipartProperties) # Enable multipart uploads spring.servlet.multipart.enabled=true # Threshold after which files are written to disk. spring.servlet.multipart.file-size-threshold=2KB # Max file size. spring.servlet.multipart.max-file-size=200MB # Max Request Size spring.servlet.multipart.max-request-size=215MB ## File Storage Properties # 文件存放的路径D:/Users/callicoder/uploads/20190609111149160.txt file.upload-dir=/Users/callicoder/uploads/ server.port=8090
源码下载地址:https://github.com/callicoder/spring-boot-file-upload-download-rest-api-example