diff --git a/spring-boot-demo-upload/README.md b/spring-boot-demo-upload/README.md new file mode 100644 index 0000000..a139374 --- /dev/null +++ b/spring-boot-demo-upload/README.md @@ -0,0 +1,519 @@ +# 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 +/** + *

+ * 上传配置 + *

+ * + * @package: com.xkcoding.upload.config + * @description: 上传配置 + * @author: yangkai.shen + * @date: Created in 2018/10/23 14:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@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 + *

+ * + * @package: com.xkcoding.upload.controller + * @description: 文件上传 Controller + * @author: yangkai.shen + * @date: Created in 2018/11/6 16:33 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@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 + *

+ * + * @package: com.xkcoding.upload.service.impl + * @description: 七牛云上传Service + * @author: yangkai.shen + * @date: Created in 2018/11/6 17:22 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@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 +