在项目需求中需要用到图片上传的功能,决定将图片上传到图床使用,这里选用七牛云服务器。
在springboot的项目中,将结合代码上传本地图片至七牛云。
一. 准备七牛云账号
1. 申请七牛云账号
如果您还没有七牛云账号,可以先去七牛云官网注册账号,注册成功后登录进入管理控制台。
2.按需创建存储空间
七牛云新建存储空间参考文档 不懂的可以查看官方文档
- 在管理控制台界面点击左侧【对象存储】
- 点击【新建存储空间】(因为我已经有一个空间,这里只是演示一下)
新建存储空间完成后,七牛云会给我们一个测试用的域名,但是这个域名只有30天的有效时间,30天后会自动失效。
注意:如果没有自己的域名,以下的第3步和第4步可以直接跳过哦
3. 从测试域名过渡到自定义域名
详情请查看官方文档,就不做过多解释了从测试域名过渡到自定义域名
4. 配置域名的 CNAME
详情请查看官方文档如何配置域名的CNAME
以上准备工作做完后,开始代码编写的过程。
二. springboot整合七牛云
此项目使用 springboot 搭建
- 将七牛云的相关依赖项添加到
pom.xml
文件中
<!--七牛云-->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.2.0, 7.2.99]</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>happy-dns-java</artifactId>
<version>0.1.4</version>
<scope>compile</scope>
</dependency>
- 在
application.properties
文件中编写七牛云的配置
# 七牛云相关配置
# bucket 是创建的存储空间名
# path 对应存储空间的访问域名
qiniu.accessKey=
qiniu.secretKey=
qiniu.bucket=
qiniu.path=
baseUploadUrl= c://xianer/images/
相关参数含义
进入七牛云管理控制台的【密钥管理】查看 accessKey
和 secretKey
bucket
是我们之前创建的存储空间名称
path
是我们的测试域名或自定义域名
baseUploadUrl
是自定义的本地文件路径,七牛云在图片上传过程中会在本地临时存储文件,可以自己修改文件路径。
3. 在 config
包下新建一个 FileUploadConfig
的配置类
package cn.duli.xianer.config;
import com.google.gson.Gson;
import com.qiniu.common.Zone;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.MultipartConfigElement;
import javax.servlet.Servlet;
import java.io.File;
@Configuration
@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})
@ConditionalOnProperty(prefix = "spring.http.multipart", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(MultipartProperties.class)
public class FileUploadConfig {
private final MultipartProperties multipartProperties;
@Value("${baseUploadUrl}")
private String baseUploadUrl;
@Value("${qiniu.accessKey}")
private String accessKey;
@Value("${qiniu.secretKey}")
private String secretKey;
public FileUploadConfig(MultipartProperties multipartProperties) {
this.multipartProperties = multipartProperties;
}
/**
* 上传配置
*/
@Bean
@ConditionalOnMissingBean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
judge(baseUploadUrl);
factory.setLocation(baseUploadUrl);
return factory.createMultipartConfig();
}
public void judge(String filePath){
File file = new File(filePath);
if(!file.exists()){
file.mkdir();
}
}
/**
* 注册解析器
*/
@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.zone2());
}
/**
* 构建一个七牛上传工具实例
*/
@Bean
public UploadManager uploadManager() {
return new UploadManager(qiniuConfig());
}
/**
* 认证信息实例
*
* @return
*/
@Bean
public Auth auth() {
return Auth.create(accessKey, secretKey);
}
/**
* 构建七牛空间管理实例
*/
@Bean
public BucketManager bucketManager() {
return new BucketManager(auth(), qiniuConfig());
}
/**
* 配置gson为json解析工具
*
* @return
*/
@Bean
public Gson gson() {
return new Gson();
}
}
**注意:**在第3步中,需要查看你自己新建的存储空间所属区域,区域必须 与 构建配置类中的 Zone.zone2() 一 一对应
/**
* 华南机房(特别注意)
*/
@Bean
public com.qiniu.storage.Configuration qiniuConfig() {
return new com.qiniu.storage.Configuration(Zone.zone2());
}
其他常见的所属配置
Configuration cfg = new Configuration(Zone.zone0());//Zone.zone0() 指华东
Configuration cfg = new Configuration(Zone.zone1());//华北
Configuration cfg = new Configuration(Zone.zone2());//华南
- 在
service
包下新建一个FileService
的接口
package cn.duli.xianer.service;
import com.qiniu.common.QiniuException;
import java.io.File;
import java.util.Map;
public interface FileService {
/**
* 多文件上传
* @param file
* @return
* @throws QiniuException
*/
Map uploadFile(File file) throws QiniuException;
}
- 在
impl
包下新建FileServiceImpl
实现类
package cn.duli.xianer.service.impl;
import cn.duli.xianer.service.FileService;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private UploadManager uploadManager;
@Autowired
private Auth auth;
@Value("${qiniu.bucket}")
private String bucket;
private StringMap putPolicy;
@Override
public Map uploadFile(File file) throws QiniuException {
Map map = new HashMap();
Response response = this.uploadManager.put(file,null,getUploadToken());
//解析上传的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(),DefaultPutRet.class);
String imageName = putRet.hash;
int retry = 0;
while(response.needRetry() && retry < 3){
response = this.uploadManager.put(file,null,getUploadToken());
}
map.put("response",response);
map.put("imgName",imageName);
return map;
}
private String getUploadToken(){
return this.auth.uploadToken(bucket,null,3600,putPolicy);
}
}
- 在
controller
包下新建一个TestController
类,用来测试图片上传
package cn.duli.xianer.controller;
import cn.duli.xianer.service.FileService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/upload")
public class TestController {
@Autowired
FileService fileService;
@Value("${baseUploadUrl}")
private String url;
/**
* 多图上传
* @param upfiles
* @return
* @throws IOException
*/
@PostMapping(value = "/uploadImg")
public List<Map<String,Object>> uploadImg(@RequestParam(value = "files")MultipartFile upfiles[]) throws IOException {
List<Map<String,Object>> listMaps = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
System.out.println(upfiles);
try{
if(upfiles!=null) {
for (int i=0;i<upfiles.length;i++) {
if (!upfiles[i].isEmpty()) {
String fileName = upfiles[i].getOriginalFilename();
File file = new File(url + fileName);
// 将MulitpartFile文件转化为file文件格式
upfiles[i].transferTo(file);
Map response = fileService.uploadFile(file);
Object imageName = response.get("imgName");
map.put("url",imageName);
listMaps.add(map);
System.out.println(upfiles[i]);
}
}
System.out.println(listMaps);
}
}catch (Exception e){
e.printStackTrace();
}
return listMaps;
}
}
以上都完成了过后,我们使用 postman
测试多图上传接口
注意:使用 postman
测试图片上传时,Headers头部不能有任何东西,如果有 Content-Type
的话,需要取消勾选,否则图片会上传失败
Body:
选择Body
选择form-data
key:后台规定的接收文件的名称参数(切记不是你传的图片名称)
key的格式选择为File
value:自动变成 选择文件
点击 send 即可将图片上传成功
查看七牛云中是否上传成功,在管理控制台的空间管理-》文件管理中查看
最后,使用 域名+文件名 就可以访问图片啦~
补充:如果只需要实现单张图片上传到七牛云服务器,则只修改 TestController
中的代码即可
package cn.duli.xianer.controller;
import cn.duli.xianer.service.FileService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/upload")
public class TestController {
@Autowired
FileService fileService;
@Value("${baseUploadUrl}")
private String url;
/**
* 单图上传
* @param upfiles
* @return
* @throws IOException
*/
@PostMapping(value = "/uploadImg")
public Map<String,Object> uploadImg(@RequestParam(value = "file")MultipartFile upfile) throws IOException {
Map<String,Object> map = new HashMap<>();
String fileName = upfile.getOriginalFilename();
File file = new File(url + fileName);
try{
//将MulitpartFile文件转化为file文件格式
upfile.transferTo(file);
Map response = fileService.uploadFile(file);
Object imageName = response.get("imgName");
map.put("url",imageName);
}catch (Exception e){
e.printStackTrace();
}
return map;
}
}