diff --git a/pom.xml b/pom.xml
index 6710ef7..340d5d7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,7 @@
zkh-common
zkh-web
zkh-data
+ zkh-log
@@ -71,6 +72,11 @@
zkh-data
${project.version}
+
+ vip.jcfd
+ zkh-log
+ ${project.version}
+
org.springdoc
springdoc-openapi-common
diff --git a/zkh-data/pom.xml b/zkh-data/pom.xml
index 7bb4ad8..e15d51b 100644
--- a/zkh-data/pom.xml
+++ b/zkh-data/pom.xml
@@ -13,12 +13,6 @@
ZKH Data
Data layer components for ZKH framework
-
- 21
- 21
- UTF-8
-
-
jakarta.persistence
diff --git a/zkh-log/pom.xml b/zkh-log/pom.xml
new file mode 100644
index 0000000..960722d
--- /dev/null
+++ b/zkh-log/pom.xml
@@ -0,0 +1,23 @@
+
+
+ 4.0.0
+
+ vip.jcfd
+ zkh-framework
+ 1.4
+
+
+ zkh-log
+ ZKH log
+ Logging utilities for ZKH framework
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
diff --git a/zkh-log/src/main/java/vip/jcfd/log/annotation/Log.java b/zkh-log/src/main/java/vip/jcfd/log/annotation/Log.java
new file mode 100644
index 0000000..1c2d8c9
--- /dev/null
+++ b/zkh-log/src/main/java/vip/jcfd/log/annotation/Log.java
@@ -0,0 +1,10 @@
+package vip.jcfd.log.annotation;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Log {
+ String value();
+}
diff --git a/zkh-log/src/main/java/vip/jcfd/log/annotation/config/LogConfig.java b/zkh-log/src/main/java/vip/jcfd/log/annotation/config/LogConfig.java
new file mode 100644
index 0000000..498044d
--- /dev/null
+++ b/zkh-log/src/main/java/vip/jcfd/log/annotation/config/LogConfig.java
@@ -0,0 +1,7 @@
+package vip.jcfd.log.annotation.config;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration("_logConfiguration")
+public class LogConfig {
+}
diff --git a/zkh-web/pom.xml b/zkh-web/pom.xml
index 48b5718..5fed6dd 100644
--- a/zkh-web/pom.xml
+++ b/zkh-web/pom.xml
@@ -19,6 +19,10 @@
vip.jcfd
zkh-common
+
+ vip.jcfd
+ zkh-log
+
org.springframework.boot
spring-boot-starter-web
diff --git a/zkh-web/src/main/java/vip/jcfd/web/config/GlobalExceptionHandler.java b/zkh-web/src/main/java/vip/jcfd/web/config/GlobalExceptionHandler.java
index 0bea6c3..c6a9b2a 100644
--- a/zkh-web/src/main/java/vip/jcfd/web/config/GlobalExceptionHandler.java
+++ b/zkh-web/src/main/java/vip/jcfd/web/config/GlobalExceptionHandler.java
@@ -13,35 +13,35 @@ import vip.jcfd.common.core.R;
import java.util.List;
-@RestControllerAdvice
+@RestControllerAdvice("_globalExceptionHandler")
public class GlobalExceptionHandler {
- private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
- @ExceptionHandler(value = Exception.class)
- public R handleException(Exception e) {
- log.error("服务异常", e);
- return R.serverError("服务器繁忙,请稍候重试");
- }
+ @ExceptionHandler(value = Exception.class)
+ public R handleException(Exception e) {
+ log.error("服务异常", e);
+ return R.serverError("服务器繁忙,请稍候重试");
+ }
- @ExceptionHandler(value = BizException.class)
- public R handleBizException(BizException e) {
- log.error("业务异常", e);
- return R.error(e.getMessage());
- }
+ @ExceptionHandler(value = BizException.class)
+ public R handleBizException(BizException e) {
+ log.error("业务异常", e);
+ return R.error(e.getMessage());
+ }
- @ExceptionHandler(value = NoResourceFoundException.class)
- public R handleNotFoundException(NoResourceFoundException e) {
- log.error("404异常", e);
- return new R<>(404, "您访问的地址不存在", false, null);
- }
+ @ExceptionHandler(value = NoResourceFoundException.class)
+ public R handleNotFoundException(NoResourceFoundException e) {
+ log.error("404异常", e);
+ return new R<>(404, "您访问的地址不存在", false, null);
+ }
- @ExceptionHandler(value = BindException.class)
- public R handleBindException(BindException e) {
- log.error("接口入参校验失败", e);
+ @ExceptionHandler(value = BindException.class)
+ public R handleBindException(BindException e) {
+ log.error("接口入参校验失败", e);
- List fieldErrors = e.getBindingResult().getFieldErrors();
- return R.error(String.join("。\n", fieldErrors.stream().map(FieldError::getDefaultMessage).toList()));
- }
+ List fieldErrors = e.getBindingResult().getFieldErrors();
+ return R.error(String.join("。\n", fieldErrors.stream().map(FieldError::getDefaultMessage).toList()));
+ }
}
diff --git a/zkh-web/src/main/java/vip/jcfd/web/config/RedisConfig.java b/zkh-web/src/main/java/vip/jcfd/web/config/RedisConfig.java
index 98d4b97..1030922 100644
--- a/zkh-web/src/main/java/vip/jcfd/web/config/RedisConfig.java
+++ b/zkh-web/src/main/java/vip/jcfd/web/config/RedisConfig.java
@@ -10,26 +10,26 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
import vip.jcfd.web.config.props.SecurityProps;
import vip.jcfd.web.redis.TokenRedisStorage;
-@Configuration
+@Configuration("_redisConfiguration")
public class RedisConfig {
- private final SecurityProps securityProps;
+ private final SecurityProps securityProps;
- public RedisConfig(SecurityProps securityProps) {
- this.securityProps = securityProps;
- }
+ public RedisConfig(SecurityProps securityProps) {
+ this.securityProps = securityProps;
+ }
- @Bean
- public TokenRedisStorage tokenRedisTemplate(RedisConnectionFactory factory, StringRedisTemplate stringRedisTemplate, ObjectMapper objectMapper) {
- TokenRedisStorage tokenRedisStorage = new TokenRedisStorage(
- securityProps.getAccessTokenDuration(),
- securityProps.getRefreshTokenDuration(),
- stringRedisTemplate,
- objectMapper
- );
- tokenRedisStorage.setConnectionFactory(factory);
- tokenRedisStorage.setValueSerializer(new JdkSerializationRedisSerializer());
- tokenRedisStorage.setKeySerializer(new StringRedisSerializer());
- return tokenRedisStorage;
- }
+ @Bean
+ public TokenRedisStorage tokenRedisTemplate(RedisConnectionFactory factory, StringRedisTemplate stringRedisTemplate, ObjectMapper objectMapper) {
+ TokenRedisStorage tokenRedisStorage = new TokenRedisStorage(
+ securityProps.getAccessTokenDuration(),
+ securityProps.getRefreshTokenDuration(),
+ stringRedisTemplate,
+ objectMapper
+ );
+ tokenRedisStorage.setConnectionFactory(factory);
+ tokenRedisStorage.setValueSerializer(new JdkSerializationRedisSerializer());
+ tokenRedisStorage.setKeySerializer(new StringRedisSerializer());
+ return tokenRedisStorage;
+ }
}
diff --git a/zkh-web/src/main/java/vip/jcfd/web/config/SpringDocConfig.java b/zkh-web/src/main/java/vip/jcfd/web/config/SpringDocConfig.java
index 5c4026a..825c1d0 100644
--- a/zkh-web/src/main/java/vip/jcfd/web/config/SpringDocConfig.java
+++ b/zkh-web/src/main/java/vip/jcfd/web/config/SpringDocConfig.java
@@ -10,63 +10,63 @@ import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-@Configuration("_springDocConfig")
+@Configuration("_springDocConfiguration")
public class SpringDocConfig {
- @Bean
- public OpenApiCustomizer openApiCustomizer() {
- return (openAPI) -> {
- openAPI.path("/login", new PathItem()
- .post(new Operation()
- .summary("登录接口")
- .description("用于用户登录,返回token")
- .addTagsItem("认证管理")
- .requestBody(new RequestBody()
- .description("帐号密码")
- .required(true)
- .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
- .addProperty("username", new StringSchema().example("admin"))
- .addProperty("password", new StringSchema().example("123456"))))))
- .responses(new ApiResponses()
- .addApiResponse("成功", new ApiResponse()
- .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
- .addProperty("data", new JsonSchema()
- .addProperty("accessToken", new StringSchema().example("550e8400-e29b-41d4-a716-446655440000"))
- .addProperty("refreshToken", new StringSchema().example("550e8400-e29b-41d4-a716-446655440001"))
- .addProperty("tokenType", new StringSchema().example("Bearer"))
- .addProperty("expiresIn", new NumberSchema().example(1800))
- .addProperty("username", new StringSchema().example("admin"))
- )
- .addProperty("success", new BooleanSchema().example(true))
- .addProperty("code", new IntegerSchema().example(200))
- .addProperty("message", new StringSchema().example("登录成功"))
- ))))
- .addApiResponse("失败", new ApiResponse()
- .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
- .addProperty("data", new StringSchema().example(null))
- .addProperty("success", new BooleanSchema().example(false))
- .addProperty("code", new IntegerSchema().example(401))
- .addProperty("message", new StringSchema().example("用户名或密码错误"))
- ))))
- )));
- openAPI.path("/logout", new PathItem()
- .post(new Operation()
- .summary("登出接口")
- .description("用于用户登出")
- .addTagsItem("认证管理")
- .responses(new ApiResponses()
- .addApiResponse("成功", new ApiResponse()
- .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
- .addProperty("data", new StringSchema().example(null))
- .addProperty("success", new BooleanSchema().example(true))
- .addProperty("code", new IntegerSchema().example(200))
- .addProperty("message", new StringSchema().example("登出成功"))
- )
- )
- )
- )
- )
- ));
- };
- }
+ @Bean
+ public OpenApiCustomizer openApiCustomizer() {
+ return (openAPI) -> {
+ openAPI.path("/login", new PathItem()
+ .post(new Operation()
+ .summary("登录接口")
+ .description("用于用户登录,返回token")
+ .addTagsItem("认证管理")
+ .requestBody(new RequestBody()
+ .description("帐号密码")
+ .required(true)
+ .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
+ .addProperty("username", new StringSchema().example("admin"))
+ .addProperty("password", new StringSchema().example("123456"))))))
+ .responses(new ApiResponses()
+ .addApiResponse("成功", new ApiResponse()
+ .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
+ .addProperty("data", new JsonSchema()
+ .addProperty("accessToken", new StringSchema().example("550e8400-e29b-41d4-a716-446655440000"))
+ .addProperty("refreshToken", new StringSchema().example("550e8400-e29b-41d4-a716-446655440001"))
+ .addProperty("tokenType", new StringSchema().example("Bearer"))
+ .addProperty("expiresIn", new NumberSchema().example(1800))
+ .addProperty("username", new StringSchema().example("admin"))
+ )
+ .addProperty("success", new BooleanSchema().example(true))
+ .addProperty("code", new IntegerSchema().example(200))
+ .addProperty("message", new StringSchema().example("登录成功"))
+ ))))
+ .addApiResponse("失败", new ApiResponse()
+ .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
+ .addProperty("data", new StringSchema().example(null))
+ .addProperty("success", new BooleanSchema().example(false))
+ .addProperty("code", new IntegerSchema().example(401))
+ .addProperty("message", new StringSchema().example("用户名或密码错误"))
+ ))))
+ )));
+ openAPI.path("/logout", new PathItem()
+ .post(new Operation()
+ .summary("登出接口")
+ .description("用于用户登出")
+ .addTagsItem("认证管理")
+ .responses(new ApiResponses()
+ .addApiResponse("成功", new ApiResponse()
+ .content(new Content().addMediaType("application/json", new MediaType().schema(new Schema<>()
+ .addProperty("data", new StringSchema().example(null))
+ .addProperty("success", new BooleanSchema().example(true))
+ .addProperty("code", new IntegerSchema().example(200))
+ .addProperty("message", new StringSchema().example("登出成功"))
+ )
+ )
+ )
+ )
+ )
+ ));
+ };
+ }
}
diff --git a/zkh-web/src/main/java/vip/jcfd/web/config/WebSecurityConfig.java b/zkh-web/src/main/java/vip/jcfd/web/config/WebSecurityConfig.java
index e798166..1da13c6 100644
--- a/zkh-web/src/main/java/vip/jcfd/web/config/WebSecurityConfig.java
+++ b/zkh-web/src/main/java/vip/jcfd/web/config/WebSecurityConfig.java
@@ -52,7 +52,7 @@ import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
-@Configuration
+@Configuration("_webSecurityConfiguration")
@EnableWebSecurity
@ConfigurationPropertiesScan(basePackageClasses = {SecurityProps.class})
@EnableJpaAuditing
@@ -60,191 +60,191 @@ import java.util.UUID;
@EnableScheduling
public class WebSecurityConfig {
- private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);
- private final SecurityProps securityProps;
- private final ObjectMapper objectMapper;
- private final TokenRedisStorage tokenRedisStorage;
+ private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);
+ private final SecurityProps securityProps;
+ private final ObjectMapper objectMapper;
+ private final TokenRedisStorage tokenRedisStorage;
- public WebSecurityConfig(SecurityProps securityProps,
- ObjectMapper objectMapper,
- TokenRedisStorage tokenRedisStorage,
- AuthenticationManagerBuilder builder,
- UserDetailsService userDetailsService) {
- this.securityProps = securityProps;
- this.objectMapper = objectMapper;
- this.tokenRedisStorage = tokenRedisStorage;
- builder.authenticationProvider(new RefreshTokenAuthProvider(userDetailsService));
- DaoAuthenticationProvider authenticationProvider = new CustomDaoAuthenticationProvider(userDetailsService);
- authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
- builder.authenticationProvider(authenticationProvider);
- }
+ public WebSecurityConfig(SecurityProps securityProps,
+ ObjectMapper objectMapper,
+ TokenRedisStorage tokenRedisStorage,
+ AuthenticationManagerBuilder builder,
+ UserDetailsService userDetailsService) {
+ this.securityProps = securityProps;
+ this.objectMapper = objectMapper;
+ this.tokenRedisStorage = tokenRedisStorage;
+ builder.authenticationProvider(new RefreshTokenAuthProvider(userDetailsService));
+ DaoAuthenticationProvider authenticationProvider = new CustomDaoAuthenticationProvider(userDetailsService);
+ authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
+ builder.authenticationProvider(authenticationProvider);
+ }
- @Scheduled(cron = "0 */30 * * * *")
- @Async
- public void scheduleClearExpiredTokens() {
- tokenRedisStorage.clearExpiredTokens();
- }
+ @Scheduled(cron = "0 */30 * * * *")
+ @Async
+ public void scheduleClearExpiredTokens() {
+ tokenRedisStorage.clearExpiredTokens();
+ }
- @Bean
- public AuditorAware auditorAware() {
- return () -> Optional.ofNullable(SecurityContextHolder.getContext())
- .map(SecurityContext::getAuthentication)
- .map(Authentication::getName)
- .or(() -> Optional.of("system"));
- }
+ @Bean
+ public AuditorAware auditorAware() {
+ return () -> Optional.ofNullable(SecurityContextHolder.getContext())
+ .map(SecurityContext::getAuthentication)
+ .map(Authentication::getName)
+ .or(() -> Optional.of("system"));
+ }
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
- @Bean
- @ConditionalOnMissingBean
- public TokenFilter tokenFilter() {
- return new TokenFilter(tokenRedisStorage);
- }
+ @Bean
+ @ConditionalOnMissingBean
+ public TokenFilter tokenFilter() {
+ return new TokenFilter(tokenRedisStorage);
+ }
- @Bean
- public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
- return configuration.getAuthenticationManager();
- }
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
+ return configuration.getAuthenticationManager();
+ }
- @Bean
- public SecurityFilterChain security(HttpSecurity http, TokenFilter tokenFilter, AuthenticationManager authenticationManager) throws Exception {
- http.authorizeHttpRequests(config -> {
- config.requestMatchers(securityProps.getIgnoreUrls()).permitAll();
- config.anyRequest().authenticated();
- });
- CustomAuthenticationEntryPoint authenticationEntryPoint = new CustomAuthenticationEntryPoint(objectMapper, tokenRedisStorage);
- http.formLogin(config -> {
- config.loginProcessingUrl("/login");
- });
- http.csrf(AbstractHttpConfigurer::disable);
- http.logout(config -> {
- config.addLogoutHandler(new CustomLogoutSuccessHandler(objectMapper, tokenRedisStorage));
- });
- http.rememberMe(AbstractHttpConfigurer::disable);
- http.sessionManagement(AbstractHttpConfigurer::disable);
- http.exceptionHandling(config -> {
- config.authenticationEntryPoint(authenticationEntryPoint);
- config.accessDeniedHandler(new CustomAccessDeniedHandler(objectMapper));
- });
+ @Bean
+ public SecurityFilterChain security(HttpSecurity http, TokenFilter tokenFilter, AuthenticationManager authenticationManager) throws Exception {
+ http.authorizeHttpRequests(config -> {
+ config.requestMatchers(securityProps.getIgnoreUrls()).permitAll();
+ config.anyRequest().authenticated();
+ });
+ CustomAuthenticationEntryPoint authenticationEntryPoint = new CustomAuthenticationEntryPoint(objectMapper, tokenRedisStorage);
+ http.formLogin(config -> {
+ config.loginProcessingUrl("/login");
+ });
+ http.csrf(AbstractHttpConfigurer::disable);
+ http.logout(config -> {
+ config.addLogoutHandler(new CustomLogoutSuccessHandler(objectMapper, tokenRedisStorage));
+ });
+ http.rememberMe(AbstractHttpConfigurer::disable);
+ http.sessionManagement(AbstractHttpConfigurer::disable);
+ http.exceptionHandling(config -> {
+ config.authenticationEntryPoint(authenticationEntryPoint);
+ config.accessDeniedHandler(new CustomAccessDeniedHandler(objectMapper));
+ });
- http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
- JsonUsernamePasswordAuthenticationFilter filter = new JsonUsernamePasswordAuthenticationFilter(objectMapper, authenticationManager);
- filter.setAuthenticationSuccessHandler(authenticationEntryPoint);
- filter.setAuthenticationFailureHandler(authenticationEntryPoint);
- http.addFilterAt(filter, UsernamePasswordAuthenticationFilter.class);
- return http.build();
- }
+ http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
+ JsonUsernamePasswordAuthenticationFilter filter = new JsonUsernamePasswordAuthenticationFilter(objectMapper, authenticationManager);
+ filter.setAuthenticationSuccessHandler(authenticationEntryPoint);
+ filter.setAuthenticationFailureHandler(authenticationEntryPoint);
+ http.addFilterAt(filter, UsernamePasswordAuthenticationFilter.class);
+ return http.build();
+ }
- private record CustomAuthenticationEntryPoint(
- ObjectMapper objectMapper,
- TokenRedisStorage tokenRedisStorage) implements AuthenticationEntryPoint, AuthenticationFailureHandler, AuthenticationSuccessHandler {
- @Override
- public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
- log.warn("认证失败", authException);
- R