├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── coderman
│ │ └── uploader
│ │ ├── UploaderApplication.java
│ │ ├── config
│ │ ├── MvcConfig.java
│ │ ├── RedisConfig.java
│ │ └── UploadConfig.java
│ │ ├── controller
│ │ ├── TestController.java
│ │ └── UploadController.java
│ │ ├── dto
│ │ ├── FileChunkDTO.java
│ │ └── FileChunkResultDTO.java
│ │ ├── model
│ │ └── FileResource.java
│ │ ├── response
│ │ ├── RestApiResponse.java
│ │ └── error
│ │ │ ├── BaseErrorCode.java
│ │ │ ├── BusinessErrorCode.java
│ │ │ └── BusinessException.java
│ │ └── service
│ │ ├── IUploadService.java
│ │ └── impl
│ │ └── UploadServiceImpl.java
└── resources
│ └── application.yml
└── test
└── java
└── com
└── coderman
└── uploader
├── RedisTest.java
└── TestFile.java
/README.md:
--------------------------------------------------------------------------------
1 | # 大文件分片上传
2 |
3 | SpringBoot+Redis 大文件实现文件分片上传,断点续传,急速秒传。前端使用vue-simpler-uploader实现文件并发上传。
4 |
5 |
6 | 
7 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | org.springframework.boot
9 | spring-boot-starter-parent
10 | 2.2.4.RELEASE
11 |
12 |
13 | com.coderman
14 | springboot_uploader
15 | 1.0
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot-starter-thymeleaf
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-test
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-web
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-data-redis
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/UploaderApplication.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @Author zhangyukang
8 | * @Date 2021/1/16 12:58
9 | * @Version 1.0
10 | **/
11 | @SpringBootApplication
12 | public class UploaderApplication {
13 | public static void main(String[] args) {
14 | SpringApplication.run(UploaderApplication.class,args);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/config/MvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader.config;
2 |
3 | import com.coderman.uploader.response.RestApiResponse;
4 | import com.coderman.uploader.response.error.BusinessException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.web.cors.CorsConfiguration;
12 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
13 | import org.springframework.web.filter.CorsFilter;
14 | import org.springframework.web.servlet.HandlerExceptionResolver;
15 | import org.springframework.web.servlet.ModelAndView;
16 | import org.springframework.web.servlet.NoHandlerFoundException;
17 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
18 |
19 | import javax.servlet.http.HttpServletResponse;
20 | import java.io.IOException;
21 | import java.util.HashMap;
22 | import java.util.List;
23 |
24 | /**
25 | * @Author zhangyukang
26 | * @Date 2021/1/16 14:05
27 | * @Version 1.0
28 | **/
29 | @Configuration
30 | public class MvcConfig implements WebMvcConfigurer {
31 |
32 | private static Logger logger = LoggerFactory.getLogger(MvcConfig.class);
33 |
34 | @Override
35 | public void configureHandlerExceptionResolvers(List resolvers) {
36 | resolvers.add((httpServletRequest, httpServletResponse, o, e) -> {
37 | String requestUrl = httpServletRequest.getRequestURL().toString();
38 | final String defaultErrorMsg = "服务器冒烟了,请联系管理员";
39 | HashMap errorMap = new HashMap<>();
40 | logger.info("请求地址:{}", requestUrl);
41 | if (e instanceof BusinessException) {
42 | BusinessException businessException = (BusinessException) e;
43 | logger.info("业务异常,code:{},errorMsg:{}", businessException.getErrorCode().getErrorCode()
44 | , businessException.getErrorCode().getErrorMsg());
45 | errorMap.put("errorCode", businessException.getErrorCode().getErrorCode());
46 | errorMap.put("errorMsg", businessException.getErrorCode().getErrorMsg());
47 | }else if(e instanceof NoHandlerFoundException){
48 | logger.info("接口不存在,code:{},errorMsg:{}",HttpStatus.NOT_FOUND.value(),e.getMessage());
49 | errorMap.put("errorCode", HttpStatus.NOT_FOUND.value());
50 | errorMap.put("errorMsg", "接口: ["+httpServletRequest.getServletPath()+"] 不存在");
51 | } else {
52 | logger.info("系统异常,code:{},errorMsg:{}", HttpStatus.INTERNAL_SERVER_ERROR.value()
53 | , e.getMessage(),e);
54 | errorMap.put("errorCode", HttpStatus.INTERNAL_SERVER_ERROR.value());
55 | errorMap.put("errorMsg", defaultErrorMsg);
56 | }
57 | responseError(httpServletResponse,RestApiResponse.error(errorMap));
58 | return new ModelAndView();
59 | });
60 | }
61 |
62 | private void responseError(HttpServletResponse httpServletResponse, RestApiResponse> error) {
63 | ObjectMapper objectMapper = new ObjectMapper();
64 | try {
65 | httpServletResponse.setContentType("application/json;charset=utf-8");
66 | String json = objectMapper.writeValueAsString(error);
67 | httpServletResponse.getWriter().println(json);
68 | } catch (IOException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 |
73 | /**
74 | * 配置跨域
75 | * @return
76 | */
77 | private CorsConfiguration corsConfig() {
78 | CorsConfiguration corsConfiguration = new CorsConfiguration();
79 | corsConfiguration.addAllowedOrigin("*");
80 | corsConfiguration.addAllowedHeader("*");
81 | corsConfiguration.addAllowedMethod("*");
82 | corsConfiguration.setAllowCredentials(true);
83 | corsConfiguration.setMaxAge(3600L);
84 | return corsConfiguration;
85 | }
86 | @Bean
87 | public CorsFilter corsFilter() {
88 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
89 | source.registerCorsConfiguration("/**", corsConfig());
90 | return new CorsFilter(source);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.data.redis.connection.RedisConnectionFactory;
9 | import org.springframework.data.redis.core.RedisTemplate;
10 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
11 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
12 | import org.springframework.data.redis.serializer.StringRedisSerializer;
13 |
14 | /**
15 | * @Author zhangyukang
16 | * @Date 2020/12/2 11:26
17 | * @Version 1.0
18 | **/
19 | @Configuration
20 | public class RedisConfig {
21 |
22 | @Bean
23 | @SuppressWarnings("all")
24 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
25 | RedisTemplate template = new RedisTemplate();
26 | template.setConnectionFactory(factory);
27 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
28 | ObjectMapper om = new ObjectMapper();
29 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
30 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
31 | jackson2JsonRedisSerializer.setObjectMapper(om);
32 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
33 | // key采用String的序列化方式
34 | template.setKeySerializer(stringRedisSerializer);
35 | // hash的key也采用String的序列化方式
36 | template.setHashKeySerializer(stringRedisSerializer);
37 | // value序列化方式采用jackson
38 | template.setValueSerializer(jackson2JsonRedisSerializer);
39 | template.setHashValueSerializer(jackson2JsonRedisSerializer);
40 | template.afterPropertiesSet();
41 | return template;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/config/UploadConfig.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 |
5 | /**
6 | * @Author zhangyukang
7 | * @Date 2021/1/17 17:48
8 | * @Version 1.0
9 | **/
10 | @Configuration
11 | public class UploadConfig {
12 | private String fileStoragePath;
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/controller/TestController.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader.controller;
2 |
3 | import com.coderman.uploader.response.RestApiResponse;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | /**
9 | * @Author zhangyukang
10 | * @Date 2021/1/16 15:14
11 | * @Version 1.0
12 | **/
13 | @RestController
14 | @RequestMapping(value = "/test")
15 | public class TestController {
16 |
17 | @GetMapping(value = "/error")
18 | public RestApiResponse error(){
19 | return RestApiResponse.success();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/coderman/uploader/controller/UploadController.java:
--------------------------------------------------------------------------------
1 | package com.coderman.uploader.controller;
2 |
3 | import com.coderman.uploader.dto.FileChunkDTO;
4 | import com.coderman.uploader.dto.FileChunkResultDTO;
5 | import com.coderman.uploader.response.RestApiResponse;
6 | import com.coderman.uploader.service.IUploadService;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.PostMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 |
19 | /**
20 | * @Author zhangyukang
21 | * @Date 2021/1/16 19:22
22 | * @Version 1.0
23 | **/
24 | @RestController
25 | public class UploadController {
26 |
27 | @Autowired
28 | private IUploadService uploadService;
29 |
30 | private Logger logger= LoggerFactory.getLogger(UploadController.class);
31 |
32 | /**
33 | * 检查分片是否存在
34 | * @return
35 | */
36 | @GetMapping(value = "/upload/chunk")
37 | public RestApiResponse