上传多张图片时需要在对应类中增加图像地址的数组(加上数据库不存在该字段注解),在逻辑层将多张图片的地址进行拼接一起,存入数据库。
配置文件
minio.url = http://10.34.5.124:9000/ #图床
minio.domain = http://10.34.5.124:9000/ #正式上线
minio.user=test
minio.password=12345678
minio.bucketName=reportsystem
minio工具类
package com.custhitahi.zhjc.util;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@Slf4j
@PropertySource("classpath:upload.properties")
@Component
public class MinioUtil {
/** minio地址+端口号 */
@Value("${minio.url}")
private String url;
/** minio用户名 */
@Value("${minio.user}")
private String user;
/** minio密码 */
@Value("${minio.password}")
private String password;
/** 桶的名称 */
@Value("${minio.bucketName}")
private String bucketName;
/** 域名 */
@Value("${minio.domain}")
private String domain;
private static MinioClient minioClient;
/**
* 不排序
*/
public final static boolean NOT_SORT = false;
/**
* 初始化minio配置
*/
@PostConstruct
public void init() {
try {
minioClient = MinioClient.builder().endpoint(url).credentials(user,password).build();
if(!isBucketExist()){
createBucket();
}
} catch (Exception e) {
e.printStackTrace();
log.error("初始化minio配置异常: 【{ }】", e.fillInStackTrace());
}
}
/**
* 存储桶是否存在
* @return true/false
*/
@SneakyThrows
public boolean isBucketExist(){
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* 创建存储桶
*/
@SneakyThrows
public void createBucket(){
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
/**
* 获取访问对象的外链地址
* @param objectName 对象名称
* @return viewUrl
*/
@SneakyThrows
public String getObjectUrl(String objectName){
String ori = minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.build()
);
//把minio图床的前缀网址截取出来
String url = ori.substring(0, ori.indexOf("?"));
//把图传的网址改为正式上线的远程服务器的地址
return domain+url.substring(url.indexOf("9000")+5);
}
@SneakyThrows
public String getObjectUrlWithBucket(String objectName,String bucketName){
String ori = minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(objectName)
.build()
);
String url = ori.substring(0, ori.indexOf("?"));
return domain+url.substring(url.indexOf("9000")+5);
}
/**
* 上传本地文件
* @param objectName 欲上传的本地文件对象的名称
* @param filePath 本地文件路径
*/
@SneakyThrows
public void uploadFile(String objectName, String filePath){
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(filePath)
.build());
}
public void uploadFile(String objectName, MultipartFile file) throws Exception {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.contentType(file.getContentType())
.stream(file.getInputStream(), file.getSize(), -1)
.build());
}
public void uploadFile(String objectName, InputStream stream, String size) throws Exception {
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(stream, Long.parseLong(size), -1)
.build());
}
@SneakyThrows
public void uploadFileWithBucket(String bucketName,String objectName, String filePath){
minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(filePath)
.build());
}
/**
* 下载文件
* @param fileName 文件名
* @return 文件流
*/
@SneakyThrows(Exception.class)
public InputStream download(String fileName) {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
}
@SneakyThrows(Exception.class)
public InputStream downloadWithBucket(String fileName,String bucketName) {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build());
}
/**
* 删除对象
* @param objectName
* @return true/false
*/
@SneakyThrows
public boolean removeObject(String objectName){
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build()
);
return true;
}
/**
* 批量删除对象
* @param objectNames
* @return true/false
*/
public boolean removeObjects(List<String> objectNames){
List<DeleteObject> deleteObjects = new ArrayList<>(objectNames.size());
for (String objectName : objectNames){
deleteObjects.add(new DeleteObject(objectName));
}
minioClient.removeObjects(
RemoveObjectsArgs.builder()
.bucket(bucketName)
.objects(deleteObjects)
.build()
);
return true;
}
/**
* 将分钟数转换为秒数
* @param expiry 过期时间(分钟数)
* @return expiry
*/
private static int expiryHandle(Integer expiry){
expiry = expiry * 60;
if (expiry > 604800){
return 604800;
}
return expiry;
}
static class Str2IntComparator implements Comparator<String> {
private final boolean reverseOrder; // 是否倒序
public Str2IntComparator(boolean reverseOrder) {
this.reverseOrder = reverseOrder;
}
@Override
public int compare(String arg0, String arg1) {
Integer intArg0 = Integer.parseInt(arg0.substring(arg0.indexOf("/") + 1,arg0.lastIndexOf(".")));
Integer intArg1 = Integer.parseInt(arg1.substring(arg1.indexOf("/") + 1,arg1.lastIndexOf(".")));
if(reverseOrder) {
return intArg1 - intArg0;
} else {
return intArg0 - intArg1;
}
}
}
}
单张控制层
@PostMapping("/uploadSign") public Result uploadInvoice(@RequestParam("file") MultipartFile multipartFile) throws Exception { System.out.println("-------------" + multipartFile); String url = null; String originalFilename = multipartFile.getOriginalFilename(); String mainName = FileUtil.mainName(originalFilename); String extName = FileUtil.extName(originalFilename); String fileName = System.currentTimeMillis() + "_" + mainName + "." + extName; //将文件上传到图床 minioUtil.uploadFile(objectName + fileName ,multipartFile); url = minioUtil.getObjectUrl(objectName+fileName); return ResultFactory.successWithData(url); }
多张控制层
可以和单张用一样的,因为前端上传几张就需要访问几次上传接口
与单张不同的是多次上传后前端通过数组把多次的地址储存起来,添加的时候传给后端数组,后端在服务层进行数组切割,然后赋值到实体类的img字段插入到数据库
@Resource private MinioUtil minioUtil; String objectName = "invoice/"; //这里为每上传一张图片返回给前端一个地址,上传多张图片后前端把地址拼接成一个数组, //添加的时候和其他数据一起返回给后端,后端在服务层做分割处理,复制到实体类的img字段中 @RequestMapping("/uploadInvoice") public Result uploadInvoice(MultipartRequest multipartRequest) throws Exception { Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); String url = null; for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) { MultipartFile file = entry.getValue(); String originalFileName = file.getOriginalFilename(); String mainName = FileUtil.mainName(originalFileName);//aaa String extName = FileUtil.extName(originalFileName);//png String fileName = System.currentTimeMillis() + "_" + mainName + "." + extName; //将文件上传到图床 minioUtil.uploadFile(objectName + fileName, file); url = minioUtil.getObjectUrl(objectName + fileName); } return ResultFactory.successWithData(url); }
多张服务层
@Transactional @Override public int addPurchaseDetail(FireconPurchaseDetail fireconPurchaseDetail) { int res = -1; // 参数判空处理 if(ObjectUtil.isEmpty(fireconPurchaseDetail)) { throw new NullPointerException(); } try { String result = String.join(",", fireconPurchaseDetail.getImageUrls()); fireconPurchaseDetail.setImg(result); // 保存到数据库 fireconPurchaseDetail.setApplicationDate(LocalDateTime.now().toLocalDate()); fireconPurchaseDetail.setApplicationMoney(fireconPurchaseDetail.getApplicationPrice().multiply(fireconPurchaseDetail.getApplicationNum())); fireconPurchaseDetailMapper.insert(fireconPurchaseDetail); res = fireconPurchaseRequestMapper.updateTotal(fireconPurchaseDetail.getRequestId()); } catch (Exception e) { throw e; } return res; }
实体类
private String img;//数据库存储的拼接后多张图片的地址
//接收前端传来的多张图片地址,数据库不存在该字段,后端做字符串拼接后存入img字段
@TableField(exist=false)
private String[] imageUrls;