diff --git a/.gitignore b/.gitignore
index 5c08283..31eae03 100755
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,4 @@ build/
/han-note-auth/logs/
/logs/
/.idea/
+/han-note-oss/han-note-oss-biz/src/main/resources/application-dev.yml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index 7932393..8126366 100755
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -5,6 +5,12 @@
+
+
+
+
+
+
diff --git a/han-note-auth/pom.xml b/han-note-auth/pom.xml
index 7f37689..c119563 100755
--- a/han-note-auth/pom.xml
+++ b/han-note-auth/pom.xml
@@ -97,6 +97,11 @@
com.hanserwei
hanserwei-spring-boot-starter-biz-context
+
+
+ org.springframework.security
+ spring-security-crypto
+
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/config/PasswordEncoderConfig.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/config/PasswordEncoderConfig.java
new file mode 100644
index 0000000..3f349ee
--- /dev/null
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/config/PasswordEncoderConfig.java
@@ -0,0 +1,21 @@
+package com.hanserwei.hannote.auth.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PasswordEncoderConfig {
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ // BCrypt 是一种安全且适合密码存储的哈希算法,它在进行哈希时会自动加入“盐”,增加密码的安全性。
+ return new BCryptPasswordEncoder();
+ }
+
+ public static void main(String[] args) {
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ System.out.println(encoder.encode("qwe123"));
+ }
+}
\ No newline at end of file
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/controller/UserController.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/controller/UserController.java
index 3ca8fcc..e00621c 100644
--- a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/controller/UserController.java
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/controller/UserController.java
@@ -2,13 +2,17 @@ package com.hanserwei.hannote.auth.controller;
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
import com.hanserwei.hannote.auth.service.UserService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
@@ -30,4 +34,10 @@ public class UserController {
public Response> logout() {
return userService.logout();
}
+
+ @PostMapping("/password/update")
+ @ApiOperationLog(description = "修改密码")
+ public Response> updatePassword(@Validated @RequestBody UpdatePasswordReqVO updatePasswordReqVO) {
+ return userService.updatePassword(updatePasswordReqVO);
+ }
}
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/enums/ResponseCodeEnum.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/enums/ResponseCodeEnum.java
index 4911adf..3caf502 100644
--- a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/enums/ResponseCodeEnum.java
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/enums/ResponseCodeEnum.java
@@ -15,6 +15,9 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
// ----------- 业务异常状态码 -----------
VERIFICATION_CODE_SEND_FREQUENTLY("AUTH-20000", "请求太频繁,请3分钟后再试"),
VERIFICATION_CODE_ERROR("AUTH-20001", "验证码错误"),
+ LOGIN_TYPE_ERROR("AUTH-20002", "登录类型错误"),
+ USER_NOT_FOUND("AUTH-20003", "该用户不存在"),
+ MAIL_OR_PASSWORD_ERROR("AUTH-20004", "邮箱号或密码错误"),
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/model/vo/user/UpdatePasswordReqVO.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/model/vo/user/UpdatePasswordReqVO.java
new file mode 100644
index 0000000..caf0c70
--- /dev/null
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/model/vo/user/UpdatePasswordReqVO.java
@@ -0,0 +1,18 @@
+package com.hanserwei.hannote.auth.model.vo.user;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class UpdatePasswordReqVO {
+
+ @NotBlank(message = "新密码不能为空")
+ private String newPassword;
+
+}
\ No newline at end of file
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/UserService.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/UserService.java
index 40b9a48..71932e6 100644
--- a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/UserService.java
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/UserService.java
@@ -3,6 +3,7 @@ package com.hanserwei.hannote.auth.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.auth.domain.dataobject.UserDO;
+import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
public interface UserService extends IService {
@@ -20,4 +21,11 @@ public interface UserService extends IService {
* @return 响应结果
*/
Response> logout();
+
+ /**
+ * 修改密码
+ * @param updatePasswordReqVO 请求参数
+ * @return 响应结果
+ */
+ Response> updatePassword(UpdatePasswordReqVO updatePasswordReqVO);
}
diff --git a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/impl/UserServiceImpl.java b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/impl/UserServiceImpl.java
index db00b49..c41553c 100644
--- a/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/impl/UserServiceImpl.java
+++ b/han-note-auth/src/main/java/com/hanserwei/hannote/auth/service/impl/UserServiceImpl.java
@@ -22,6 +22,7 @@ import com.hanserwei.hannote.auth.domain.mapper.UserDOMapper;
import com.hanserwei.hannote.auth.domain.mapper.UserRoleDOMapper;
import com.hanserwei.hannote.auth.enums.LoginTypeEnum;
import com.hanserwei.hannote.auth.enums.ResponseCodeEnum;
+import com.hanserwei.hannote.auth.model.vo.user.UpdatePasswordReqVO;
import com.hanserwei.hannote.auth.model.vo.user.UserLoginReqVO;
import com.hanserwei.hannote.auth.service.UserService;
import jakarta.annotation.Resource;
@@ -30,6 +31,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
@@ -50,6 +52,7 @@ public class UserServiceImpl extends ServiceImpl implement
private final RoleDOMapper roleDOMapper;
@Resource(name = "authTaskExecutor")
private ThreadPoolTaskExecutor authTaskExecutor;
+ private final PasswordEncoder passwordEncoder;
@Override
public Response loginAndRegister(UserLoginReqVO reqVO) {
@@ -87,6 +90,19 @@ public class UserServiceImpl extends ServiceImpl implement
}
break;
case PASSWORD:
+ String password = reqVO.getPassword();
+ // 根据邮箱号查询
+ UserDO userDO1 = this.getOne(new QueryWrapper().eq("email", email));
+ if (Objects.isNull(userDO1)){
+ throw new ApiException(ResponseCodeEnum.USER_NOT_FOUND);
+ }
+ // 拿到密文密码
+ String encodePassword = userDO1.getPassword();
+ boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);
+ if (!isPasswordCorrect) {
+ throw new ApiException(ResponseCodeEnum.MAIL_OR_PASSWORD_ERROR);
+ }
+ userId = userDO1.getId();
break;
default:
break;
@@ -158,4 +174,23 @@ public class UserServiceImpl extends ServiceImpl implement
StpUtil.logout(userId);
return Response.success();
}
+
+ @Override
+ public Response> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
+ // 新密码
+ String newPassword = updatePasswordReqVO.getNewPassword();
+ // 加密后的密码
+ String encodePassword = passwordEncoder.encode(newPassword);
+ // 获取用户ID
+ Long userId = LoginUserContextHolder.getUserId();
+
+ UserDO userDO = UserDO.builder()
+ .id(userId)
+ .password(encodePassword)
+ .updateTime(LocalDateTime.now())
+ .build();
+ // 更新用户密码
+ this.updateById(userDO);
+ return Response.success();
+ }
}
diff --git a/han-note-oss/han-note-oss-api/pom.xml b/han-note-oss/han-note-oss-api/pom.xml
new file mode 100644
index 0000000..d162cf2
--- /dev/null
+++ b/han-note-oss/han-note-oss-api/pom.xml
@@ -0,0 +1,24 @@
+
+ 4.0.0
+
+
+ com.hanserwei
+ han-note-oss
+ ${revision}
+
+
+
+ jar
+
+ han-note-oss-api
+ ${project.artifactId}
+ RPC层, 供其他服务调用
+
+
+
+ com.hanserwei
+ hanserwei-common
+
+
+
diff --git a/han-note-oss/han-note-oss-biz/pom.xml b/han-note-oss/han-note-oss-biz/pom.xml
new file mode 100644
index 0000000..8d011fd
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/pom.xml
@@ -0,0 +1,88 @@
+
+ 4.0.0
+
+
+ com.hanserwei
+ han-note-oss
+ ${revision}
+
+
+
+ jar
+
+ han-note-oss-biz
+ ${project.artifactId}
+ 对象存储业务层
+
+
+
+ com.hanserwei
+ hanserwei-common
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+ software.amazon.awssdk
+ s3
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+ javax.activation
+ activation
+
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+
+
+
+ com.qcloud
+ cos_api
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/HannoteOssBizApplication.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/HannoteOssBizApplication.java
new file mode 100644
index 0000000..b66c51e
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/HannoteOssBizApplication.java
@@ -0,0 +1,12 @@
+package com.hanserwei.hannote.oss;
+
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class HannoteOssBizApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(HannoteOssBizApplication.class, args);
+ }
+}
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSConfig.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSConfig.java
new file mode 100644
index 0000000..ebdb7aa
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSConfig.java
@@ -0,0 +1,31 @@
+package com.hanserwei.hannote.oss.config;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.common.auth.CredentialsProviderFactory;
+import com.aliyun.oss.common.auth.DefaultCredentialProvider;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AliyunOSSConfig {
+
+ @Resource
+ private AliyunOSSProperties aliyunOSSProperties;
+
+ /**
+ * 构建 阿里云 OSS 客户端
+ *
+ * @return 阿里云 OSS 客户端
+ */
+ @Bean
+ public OSS aliyunOSSClient() {
+ // 设置访问凭证
+ DefaultCredentialProvider credentialsProvider = CredentialsProviderFactory.newDefaultCredentialProvider(
+ aliyunOSSProperties.getAccessKey(), aliyunOSSProperties.getSecretKey());
+
+ // 创建 OSSClient 实例
+ return new OSSClientBuilder().build(aliyunOSSProperties.getEndpoint(), credentialsProvider);
+ }
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSProperties.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSProperties.java
new file mode 100644
index 0000000..c0cc8cf
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/AliyunOSSProperties.java
@@ -0,0 +1,14 @@
+package com.hanserwei.hannote.oss.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@ConfigurationProperties(prefix = "storage.aliyun-oss")
+@Component
+@Data
+public class AliyunOSSProperties {
+ private String endpoint;
+ private String accessKey;
+ private String secretKey;
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosConfig.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosConfig.java
new file mode 100644
index 0000000..27e5f7a
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosConfig.java
@@ -0,0 +1,48 @@
+package com.hanserwei.hannote.oss.config;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.endpoint.EndpointBuilder;
+import com.qcloud.cos.region.Region;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CosConfig {
+
+ @Resource
+ private CosProperties cosProperties;
+
+ @Bean
+ public COSClient cosClient() {
+ // 1. 初始化用户身份信息(SecretId, SecretKey)
+ COSCredentials cred = new BasicCOSCredentials(
+ cosProperties.getSecretId(),
+ cosProperties.getSecretKey()
+ );
+
+ // 2. 设置 bucket 的地域
+ Region region = new Region(cosProperties.getRegion());
+ ClientConfig clientConfig = new ClientConfig(region);
+ if (cosProperties.getEndpoint() != null && !cosProperties.getEndpoint().isEmpty()) {
+ clientConfig.setEndpointBuilder(new EndpointBuilder() {
+ @Override
+ public String buildGeneralApiEndpoint(String bucketName) {
+ // 所有 API 请求都会使用自定义域名
+ return cosProperties.getEndpoint();
+ }
+
+ @Override
+ public String buildGetServiceApiEndpoint() {
+ return cosProperties.getEndpoint();
+ }
+ });
+ }
+
+ // 3. 构建 COSClient
+ return new COSClient(cred, clientConfig);
+ }
+}
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosProperties.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosProperties.java
new file mode 100644
index 0000000..a9cc9f1
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/CosProperties.java
@@ -0,0 +1,16 @@
+package com.hanserwei.hannote.oss.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@Data
+@ConfigurationProperties(prefix = "storage.cos")
+public class CosProperties {
+ private String endpoint;
+ private String secretId;
+ private String secretKey;
+ private String appId;
+ private String region;
+}
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsConfig.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsConfig.java
new file mode 100644
index 0000000..469f387
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsConfig.java
@@ -0,0 +1,28 @@
+package com.hanserwei.hannote.oss.config;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
+
+import java.net.URI;
+
+@Configuration
+public class RustfsConfig {
+
+ @Resource
+ private RustfsProperties rustfsProperties;
+
+ @Bean
+ public S3Client minioClient() {
+ // 构建 Rustfs 客户端
+ return S3Client.builder()
+ .endpointOverride(URI.create(rustfsProperties.getEndpoint()))
+ .region(Region.US_EAST_1)
+ .credentialsProvider(() -> AwsBasicCredentials.create(rustfsProperties.getAccessKey(), rustfsProperties.getSecretKey()))
+ .forcePathStyle(true)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsProperties.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsProperties.java
new file mode 100644
index 0000000..7284e0b
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/config/RustfsProperties.java
@@ -0,0 +1,14 @@
+package com.hanserwei.hannote.oss.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@ConfigurationProperties(prefix = "storage.rustfs")
+@Component
+@Data
+public class RustfsProperties {
+ private String endpoint;
+ private String accessKey;
+ private String secretKey;
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/controller/FileController.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/controller/FileController.java
new file mode 100644
index 0000000..54748cb
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/controller/FileController.java
@@ -0,0 +1,27 @@
+package com.hanserwei.hannote.oss.controller;
+
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.oss.service.FileService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping("/file")
+@Slf4j
+public class FileController {
+
+ @Resource
+ private FileService fileService;
+
+ @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public Response> uploadFile(@RequestPart(value = "file") MultipartFile file) {
+ return fileService.uploadFile(file);
+ }
+
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/enums/ResponseCodeEnum.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/enums/ResponseCodeEnum.java
new file mode 100644
index 0000000..98bebb0
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/enums/ResponseCodeEnum.java
@@ -0,0 +1,23 @@
+package com.hanserwei.hannote.oss.enums;
+
+import com.hanserwei.framework.common.exception.BaseExceptionInterface;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum ResponseCodeEnum implements BaseExceptionInterface {
+
+ // ----------- 通用异常状态码 -----------
+ SYSTEM_ERROR("OSS-10000", "出错啦,后台小维正在努力修复中..."),
+ PARAM_NOT_VALID("OSS-10001", "参数错误!!!"),
+
+ // ----------- 业务异常状态码 -----------
+ ;
+
+ // 异常码
+ private final String errorCode;
+ // 错误信息
+ private final String errorMsg;
+
+}
\ No newline at end of file
diff --git a/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/exception/GlobalExceptionHandler.java b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..0d45e60
--- /dev/null
+++ b/han-note-oss/han-note-oss-biz/src/main/java/com/hanserwei/hannote/oss/exception/GlobalExceptionHandler.java
@@ -0,0 +1,103 @@
+package com.hanserwei.hannote.oss.exception;
+
+import com.hanserwei.framework.common.exception.ApiException;
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.oss.enums.ResponseCodeEnum;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Optional;
+
+@SuppressWarnings("LoggingSimilarMessage")
+@ControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+ /**
+ * 捕获自定义业务异常
+ *
+ * @return Response.fail(e)
+ */
+ @ExceptionHandler({ApiException.class})
+ @ResponseBody
+ public Response