SpringBoot实现将图片上传到阿里云OSS
阿里云OSS的购买和使用可以参考我的这篇博客:阿里云OSS存储的购买和使用
1、导入相关依赖
<!--阿里云OSS依赖--> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.9.1</version> </dependency> <!--日期处理依赖--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.1</version> </dependency>
2、创建相关配置类
@Configuration @PropertySource("classpath:aliyun.yaml") //读取配置文件 @ConfigurationProperties(prefix = "aliyun") @Data public class AliyunConfig { private String endpoint ; private String accessKeyId; private String accessKeySecret; @Bean public OSS ossClient(){ return new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret); } }
这里需要注意的是endpoint,accessKeyId,accessKeySecret的值是写到了配置文件中,使用@PropertySource注解来读取配置文件
配置文件我这里使用的是yaml格式,看起来层次更加清晰
同时还需要使用@ConfigurationProperties(prefix = "aliyun")注解来指定哪个前缀下面的值会被注入到AliyunConfig类的属性中(需要注意的是,该注解注入属性的方式是使用set方法,所以必须为AliyunConfig类中的属性提供set方法,我这里使用了@Data注解来简化开发)
@ConfigurationProperties注解使用的时候需要添加下面的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置文件中的endpoint指的是域名节点,可以在你创建的bucket概览中查看
accessKeyId和accessKeySecret的获取
1、鼠标放在登录头向上,点击AccessKey管理
2、点击使用子用户
3、创建用户
4、创建成功之后点击用户
5、点击创建AccessKey
6、将创建好的信息保存(accessSecret只能通过改方法获取一次,弹框关闭之后再也无法查看了!!!)
编写上传逻辑代码
1、自定义结果类
@Data public class PicUploadResult { /* * 这个类是我自定义的结果类,不一定非要按照这个格式写,里面的属性都可以自己定义 * */ private String uid; //自定义ID private String name;//自定义文件名称 private String status;//上传结果的状态 private String response;//上传响应的状态 public PicUploadResult() { } public PicUploadResult(String uid, String name, String status, String response) { this.uid = uid; this.name = name; this.status = status; this.response = response; } }
2、controller
@Controller @CrossOrigin //我使用的是前后端分离,该注解用来解决跨域问题 @RequestMapping("/picUpload") public class PicUploadController { @Autowired private PicUploadService picUploadService; @PostMapping() @ResponseBody public PicUploadResult upload(@RequestParam("file")MultipartFile file){ return picUploadService.upload(file); } }
3、service层(主要逻辑代码的书写位置)
@Service public class PicUploadServiceImpl implements PicUploadService { //注入OSS对象 @Autowired private OSS oss; @Autowired private AliyunConfig aliyunConfig; //允许上传的格式 private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg", ".jpeg", ".webp", ".gif", ".png"}; @Override public PicUploadResult upload(MultipartFile file) { PicUploadResult result = new PicUploadResult(); //对图片的后缀名做校验 boolean isLegal = false; for (String type : IMAGE_TYPE) { if (StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), type)) { isLegal = true; break; } } if (!isLegal) { result.setStatus("error"); return result; } //设置文件的路径,getFilePath为封装的自定义路径的方法,在下面 String fileName = file.getOriginalFilename(); String filePath = getFilePath(fileName); //上传到阿里云 try { //调用阿里云提供的API oss.putObject(aliyunConfig.getBucketName(), filePath, new ByteArrayInputStream(file.getBytes())); } catch (IOException e) { e.printStackTrace(); result.setStatus("error"); return result; } result.setStatus("success"); result.setName(aliyunConfig.getUrlPrefix() + fileName); result.setUid(String.valueOf(System.currentTimeMillis())); System.out.println("result = " + result); return result; } //定义生成文件新路径的方法,目录结构:images+年+月+日+xxx.jpg private String getFilePath(String sourceFileName) { DateTime dateTime = new DateTime(); return "images" + "/" + dateTime.toString("yyyy") + "/" + dateTime.toString("MM") + "/" + dateTime.toString("dd") + "/" + System.currentTimeMillis() + RandomUtils.nextInt(100, 9999) + "." + StringUtils.substringAfterLast(sourceFileName, "."); } }
逻辑已经写完了,大家自行测试吧!!!
------------------------------------------------------------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------------------------------------------------------------
把我在实现文件上传时候遇到的坑写出来给大家作参考,避免踩坑
错误一:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'picUploadController':
Unsatisfied dependency expressed through field 'picUploadService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'picUploadServiceImpl': Unsatisfied dependency expressed through field 'oss';
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'oss' defined in class path resource [com/jingzhe/blog/config/AliyunConfig.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.aliyun.oss.OSS]: Factory method 'oss' threw exception; nested exception is
java.lang.IllegalArgumentException: java.net.URISyntaxException: Illegal character in authority at index 7: http://oss-cn-beijing.aliyuncs.com
这个错误真的是让我懵逼了很长时间,我一直以为是配置类出现了问题,但是翻来覆去的检查都觉得我写的是ok的(事实证明的确是OK的)
为了解决它我疯狂的百度、翻资料,本来就少的头发更是刷刷的往下掉,后来无意间(真的是,缘分这东西太™奇妙了)找到一篇帖子,说的是配置文件中的url路径可能写错了
嗯?!??!!!!0_0.。。。
在我一个字母一个字母翻来覆去的对比之后,终于发现了!!!!!一个不起眼的空格。。。。
就是他!!!!去掉空格之后,项目成功运行,所以说,大家在遇到错误的时候一定不能心急,仔细一些,有些错误很可能自己就蹦出来了
------------------------------------
错误2:You have no right to access this object because of bucket acl.
这个错误是在测试的时候出现的问题,原因是你所使用的子用户没有被授权。
添加完成在测试就OK了。至此,文件上传至阿里云告一段落。
祝大家处事不惊,前程似锦,晚安!