更新用户头像上传功能

This commit is contained in:
jieyuu 2024-04-27 21:04:06 +08:00
parent b488fcc971
commit 285e2b4534
15 changed files with 454 additions and 76 deletions

View File

@ -34,6 +34,8 @@
<commons.lang3.version>3.9</commons.lang3.version>
<commons.codec.version>1.15</commons.codec.version>
<springfox.boot.starter.version>3.0.0</springfox.boot.starter.version>
<minio.version>8.2.1</minio.version>
<docker.image.prefix>xdclass-cloud</docker.image.prefix>
@ -123,6 +125,13 @@
<version>1.1.0</version>
</dependency>
<!--MINIO-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
</dependencies>

View File

@ -27,7 +27,8 @@ public enum BizCodeEnum {
*/
ACCOUNT_REPEAT(250001, "账号已经存在"),
ACCOUNT_UNREGISTER(250002, "账号不存在"),
ACCOUNT_PWD_ERROR(250003, "账号或者密码错误");
ACCOUNT_PWD_ERROR(250003, "账号或者密码错误"),
FILE_UPLOAD_USER_IMG_FAIL(600101, "用户头像文件上传失败");
@Getter
private int code;

View File

@ -5,6 +5,7 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.util.Random;
import java.util.UUID;
public class CommonUtil {
@ -76,6 +77,7 @@ public class CommonUtil {
/**
* 生成随机数
*
* @param length
* @return
*/
@ -90,4 +92,17 @@ public class CommonUtil {
return stringBuilder.toString();
}
/**
* 生成UUID
*
* @return
*/
public static String generateUUID() {
return UUID.randomUUID().toString()
//删除-
.replaceAll("-", "")
//截取前32位
.substring(0, 32);
}
}

View File

@ -30,6 +30,11 @@
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
</dependencies>
<properties>

View File

@ -0,0 +1,277 @@
package net.jieyuu.component;
import io.minio.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import lombok.Data;
import net.jieyuu.utils.CommonUtil;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @description minio工具类
* @version1.0
*/
@Component
public class MinioUtils {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.endpoint}")
private String endpoint;
/**
* description: 判断bucket是否存在不存在则创建
*
* @return: void
*/
public void existBucket(String name) {
try {
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建存储bucket
*
* @param bucketName 存储bucket名称
* @return Boolean
*/
public Boolean makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 删除存储bucket
*
* @param bucketName 存储bucket名称
* @return Boolean
*/
// public Boolean removeBucket(String bucketName) {
// try {
// minioClient.removeBucket(RemoveBucketArgs.builder()
// .bucket(bucketName)
// .build());
// } catch (Exception e) {
// e.printStackTrace();
// return false;
// }
// return true;
// }
/**
* description: 上传多个文件
*
* @param multipartFile
* @return: java.lang.String
*/
// public List<String> uploadFiles(MultipartFile[] multipartFile) {
// List<String> names = new ArrayList<>(multipartFile.length);
// for (MultipartFile file : multipartFile) {
// String fileName = file.getOriginalFilename();
// String[] split = fileName.split("\\.");
// if (split.length > 1) {
// fileName = split[0] + "_" + System.currentTimeMillis() + "." + split[1];
// } else {
// fileName = fileName + System.currentTimeMillis();
// }
// InputStream in = null;
// try {
// in = file.getInputStream();
// minioClient.putObject(PutObjectArgs.builder()
// .bucket(bucketName)
// .object(fileName)
// .stream(in, in.available(), -1)
// .contentType(file.getContentType())
// .build()
// );
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// if (in != null) {
// try {
// in.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
// names.add(fileName);
// }
// return names;
// }
/**
* description: 上传单个文件
*
* @param file
* @return: String
*/
public String uploadFile(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String folder = dateTimeFormatter.format(localDateTime);
String fileName = CommonUtil.generateUUID();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = "user/" + folder + "/" + fileName + extension;
InputStream in = null;
try {
in = file.getInputStream();
ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(newFileName)
.stream(in, in.available(), -1)
.contentType(file.getContentType())
.build()
);
if (objectWriteResponse != null) {
String res = endpoint + "/" + bucketName + "/" + newFileName;
return res;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* description: 下载文件
*
* @param fileName
* @return: org.springframework.http.ResponseEntity<byte [ ]>
*/
public ResponseEntity<byte[]> download(String fileName) {
ResponseEntity<byte[]> responseEntity = null;
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
out = new ByteArrayOutputStream();
IOUtils.copy(in, out);
//封装返回值
byte[] bytes = out.toByteArray();
HttpHeaders headers = new HttpHeaders();
try {
headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
headers.setContentLength(bytes.length);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setAccessControlExposeHeaders(Arrays.asList("*"));
responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return responseEntity;
}
/**
* 查看文件对象
*
* @param bucketName 存储bucket名称
* @return 存储bucket内文件对象信息
*/
// public List<ObjectItem> listObjects(String bucketName) {
// Iterable<Result<Item>> results = minioClient.listObjects(
// ListObjectsArgs.builder().bucket(bucketName).build());
// List<ObjectItem> objectItems = new ArrayList<>();
// try {
// for (Result<Item> result : results) {
// Item item = result.get();
// ObjectItem objectItem = new ObjectItem();
// objectItem.setObjectName(item.objectName());
// objectItem.setSize(item.size());
// objectItems.add(objectItem);
// }
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// return objectItems;
// }
// @Data
// public class ObjectItem {
// private String objectName;
// private Long size;
// }
/**
* 批量删除文件对象
*
* @param bucketName 存储bucket名称
* @param objects 对象名称集合
*/
public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
return results;
}
}

View File

@ -0,0 +1,36 @@
package net.jieyuu.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "minio")
@Configuration
public class MinIoClientConfig {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
/**
* 注入minio 客户端
*
* @return
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKeyId, accessKeySecret)
.build();
}
}

View File

@ -6,7 +6,6 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import net.jieyuu.service.AddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
/**

View File

@ -4,13 +4,15 @@ package net.jieyuu.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import net.jieyuu.enums.BizCodeEnum;
import net.jieyuu.service.AddressService;
import net.jieyuu.service.FileService;
import net.jieyuu.utils.JsonData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* <p>
@ -26,6 +28,8 @@ import org.springframework.web.bind.annotation.RestController;
public class UserController {
@Autowired
AddressService addressService;
@Autowired
FileService fileService;
@ApiOperation("根据id查询地址详情")
@GetMapping("detail/{address_id}")
@ -35,5 +39,22 @@ public class UserController {
return addressService.detail(id);
}
/**
* 用户头像上传
* 默认最大1M,超过报错
*
* @return
*/
@ApiOperation("用户头像上传")
@PostMapping(value = "upload")
public JsonData uploadUserImg(
@ApiParam(value = "文件上传", required = true)
@RequestPart("file") MultipartFile file) throws IOException {
String result = fileService.uploadUserHeadImg(file);
return result!=null?JsonData.buildSuccess(result):JsonData.buildResult(BizCodeEnum.FILE_UPLOAD_USER_IMG_FAIL);
}
}

View File

@ -0,0 +1,11 @@
package net.jieyuu.service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
public interface FileService {
public String uploadUserHeadImg(MultipartFile file) throws IOException;
}

View File

@ -1,21 +0,0 @@
package net.jieyuu.service;
/**
* <p>
* 邮件发送类
* </p>
*
* @author jieyuu
* @since 2024-02-12
*/
public interface MailService {
/**
* 发送邮件
* @param to
* @param subject
* @param content
*/
public void sendMail(String to, String subject, String content);
}

View File

@ -0,0 +1,62 @@
package net.jieyuu.service.impl;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.service.FileService;
import net.jieyuu.utils.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@Service
public class FileServiceImpl implements FileService {
@Autowired
private MinioClient minioClient;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.endpoint}")
private String endpoint;
@Override
public String uploadUserHeadImg(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String folder = dateTimeFormatter.format(localDateTime);
String fileName = CommonUtil.generateUUID();
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
String newFileName = "user/" + folder + "/" + fileName + extension;
try (InputStream in = file.getInputStream();){
ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(newFileName)
.stream(in, in.available(), -1)
.contentType(file.getContentType())
.build()
);
if (objectWriteResponse != null) {
String res = endpoint + "/" + bucketName + "/" + newFileName;
return res;
}
} catch (Exception e) {
log.error("上传头像失败:{}", e);
}
return null;
}
}

View File

@ -1,44 +0,0 @@
package net.jieyuu.service.impl;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.service.MailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class MailServiceImpl implements MailService {
/**
* Spring Boot 提供了一个发送邮件的简单抽象直接注入即可使用
*/
@Autowired
private JavaMailSender mailSender;
/**
* 配置文件中的发送邮箱
*/
@Value("${spring.mail.from}")
private String from;
@Override
public void sendMail(String to, String subject, String content) {
//创建SimpleMailMessage对象
SimpleMailMessage message = new SimpleMailMessage();
//邮件发送人
message.setFrom(from);
//邮件接收人
message.setTo(to);
//邮件主题
message.setSubject(subject);
//邮件内容
message.setText(content);
//发送邮件
mailSender.send(message);
log.info("邮件发成功:{}", message.toString());
}
}

View File

@ -1,8 +1,8 @@
package net.jieyuu.service.impl;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.component.MailService;
import net.jieyuu.enums.SendCodeEnum;
import net.jieyuu.service.MailService;
import net.jieyuu.service.NotifyService;
import net.jieyuu.utils.CheckUtil;
import net.jieyuu.utils.CommonUtil;
@ -11,8 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.security.auth.Subject;
@Slf4j
@Service
public class NotifyServiceImpl implements NotifyService {

View File

@ -36,4 +36,13 @@ mybatis-plus:
#设置日志级别,ERROR/WARN/INFO/DEBUG,默认是INFO以上才显示
logging:
level:
root: INFO
root: INFO
minio:
endpoint: http://134.175.219.253:9000
access-key-id: Y7sQYzzcBob67Wu7agLK
access-key-secret: PXT1QKl0U23VMMKPmCbDZvGaJiw23AhQWpd4RlO9
bucketName: xdclass-shop-image

View File

@ -2,7 +2,7 @@ package net.jieyuu.biz;
import lombok.extern.slf4j.Slf4j;
import net.jieyuu.UserServiceApplication;
import net.jieyuu.service.MailService;
import net.jieyuu.component.MailService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;