# spring-boot-demo-upload > 本 demo 演示了 Spring Boot 如何实现本地文件上传以及如何上传文件至七牛云平台。前端使用 vue 和 iview 实现上传页面。 ## pom.xml ```xml 4.0.0 spring-boot-demo-upload 1.0.0-SNAPSHOT jar spring-boot-demo-upload Demo project for Spring Boot com.xkcoding spring-boot-demo 1.0.0-SNAPSHOT UTF-8 UTF-8 1.8 org.projectlombok lombok true org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-test test cn.hutool hutool-all com.qiniu qiniu-java-sdk [7.2.0, 7.2.99] spring-boot-demo-upload org.springframework.boot spring-boot-maven-plugin ``` ## UploadConfig.java ```java /** *

* 上传配置 *

* * @author yangkai.shen * @date Created in 2018-10-23 14:09 */ @Configuration @ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class}) @ConditionalOnProperty(prefix = "spring.http.multipart", name = "enabled", matchIfMissing = true) @EnableConfigurationProperties(MultipartProperties.class) public class UploadConfig { @Value("${qiniu.accessKey}") private String accessKey; @Value("${qiniu.secretKey}") private String secretKey; private final MultipartProperties multipartProperties; @Autowired public UploadConfig(MultipartProperties multipartProperties) { this.multipartProperties = multipartProperties; } /** * 上传配置 */ @Bean @ConditionalOnMissingBean public MultipartConfigElement multipartConfigElement() { return this.multipartProperties.createMultipartConfig(); } /** * 注册解析器 */ @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) @ConditionalOnMissingBean(MultipartResolver.class) public StandardServletMultipartResolver multipartResolver() { StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver(); multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily()); return multipartResolver; } /** * 华东机房 */ @Bean public com.qiniu.storage.Configuration qiniuConfig() { return new com.qiniu.storage.Configuration(Zone.zone0()); } /** * 构建一个七牛上传工具实例 */ @Bean public UploadManager uploadManager() { return new UploadManager(qiniuConfig()); } /** * 认证信息实例 */ @Bean public Auth auth() { return Auth.create(accessKey, secretKey); } /** * 构建七牛空间管理实例 */ @Bean public BucketManager bucketManager() { return new BucketManager(auth(), qiniuConfig()); } } ``` ## UploadController.java ```java /** *

* 文件上传 Controller *

* * @author yangkai.shen * @date Created in 2018-11-06 16:33 */ @RestController @Slf4j @RequestMapping("/upload") public class UploadController { @Value("${spring.servlet.multipart.location}") private String fileTempPath; @Value("${qiniu.prefix}") private String prefix; private final IQiNiuService qiNiuService; @Autowired public UploadController(IQiNiuService qiNiuService) { this.qiNiuService = qiNiuService; } @PostMapping(value = "/local", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public Dict local(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Dict.create().set("code", 400).set("message", "文件内容为空"); } String fileName = file.getOriginalFilename(); String rawFileName = StrUtil.subBefore(fileName, ".", true); String fileType = StrUtil.subAfter(fileName, ".", true); String localFilePath = StrUtil.appendIfMissing(fileTempPath, "/") + rawFileName + "-" + DateUtil.current(false) + "." + fileType; try { file.transferTo(new File(localFilePath)); } catch (IOException e) { log.error("【文件上传至本地】失败,绝对路径:{}", localFilePath); return Dict.create().set("code", 500).set("message", "文件上传失败"); } log.info("【文件上传至本地】绝对路径:{}", localFilePath); return Dict.create().set("code", 200).set("message", "上传成功").set("data", Dict.create().set("fileName", fileName).set("filePath", localFilePath)); } @PostMapping(value = "/yun", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public Dict yun(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return Dict.create().set("code", 400).set("message", "文件内容为空"); } String fileName = file.getOriginalFilename(); String rawFileName = StrUtil.subBefore(fileName, ".", true); String fileType = StrUtil.subAfter(fileName, ".", true); String localFilePath = StrUtil.appendIfMissing(fileTempPath, "/") + rawFileName + "-" + DateUtil.current(false) + "." + fileType; try { file.transferTo(new File(localFilePath)); Response response = qiNiuService.uploadFile(new File(localFilePath)); if (response.isOK()) { JSONObject jsonObject = JSONUtil.parseObj(response.bodyString()); String yunFileName = jsonObject.getStr("key"); String yunFilePath = StrUtil.appendIfMissing(prefix, "/") + yunFileName; FileUtil.del(new File(localFilePath)); log.info("【文件上传至七牛云】绝对路径:{}", yunFilePath); return Dict.create().set("code", 200).set("message", "上传成功").set("data", Dict.create().set("fileName", yunFileName).set("filePath", yunFilePath)); } else { log.error("【文件上传至七牛云】失败,{}", JSONUtil.toJsonStr(response)); FileUtil.del(new File(localFilePath)); return Dict.create().set("code", 500).set("message", "文件上传失败"); } } catch (IOException e) { log.error("【文件上传至七牛云】失败,绝对路径:{}", localFilePath); return Dict.create().set("code", 500).set("message", "文件上传失败"); } } } ``` ## QiNiuServiceImpl.java ```java /** *

* 七牛云上传Service *

* * @author yangkai.shen * @date Created in 2018-11-06 17:22 */ @Service @Slf4j public class QiNiuServiceImpl implements IQiNiuService, InitializingBean { private final UploadManager uploadManager; private final Auth auth; @Value("${qiniu.bucket}") private String bucket; private StringMap putPolicy; @Autowired public QiNiuServiceImpl(UploadManager uploadManager, Auth auth) { this.uploadManager = uploadManager; this.auth = auth; } /** * 七牛云上传文件 * * @param file 文件 * @return 七牛上传Response * @throws QiniuException 七牛异常 */ @Override public Response uploadFile(File file) throws QiniuException { Response response = this.uploadManager.put(file, file.getName(), getUploadToken()); int retry = 0; while (response.needRetry() && retry < 3) { response = this.uploadManager.put(file, file.getName(), getUploadToken()); retry++; } return response; } @Override public void afterPropertiesSet() { this.putPolicy = new StringMap(); putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"width\":$(imageInfo.width), \"height\":${imageInfo.height}}"); } /** * 获取上传凭证 * * @return 上传凭证 */ private String getUploadToken() { return this.auth.uploadToken(bucket, null, 3600, putPolicy); } } ``` ## index.html ```html spring-boot-demo-upload

本地上传

选择文件 {{ local.loadingStatus ? '本地文件上传中' : '本地上传' }}
状态:{{local.log.message}}
文件名:{{local.log.fileName}}
文件路径:{{local.log.filePath}}

七牛云上传

选择文件 {{ yun.loadingStatus ? '七牛云文件上传中' : '七牛云上传' }}
状态:{{yun.log.message}}
文件名:{{yun.log.fileName}}
文件路径:{{yun.log.filePath}}
``` ## 参考 1. Spring 官方文档:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#howto-multipart-file-upload-configuration 2. 七牛云官方文档:https://developer.qiniu.com/kodo/sdk/1239/java#5