- 后端:替换 swagger bootstrap ui ,一下子接口文档好看了。
- 后端:增加 swagger AutoConfiguration 配置类 - 后端:统一访问日志的记录
This commit is contained in:
parent
3ff9f1b326
commit
53fff39a6c
@ -90,6 +90,12 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.skywalking</groupId>
|
||||||
|
<artifactId>apm-toolkit-trace</artifactId>
|
||||||
|
<version>6.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package cn.iocoder.common.framework.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mall 全局枚举
|
||||||
|
*/
|
||||||
|
public interface MallConstants {
|
||||||
|
|
||||||
|
// 全局请求路径枚举类,用于定义不同用户类型的根请求路径
|
||||||
|
/**
|
||||||
|
* 根路径 - 用户
|
||||||
|
*/
|
||||||
|
String ROOT_PATH_USER = "/users";
|
||||||
|
/**
|
||||||
|
* 根路径 - 管理员
|
||||||
|
*/
|
||||||
|
String ROOT_PATH_ADMIN = "/admins";
|
||||||
|
|
||||||
|
// 用户类型
|
||||||
|
/**
|
||||||
|
* 用户类型 - 用户
|
||||||
|
*/
|
||||||
|
Integer USER_TYPE_USER = 1;
|
||||||
|
/**
|
||||||
|
* 用户类型 - 管理员
|
||||||
|
*/
|
||||||
|
Integer USER_TYPE_ADMIN = 2;
|
||||||
|
|
||||||
|
// HTTP Request Attr
|
||||||
|
/**
|
||||||
|
* HTTP Request Attr - 用户编号
|
||||||
|
*/
|
||||||
|
String REQUEST_ATTR_USER_ID_KEY = "mall_user_id";
|
||||||
|
/**
|
||||||
|
* HTTP Request Attr - 用户类型
|
||||||
|
*/
|
||||||
|
String REQUEST_ATTR_USER_TYPE_KEY = "mall_user_type";
|
||||||
|
/**
|
||||||
|
* HTTP Request Attr - Controller 执行返回
|
||||||
|
*/
|
||||||
|
String REQUEST_ATTR_COMMON_RESULT = "mall_common_result";
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.common.framework.config;
|
package cn.iocoder.common.framework.exception;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
||||||
import cn.iocoder.common.framework.exception.ServiceException;
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
@ -5,6 +5,11 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cors 过滤器
|
||||||
|
*
|
||||||
|
* 未来使用 {@link org.springframework.web.filter.CorsFilter} 替换
|
||||||
|
*/
|
||||||
public class CorsFilter implements Filter {
|
public class CorsFilter implements Filter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,7 +44,7 @@ public class HttpUtil {
|
|||||||
*/
|
*/
|
||||||
public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
|
public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
|
||||||
|
|
||||||
public static String obtainAccess(HttpServletRequest request) {
|
public static String obtainAuthorization(HttpServletRequest request) {
|
||||||
String authorization = request.getHeader("Authorization");
|
String authorization = request.getHeader("Authorization");
|
||||||
if (!StringUtils.hasText(authorization)) {
|
if (!StringUtils.hasText(authorization)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package cn.iocoder.common.framework.util;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class MallUtil {
|
||||||
|
|
||||||
|
public static Integer getUserId(ServletRequest request) {
|
||||||
|
return (Integer) request.getAttribute(MallConstants.REQUEST_ATTR_USER_ID_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUserId(ServletRequest request, Integer userId) {
|
||||||
|
request.setAttribute(MallConstants.REQUEST_ATTR_USER_ID_KEY, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getUserType(ServletRequest request) {
|
||||||
|
return (Integer) request.getAttribute(MallConstants.REQUEST_ATTR_USER_TYPE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUserType(ServletRequest request, Integer userType) {
|
||||||
|
request.setAttribute(MallConstants.REQUEST_ATTR_USER_TYPE_KEY, userType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CommonResult getCommonResult(ServletRequest request) {
|
||||||
|
return (CommonResult) request.getAttribute(MallConstants.REQUEST_ATTR_COMMON_RESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCommonResult(ServletRequest request, CommonResult result) {
|
||||||
|
request.setAttribute(MallConstants.REQUEST_ATTR_COMMON_RESULT, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得链路追踪编号
|
||||||
|
*
|
||||||
|
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
||||||
|
*
|
||||||
|
* 默认情况下,我们使用 Apache SkyWalking 的 traceId 作为链路追踪编号。当然,可能会存在并未引入 Skywalking 的情况,此时使用 UUID 。
|
||||||
|
*
|
||||||
|
* @return 链路追踪编号
|
||||||
|
*/
|
||||||
|
public static String getTraceId() {
|
||||||
|
String traceId = TraceContext.traceId();
|
||||||
|
if (StringUtil.hasText(traceId)) {
|
||||||
|
return traceId;
|
||||||
|
}
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class CommonResult<T> implements Serializable {
|
public final class CommonResult<T> implements Serializable {
|
||||||
|
|
||||||
public static Integer CODE_SUCCESS = 0;
|
public static Integer CODE_SUCCESS = 0;
|
||||||
|
|
||||||
|
@ -47,6 +47,17 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package cn.iocoder.mall.spring.boot.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全局请求路径枚举类,用于定义不同用户类型的根请求路径
|
|
||||||
*/
|
|
||||||
public interface RootRequestPath {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员
|
|
||||||
*/
|
|
||||||
String ADMIN = "/admins";
|
|
||||||
/**
|
|
||||||
* 用户
|
|
||||||
*/
|
|
||||||
String USER = "/users";
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,57 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.swagger;
|
||||||
|
|
||||||
|
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
|
||||||
|
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.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||||
|
import springfox.documentation.service.ApiInfo;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简单的 Swagger2 自动配置类
|
||||||
|
*
|
||||||
|
* 较为完善的,可以了解 https://mvnrepository.com/artifact/com.spring4all/spring-boot-starter-swagger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2
|
||||||
|
@EnableSwaggerBootstrapUI
|
||||||
|
@ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
|
||||||
|
@ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true) // 允许使用 swagger.enable=false 禁用 Swagger
|
||||||
|
@EnableConfigurationProperties(SwaggerProperties.class)
|
||||||
|
public class SwaggerAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SwaggerProperties swaggerProperties() {
|
||||||
|
return new SwaggerProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Docket createRestApi() {
|
||||||
|
SwaggerProperties properties = swaggerProperties();
|
||||||
|
// 创建 Docket 对象
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.apiInfo(apiInfo(properties))
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage(properties.getBasePackage()))
|
||||||
|
.paths(PathSelectors.any())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiInfo apiInfo(SwaggerProperties properties) {
|
||||||
|
return new ApiInfoBuilder()
|
||||||
|
.title(properties.getTitle())
|
||||||
|
.description(properties.getDescription())
|
||||||
|
.version(properties.getVersion())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.swagger;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties("swagger")
|
||||||
|
public class SwaggerProperties {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private String description;
|
||||||
|
private String version;
|
||||||
|
private String basePackage;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.web;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
|
import cn.iocoder.common.framework.servlet.CorsFilter;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.interceptor.AccessLogInterceptor;
|
||||||
|
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.handler.GlobalResponseBodyHandler;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // TODO 芋艿,未来可能考虑 REACTIVE
|
||||||
|
@ConditionalOnClass({DispatcherServlet.class, WebMvcConfigurer.class, // 有 Spring MVC 容器
|
||||||
|
AdminSecurityInterceptor.class, AccessLogInterceptor.class}) // 有引入 system-sdk
|
||||||
|
public class AdminMVCAutoConfiguration implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
// @ConditionalOnMissingBean(AccessLogInterceptor.class)
|
||||||
|
public AccessLogInterceptor adminAccessLogInterceptor() {
|
||||||
|
return new AccessLogInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(AdminSecurityInterceptor.class)
|
||||||
|
public AdminSecurityInterceptor adminSecurityInterceptor() {
|
||||||
|
return new AdminSecurityInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(GlobalResponseBodyHandler.class)
|
||||||
|
public GlobalResponseBodyHandler globalReturnValueHandler() {
|
||||||
|
return new GlobalResponseBodyHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(GlobalResponseBodyHandler.class)
|
||||||
|
public GlobalExceptionHandler globalExceptionHandler() {
|
||||||
|
return new GlobalExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(adminAccessLogInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**");
|
||||||
|
registry.addInterceptor(adminSecurityInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_ADMIN + "/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
||||||
|
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
|
||||||
|
registrationBean.setFilter(new CorsFilter());
|
||||||
|
registrationBean.addUrlPatterns("/*");
|
||||||
|
return registrationBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
package cn.iocoder.mall.spring.boot.web;
|
|
||||||
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminAccessLogInterceptor;
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
|
||||||
import cn.iocoder.mall.spring.boot.constant.RootRequestPath;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // TODO 芋艿,未来可能考虑 REACTIVE
|
|
||||||
@ConditionalOnClass({DispatcherServlet.class, WebMvcConfigurer.class, // 有 Spring MVC 容器
|
|
||||||
AdminSecurityInterceptor.class, AdminAccessLogInterceptor.class}) // 有引入 system-sdk
|
|
||||||
public class AdminMVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(AdminSecurityInterceptor.class)
|
|
||||||
public AdminSecurityInterceptor adminSecurityInterceptor() {
|
|
||||||
return new AdminSecurityInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(AdminAccessLogInterceptor.class)
|
|
||||||
public AdminAccessLogInterceptor adminAccessLogInterceptor() {
|
|
||||||
return new AdminAccessLogInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
registry.addInterceptor(adminAccessLogInterceptor()).addPathPatterns(RootRequestPath.ADMIN + "/**");
|
|
||||||
registry.addInterceptor(adminSecurityInterceptor()).addPathPatterns(RootRequestPath.ADMIN + "/**");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping(RootRequestPath.USER + "/**")
|
|
||||||
.allowedOrigins("*")
|
|
||||||
.allowedMethods("*")
|
|
||||||
.allowedHeaders("*")
|
|
||||||
.allowCredentials(true).maxAge(1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,65 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.web;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
|
import cn.iocoder.common.framework.servlet.CorsFilter;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.interceptor.AccessLogInterceptor;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.handler.GlobalExceptionHandler;
|
||||||
|
import cn.iocoder.mall.spring.boot.web.handler.GlobalResponseBodyHandler;
|
||||||
|
import cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // TODO 芋艿,未来可能考虑 REACTIVE
|
||||||
|
@ConditionalOnClass({DispatcherServlet.class, WebMvcConfigurer.class, // 有 Spring MVC 容器
|
||||||
|
UserSecurityInterceptor.class, // 有引入 user-sdk
|
||||||
|
AccessLogInterceptor.class}) // 有引入 system-sdk
|
||||||
|
public class UserMVCAutoConfiguration implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
// @ConditionalOnMissingBean(AccessLogInterceptor.class)
|
||||||
|
public AccessLogInterceptor userAccessLogInterceptor() {
|
||||||
|
return new AccessLogInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(UserSecurityInterceptor.class)
|
||||||
|
public UserSecurityInterceptor userSecurityInterceptor() {
|
||||||
|
return new UserSecurityInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(GlobalResponseBodyHandler.class)
|
||||||
|
public GlobalResponseBodyHandler globalReturnValueHandler() {
|
||||||
|
return new GlobalResponseBodyHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(GlobalExceptionHandler.class)
|
||||||
|
public GlobalExceptionHandler globalExceptionHandler() {
|
||||||
|
return new GlobalExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(userAccessLogInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_USER + "/**");
|
||||||
|
registry.addInterceptor(userSecurityInterceptor()).addPathPatterns(MallConstants.ROOT_PATH_USER + "/**");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
||||||
|
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
|
||||||
|
registrationBean.setFilter(new CorsFilter());
|
||||||
|
registrationBean.addUrlPatterns("/*");
|
||||||
|
return registrationBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
package cn.iocoder.mall.spring.boot.web;
|
|
||||||
|
|
||||||
import cn.iocoder.mall.spring.boot.constant.RootRequestPath;
|
|
||||||
import cn.iocoder.mall.user.sdk.interceptor.UserAccessLogInterceptor;
|
|
||||||
import cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // TODO 芋艿,未来可能考虑 REACTIVE
|
|
||||||
@ConditionalOnClass({DispatcherServlet.class, WebMvcConfigurer.class, // 有 Spring MVC 容器
|
|
||||||
UserSecurityInterceptor.class, UserAccessLogInterceptor.class}) // 有引入 system-sdk
|
|
||||||
public class UserMVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(UserAccessLogInterceptor.class)
|
|
||||||
public UserAccessLogInterceptor userAccessLogInterceptor() {
|
|
||||||
return new UserAccessLogInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(UserSecurityInterceptor.class)
|
|
||||||
public UserSecurityInterceptor userSecurityInterceptor() {
|
|
||||||
return new UserSecurityInterceptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
registry.addInterceptor(userAccessLogInterceptor()).addPathPatterns(RootRequestPath.USER + "/**");
|
|
||||||
registry.addInterceptor(userSecurityInterceptor()).addPathPatterns(RootRequestPath.USER + "/**");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping(RootRequestPath.USER + "/**")
|
|
||||||
.allowedOrigins("*")
|
|
||||||
.allowedMethods("*")
|
|
||||||
.allowedHeaders("*")
|
|
||||||
.allowCredentials(true).maxAge(1800);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.web.handler;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
||||||
|
import cn.iocoder.common.framework.exception.ServiceException;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
// 逻辑异常
|
||||||
|
@ResponseBody
|
||||||
|
@ExceptionHandler(value = ServiceException.class)
|
||||||
|
public CommonResult serviceExceptionHandler(HttpServletRequest req, ServiceException ex) {
|
||||||
|
logger.debug("[serviceExceptionHandler]", ex);
|
||||||
|
return CommonResult.error(ex.getCode(), ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spring MVC 参数不正确
|
||||||
|
@ResponseBody
|
||||||
|
@ExceptionHandler(value = MissingServletRequestParameterException.class)
|
||||||
|
public CommonResult missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
|
||||||
|
logger.warn("[missingServletRequestParameterExceptionHandler]", ex);
|
||||||
|
return CommonResult.error(SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getCode(), SysErrorCodeEnum.MISSING_REQUEST_PARAM_ERROR.getMessage() + ":" + ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@ExceptionHandler(value = ConstraintViolationException.class)
|
||||||
|
public CommonResult constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
|
||||||
|
logger.info("[constraintViolationExceptionHandler]", ex);
|
||||||
|
// TODO 芋艿,后续要想一个更好的方式。
|
||||||
|
// 拼接详细报错
|
||||||
|
StringBuilder detailMessage = new StringBuilder("\n\n详细错误如下:");
|
||||||
|
ex.getConstraintViolations().forEach(constraintViolation -> detailMessage.append("\n").append(constraintViolation.getMessage()));
|
||||||
|
return CommonResult.error(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getMessage()
|
||||||
|
+ detailMessage.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@ExceptionHandler(value = Exception.class)
|
||||||
|
public CommonResult resultExceptionHandler(HttpServletRequest req, Exception e) {
|
||||||
|
logger.error("[resultExceptionHandler]", e);
|
||||||
|
// 返回
|
||||||
|
try {
|
||||||
|
addExceptionLog();
|
||||||
|
} catch (Throwable th) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
return CommonResult.error(SysErrorCodeEnum.SYS_ERROR.getCode(), SysErrorCodeEnum.SYS_ERROR.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿,应该还有其它的异常,需要进行翻译
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void addExceptionLog() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.web.handler;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.util.MallUtil;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
|
import org.springframework.http.server.ServletServerHttpRequest;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(MethodParameter returnType, Class converterType) {
|
||||||
|
if (returnType.getMethod() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return returnType.getMethod().getReturnType().isAssignableFrom(CommonResult.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
|
||||||
|
ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
MallUtil.setCommonResult(((ServletServerHttpRequest) request).getServletRequest(), (CommonResult) body);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package cn.iocoder.mall.spring.boot.web.interceptor;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
|
import cn.iocoder.common.framework.util.MallUtil;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.admin.api.SystemLogService;
|
||||||
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.apache.dubbo.config.annotation.Reference;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问日志拦截器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AccessLogInterceptor extends HandlerInterceptorAdapter {
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Date> START_TIME = new ThreadLocal<>();
|
||||||
|
|
||||||
|
@Reference(validation = "true", version = "${dubbo.consumer.AdminAccessLogService.version:1.0.0}")
|
||||||
|
private SystemLogService adminAccessLogService;
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String applicationName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
|
// 记录当前时间
|
||||||
|
START_TIME.set(new Date());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
|
AccessLogAddDTO accessLog = new AccessLogAddDTO();
|
||||||
|
try {
|
||||||
|
// 设置用户编号
|
||||||
|
accessLog.setUserId(MallUtil.getUserId(request));
|
||||||
|
if (accessLog.getUserId() == null) {
|
||||||
|
accessLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
|
||||||
|
}
|
||||||
|
accessLog.setUserType(MallUtil.getUserType(request));
|
||||||
|
// 设置访问结果
|
||||||
|
CommonResult result = MallUtil.getCommonResult(request);
|
||||||
|
Assert.isTrue(result != null, "result 必须非空");
|
||||||
|
accessLog.setErrorCode(result.getCode())
|
||||||
|
.setErrorMessage(result.getMessage());
|
||||||
|
// 设置其它字段
|
||||||
|
accessLog.setTraceId(MallUtil.getTraceId())
|
||||||
|
.setApplicationName(applicationName)
|
||||||
|
.setUri(request.getRequestURI()) // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
||||||
|
.setQueryString(HttpUtil.buildQueryString(request))
|
||||||
|
.setMethod(request.getMethod())
|
||||||
|
.setUserAgent(HttpUtil.getUserAgent(request))
|
||||||
|
.setIp(HttpUtil.getIp(request))
|
||||||
|
.setStartTime(START_TIME.get())
|
||||||
|
.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime())); // 默认响应时间设为 0
|
||||||
|
// 执行插入
|
||||||
|
addAccessLog(accessLog);
|
||||||
|
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
||||||
|
} catch (Throwable th) {
|
||||||
|
logger.error("[afterCompletion][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
||||||
|
} finally {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async // 异步入库
|
||||||
|
public void addAccessLog(AccessLogAddDTO accessLog) {
|
||||||
|
try {
|
||||||
|
adminAccessLogService.addAccessLog(accessLog);
|
||||||
|
} catch (Throwable th) {
|
||||||
|
logger.error("[addAccessLog][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clear() {
|
||||||
|
START_TIME.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
cn.iocoder.mall.spring.boot.web.AdminMVCConfiguration, \
|
cn.iocoder.mall.spring.boot.web.AdminMVCAutoConfiguration, \
|
||||||
cn.iocoder.mall.spring.boot.web.UserMVCConfiguration
|
cn.iocoder.mall.spring.boot.web.UserMVCAutoConfiguration, \
|
||||||
|
cn.iocoder.mall.spring.boot.swagger.SwaggerAutoConfiguration
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.iocoder.mall.order.application.config;
|
package cn.iocoder.mall.order.application.config;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
import cn.iocoder.common.framework.exception.GlobalExceptionHandler;
|
||||||
import cn.iocoder.common.framework.servlet.CorsFilter;
|
import cn.iocoder.common.framework.servlet.CorsFilter;
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
||||||
import cn.iocoder.mall.user.sdk.interceptor.UserAccessLogInterceptor;
|
import cn.iocoder.mall.user.sdk.interceptor.UserAccessLogInterceptor;
|
||||||
@ -49,12 +49,4 @@ public class MVCConfiguration implements WebMvcConfigurer {
|
|||||||
return registrationBean;
|
return registrationBean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 芋艿,允许跨域
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/**")
|
|
||||||
.allowedHeaders("*")
|
|
||||||
.allowedMethods("*")
|
|
||||||
.allowedOrigins("*");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
<artifactId>common-framework</artifactId>
|
<artifactId>common-framework</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>mall-spring-boot</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
<artifactId>pay-service-impl</artifactId>
|
<artifactId>pay-service-impl</artifactId>
|
||||||
@ -63,8 +68,9 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2,8 +2,10 @@ package cn.iocoder.mall.pay.application;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.pay"})
|
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.pay"})
|
||||||
|
@EnableAsync(proxyTargetClass = true)
|
||||||
public class PayApplication {
|
public class PayApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
package cn.iocoder.mall.pay.application.config;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@EnableWebMvc
|
|
||||||
@Configuration
|
|
||||||
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
|
|
||||||
// AdminSecurityInterceptor.class
|
|
||||||
})
|
|
||||||
public class MVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private UserSecurityInterceptor securityInterceptor;
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private AdminSecurityInterceptor adminSecurityInterceptor;
|
|
||||||
////
|
|
||||||
// @Override
|
|
||||||
// public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
//// registry.addInterceptor(securityInterceptor).addPathPatterns("/user/**", "/admin/**"); // 只拦截我们定义的接口
|
|
||||||
// registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**")
|
|
||||||
// .excludePathPatterns("/admins/passport/login"); // 排除登陆接口
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO 芋艿,允许跨域
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/**")
|
|
||||||
.allowedHeaders("*")
|
|
||||||
.allowedMethods("*")
|
|
||||||
.allowedOrigins("*");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package cn.iocoder.mall.pay.application.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2 // TODO 生产环境时,禁用掉。
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("cn.iocoder.mall.pay.application.controller"))
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiInfo() {
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
.title("支付子系统")
|
|
||||||
.description("支付子系统")
|
|
||||||
.termsOfServiceUrl("http://www.iocoder.cn")
|
|
||||||
.version("1.0.0")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,3 +7,9 @@ server:
|
|||||||
port: 18084
|
port: 18084
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /pay-api/
|
context-path: /pay-api/
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 支付子系统
|
||||||
|
description: 支付子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.pay.application.controller
|
||||||
|
14
pom.xml
14
pom.xml
@ -37,6 +37,7 @@
|
|||||||
<!-- <curator.version>4.0.1</curator.version>-->
|
<!-- <curator.version>4.0.1</curator.version>-->
|
||||||
<!-- <zookeeper.version>3.4.14</zookeeper.version>-->
|
<!-- <zookeeper.version>3.4.14</zookeeper.version>-->
|
||||||
<springfox-swagger.version>2.9.2</springfox-swagger.version>
|
<springfox-swagger.version>2.9.2</springfox-swagger.version>
|
||||||
|
<swagger-bootstrap-ui.version>1.9.3</swagger-bootstrap-ui.version>
|
||||||
<mybatis-spring-boot-starter.version>2.0.0</mybatis-spring-boot-starter.version>
|
<mybatis-spring-boot-starter.version>2.0.0</mybatis-spring-boot-starter.version>
|
||||||
<xxl-job.version>2.0.1</xxl-job.version>
|
<xxl-job.version>2.0.1</xxl-job.version>
|
||||||
<guava.version>27.0.1-jre</guava.version>
|
<guava.version>27.0.1-jre</guava.version>
|
||||||
@ -129,6 +130,11 @@
|
|||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>springfox-swagger-ui</artifactId>
|
||||||
<version>${springfox-swagger.version}</version>
|
<version>${springfox-swagger.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
|
<version>${swagger-bootstrap-ui.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mybatis.spring.boot</groupId>
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
@ -184,6 +190,14 @@
|
|||||||
<version>${qiniu.version}</version>
|
<version>${qiniu.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>servlet-api</artifactId>
|
||||||
|
<!-- <scope>provided</scope>-->
|
||||||
|
<version>2.5</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
<artifactId>common-framework</artifactId>
|
<artifactId>common-framework</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>mall-spring-boot</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
<artifactId>product-service-api</artifactId>
|
<artifactId>product-service-api</artifactId>
|
||||||
@ -60,11 +65,10 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -2,8 +2,10 @@ package cn.iocoder.mall.product.application;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.product"})
|
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.product"})
|
||||||
|
@EnableAsync(proxyTargetClass = true)
|
||||||
public class ProductApplication {
|
public class ProductApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package cn.iocoder.mall.product.application.config;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
|
||||||
import cn.iocoder.common.framework.servlet.CorsFilter;
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminAccessLogInterceptor;
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@EnableWebMvc
|
|
||||||
@Configuration
|
|
||||||
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
|
|
||||||
AdminSecurityInterceptor.class, AdminAccessLogInterceptor.class})
|
|
||||||
public class MVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AdminSecurityInterceptor adminSecurityInterceptor;
|
|
||||||
@Autowired
|
|
||||||
private AdminAccessLogInterceptor adminAccessLogInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
// registry.addInterceptor(securityInterceptor);
|
|
||||||
registry.addInterceptor(adminAccessLogInterceptor).addPathPatterns("/admins/**");
|
|
||||||
registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
|
||||||
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
|
|
||||||
registrationBean.setFilter(new CorsFilter());
|
|
||||||
registrationBean.addUrlPatterns("/*");
|
|
||||||
return registrationBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package cn.iocoder.mall.product.application.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("cn.iocoder.mall.product.application.controller"))
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiInfo() {
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
.title("商品子系统")
|
|
||||||
.description("商品子系统")
|
|
||||||
.termsOfServiceUrl("http://www.iocoder.cn")
|
|
||||||
.version("1.0.0")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,3 +7,9 @@ server:
|
|||||||
port: 18081
|
port: 18081
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /product-api/
|
context-path: /product-api/
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 商品子系统
|
||||||
|
description: 商品子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.product.application.controller
|
||||||
|
@ -31,6 +31,8 @@ dubbo:
|
|||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
ProductSpuService:
|
ProductSpuService:
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
OAuth2Service:
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
# rocketmq
|
# rocketmq
|
||||||
rocketmq:
|
rocketmq:
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>product-service-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
<artifactId>promotion-service-api</artifactId>
|
<artifactId>promotion-service-api</artifactId>
|
||||||
@ -59,14 +64,8 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
|
||||||
<artifactId>product-service-api</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
package cn.iocoder.mall.promotion.application.config;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
|
||||||
import cn.iocoder.common.framework.servlet.CorsFilter;
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminAccessLogInterceptor;
|
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
|
||||||
import cn.iocoder.mall.user.sdk.interceptor.UserAccessLogInterceptor;
|
|
||||||
import cn.iocoder.mall.user.sdk.interceptor.UserSecurityInterceptor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@EnableWebMvc
|
|
||||||
@Configuration
|
|
||||||
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
|
|
||||||
AdminSecurityInterceptor.class, UserAccessLogInterceptor.class,
|
|
||||||
UserSecurityInterceptor.class, AdminAccessLogInterceptor.class,
|
|
||||||
})
|
|
||||||
public class MVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private UserSecurityInterceptor securityInterceptor;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private UserSecurityInterceptor userSecurityInterceptor;
|
|
||||||
@Autowired
|
|
||||||
private UserAccessLogInterceptor userAccessLogInterceptor;
|
|
||||||
@Autowired
|
|
||||||
private AdminSecurityInterceptor adminSecurityInterceptor;
|
|
||||||
@Autowired
|
|
||||||
private AdminAccessLogInterceptor adminAccessLogInterceptor;
|
|
||||||
//
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
// 用户
|
|
||||||
registry.addInterceptor(userAccessLogInterceptor).addPathPatterns("/users/**");
|
|
||||||
registry.addInterceptor(userSecurityInterceptor).addPathPatterns("/users/**"); // 只拦截我们定义的接口
|
|
||||||
// 管理员
|
|
||||||
// registry.addInterceptor(adminAccessLogInterceptor).addPathPatterns("/admins/**");
|
|
||||||
registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
|
||||||
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
|
|
||||||
registrationBean.setFilter(new CorsFilter());
|
|
||||||
registrationBean.addUrlPatterns("/*");
|
|
||||||
return registrationBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,3 +7,9 @@ server:
|
|||||||
port: 18085
|
port: 18085
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /promotion-api/
|
context-path: /promotion-api/
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 营销子系统
|
||||||
|
description: 营销子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.promotion.application.controller
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
<artifactId>common-framework</artifactId>
|
<artifactId>common-framework</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
|
<artifactId>mall-spring-boot</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.iocoder.mall</groupId>
|
<groupId>cn.iocoder.mall</groupId>
|
||||||
<artifactId>user-sdk</artifactId>
|
<artifactId>user-sdk</artifactId>
|
||||||
@ -48,8 +53,8 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2,8 +2,10 @@ package cn.iocoder.mall.search.application;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.search"})
|
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.search"})
|
||||||
|
@EnableAsync(proxyTargetClass = true)
|
||||||
public class SearchApplication {
|
public class SearchApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
package cn.iocoder.mall.search.application.config;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
|
||||||
import cn.iocoder.common.framework.servlet.CorsFilter;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@EnableWebMvc
|
|
||||||
@Configuration
|
|
||||||
@Import(value = {GlobalExceptionHandler.class, // 统一全局返回
|
|
||||||
// AdminSecurityInterceptor.class, UserAccessLogInterceptor.class,
|
|
||||||
// UserSecurityInterceptor.class, AdminAccessLogInterceptor.class,
|
|
||||||
})
|
|
||||||
public class MVCConfiguration implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private UserSecurityInterceptor securityInterceptor;
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private UserSecurityInterceptor userSecurityInterceptor;
|
|
||||||
// @Autowired
|
|
||||||
// private UserAccessLogInterceptor userAccessLogInterceptor;
|
|
||||||
// @Autowired
|
|
||||||
// private AdminSecurityInterceptor adminSecurityInterceptor;
|
|
||||||
// @Autowired
|
|
||||||
// private AdminAccessLogInterceptor adminAccessLogInterceptor;
|
|
||||||
//
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
// // 用户
|
|
||||||
// registry.addInterceptor(userAccessLogInterceptor).addPathPatterns("/users/**");
|
|
||||||
// registry.addInterceptor(userSecurityInterceptor).addPathPatterns("/users/**"); // 只拦截我们定义的接口
|
|
||||||
// // 管理员
|
|
||||||
// registry.addInterceptor(adminAccessLogInterceptor).addPathPatterns("/admins/**");
|
|
||||||
// registry.addInterceptor(adminSecurityInterceptor).addPathPatterns("/admins/**");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
|
||||||
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
|
|
||||||
registrationBean.setFilter(new CorsFilter());
|
|
||||||
registrationBean.addUrlPatterns("/*");
|
|
||||||
return registrationBean;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package cn.iocoder.mall.search.application.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2 // TODO 生产环境时,禁用掉。
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("cn.iocoder.mall.search.application.controller"))
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiInfo() {
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
.title("搜索子系统")
|
|
||||||
.description("搜索子系统")
|
|
||||||
.termsOfServiceUrl("http://www.iocoder.cn")
|
|
||||||
.version("1.0.0")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,3 +7,9 @@ server:
|
|||||||
port: 18086
|
port: 18086
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /search-api/
|
context-path: /search-api/
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 搜索子系统
|
||||||
|
description: 搜索子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.search.application.controller
|
||||||
|
@ -50,8 +50,9 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
|
@ -3,9 +3,10 @@ package cn.iocoder.mall.admin.application;
|
|||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.admin"})
|
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.admin"})
|
||||||
//@EnableAdminServer
|
@EnableAsync(proxyTargetClass = true)
|
||||||
public class AdminApplication {
|
public class AdminApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.application.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2 // TODO 生产环境时,禁用掉。
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("cn.iocoder.mall.admin.application.controller"))
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiInfo() {
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
.title("管理员子系统")
|
|
||||||
.description("管理员子系统")
|
|
||||||
.termsOfServiceUrl("http://www.iocoder.cn")
|
|
||||||
.version("1.0.0")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -18,7 +18,7 @@ import cn.iocoder.mall.admin.application.vo.AdminPageVO;
|
|||||||
import cn.iocoder.mall.admin.application.vo.AdminRoleVO;
|
import cn.iocoder.mall.admin.application.vo.AdminRoleVO;
|
||||||
import cn.iocoder.mall.admin.application.vo.AdminVO;
|
import cn.iocoder.mall.admin.application.vo.AdminVO;
|
||||||
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
||||||
import cn.iocoder.mall.spring.boot.constant.RootRequestPath;
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiImplicitParams;
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
@ -30,7 +30,7 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(RootRequestPath.ADMIN + "/admin")
|
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/admin")
|
||||||
@Api("管理员模块")
|
@Api("管理员模块")
|
||||||
public class AdminController {
|
public class AdminController {
|
||||||
|
|
||||||
|
@ -13,3 +13,6 @@ management:
|
|||||||
include: "*"
|
include: "*"
|
||||||
server:
|
server:
|
||||||
port: 19083 # 配置独立端口。而该端口,不使用 nginx 对外暴露,从而不配置安全认证。也就是说,内网环境可访问,外网环境不可访问。当然,这么做的前提是,认为内网安全。
|
port: 19083 # 配置独立端口。而该端口,不使用 nginx 对外暴露,从而不配置安全认证。也就是说,内网环境可访问,外网环境不可访问。当然,这么做的前提是,认为内网安全。
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
enable: true # 暂时不去掉
|
||||||
|
@ -17,3 +17,9 @@ qiniu:
|
|||||||
access-key: YldfyUC7OewoWM63TPYTairqnq8GMJvNek9EGoID
|
access-key: YldfyUC7OewoWM63TPYTairqnq8GMJvNek9EGoID
|
||||||
secret-key: zZ7Q8wwZRyaklVvkyLmVydA4WygOBqtc_gTYzalS
|
secret-key: zZ7Q8wwZRyaklVvkyLmVydA4WygOBqtc_gTYzalS
|
||||||
bucket: onemall
|
bucket: onemall
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 管理员子系统
|
||||||
|
description: 管理员子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.admin.application.controller
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.sdk.interceptor;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.util.HttpUtil;
|
|
||||||
import cn.iocoder.mall.admin.api.AdminAccessLogService;
|
|
||||||
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import org.apache.dubbo.config.annotation.Reference;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 访问日志拦截器
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class AdminAccessLogInterceptor extends HandlerInterceptorAdapter {
|
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始时间
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Date> START_TIME = new ThreadLocal<>();
|
|
||||||
/**
|
|
||||||
* 管理员编号
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Integer> ADMIN_ID = new ThreadLocal<>();
|
|
||||||
|
|
||||||
@Reference(validation = "true", version = "${dubbo.consumer.AdminAccessLogService.version:1.0.0}")
|
|
||||||
private AdminAccessLogService adminAccessLogService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
|
||||||
// 记录当前时间
|
|
||||||
START_TIME.set(new Date());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
|
||||||
if (adminAccessLogService == null) {
|
|
||||||
throw new IllegalStateException("AdminAccessLogService 服务未引入成功");
|
|
||||||
}
|
|
||||||
AdminAccessLogAddDTO accessLog = new AdminAccessLogAddDTO();
|
|
||||||
try {
|
|
||||||
accessLog.setAdminId(ADMIN_ID.get());
|
|
||||||
if (accessLog.getAdminId() == null) {
|
|
||||||
accessLog.setAdminId(AdminAccessLogAddDTO.ADMIN_ID_NULL);
|
|
||||||
}
|
|
||||||
accessLog.setUri(request.getRequestURI()); // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
|
||||||
accessLog.setQueryString(HttpUtil.buildQueryString(request));
|
|
||||||
accessLog.setMethod(request.getMethod());
|
|
||||||
accessLog.setUserAgent(HttpUtil.getUserAgent(request));
|
|
||||||
accessLog.setIp(HttpUtil.getIp(request));
|
|
||||||
accessLog.setStartTime(START_TIME.get());
|
|
||||||
accessLog.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime()));// 默认响应时间设为0
|
|
||||||
adminAccessLogService.addAdminAccessLog(accessLog);
|
|
||||||
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
|
||||||
} catch (Throwable th) {
|
|
||||||
logger.error("[afterCompletion][插入管理员访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
|
||||||
} finally {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAdminId(Integer adminId) {
|
|
||||||
ADMIN_ID.set(adminId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clear() {
|
|
||||||
START_TIME.remove();
|
|
||||||
ADMIN_ID.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
package cn.iocoder.mall.admin.sdk.interceptor;
|
package cn.iocoder.mall.admin.sdk.interceptor;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
import cn.iocoder.common.framework.exception.ServiceException;
|
import cn.iocoder.common.framework.exception.ServiceException;
|
||||||
import cn.iocoder.common.framework.util.HttpUtil;
|
import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
|
import cn.iocoder.common.framework.util.MallUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||||
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
|
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
|
||||||
@ -39,8 +41,10 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
// 设置当前访问的用户类型。注意,即使未登陆,我们也认为是管理员
|
||||||
|
MallUtil.setUserType(request, MallConstants.USER_TYPE_ADMIN);
|
||||||
// 校验访问令牌是否正确。若正确,返回授权信息
|
// 校验访问令牌是否正确。若正确,返回授权信息
|
||||||
String accessToken = HttpUtil.obtainAccess(request);
|
String accessToken = HttpUtil.obtainAuthorization(request);
|
||||||
OAuth2AuthenticationBO authentication = null;
|
OAuth2AuthenticationBO authentication = null;
|
||||||
if (accessToken != null) {
|
if (accessToken != null) {
|
||||||
CommonResult<OAuth2AuthenticationBO> result = oauth2Service.checkToken(accessToken);
|
CommonResult<OAuth2AuthenticationBO> result = oauth2Service.checkToken(accessToken);
|
||||||
@ -60,7 +64,7 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
|
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
|
||||||
// 因此,这里需要进行记录
|
// 因此,这里需要进行记录
|
||||||
if (authentication.getAdminId() != null) {
|
if (authentication.getAdminId() != null) {
|
||||||
AdminAccessLogInterceptor.setAdminId(authentication.getAdminId());
|
MallUtil.setUserId(request, authentication.getAdminId());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String url = request.getRequestURI();
|
String url = request.getRequestURI();
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.api;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
|
||||||
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员访问日志 Service 接口
|
|
||||||
*/
|
|
||||||
public interface AdminAccessLogService {
|
|
||||||
|
|
||||||
CommonResult<Boolean> addAdminAccessLog(AdminAccessLogAddDTO adminAccessLogAddDTO);
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
package cn.iocoder.mall.admin.api;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统日志 Service 接口
|
||||||
|
*
|
||||||
|
* 例如说,访问日志、错误日志、操作日志等等
|
||||||
|
*/
|
||||||
|
public interface SystemLogService {
|
||||||
|
|
||||||
|
void addAccessLog(AccessLogAddDTO accessLogAddDTO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package cn.iocoder.mall.admin.api.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问日志添加 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class AccessLogAddDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号 - 空
|
||||||
|
*/
|
||||||
|
public static final Integer USER_ID_NULL = 0;
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*
|
||||||
|
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
||||||
|
*/
|
||||||
|
@NotNull(message = "链路追踪编号不能为空")
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 用户编号.
|
||||||
|
*
|
||||||
|
* 当管理员为空时,该值为 {@link #USER_ID_NULL}
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Integer userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户类型不能为空")
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*
|
||||||
|
* 目前读取 spring.application.name
|
||||||
|
*/
|
||||||
|
@NotNull(message = "应用名不能为空")
|
||||||
|
private String applicationName;
|
||||||
|
/**
|
||||||
|
* 访问地址
|
||||||
|
*/
|
||||||
|
@NotNull(message = "访问地址不能为空")
|
||||||
|
private String uri;
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
@NotNull(message = "请求参数不能为空")
|
||||||
|
private String queryString;
|
||||||
|
/**
|
||||||
|
* http 方法
|
||||||
|
*/
|
||||||
|
@NotNull(message = "http 请求方法不能为空")
|
||||||
|
private String method;
|
||||||
|
/**
|
||||||
|
* User Agent
|
||||||
|
*/
|
||||||
|
@NotNull(message = "User-Agent 不能为空")
|
||||||
|
private String userAgent;
|
||||||
|
/**
|
||||||
|
* ip
|
||||||
|
*/
|
||||||
|
@NotNull(message = "ip 不能为空")
|
||||||
|
private String ip;
|
||||||
|
/**
|
||||||
|
* 请求时间
|
||||||
|
*/
|
||||||
|
@NotNull(message = "请求时间不能为空")
|
||||||
|
private Date startTime;
|
||||||
|
/**
|
||||||
|
* 响应时长 -- 毫秒级
|
||||||
|
*/
|
||||||
|
@NotNull(message = "响应时长不能为空")
|
||||||
|
private Integer responseTime;
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*
|
||||||
|
* 目前的结果,是使用 {@link CommonResult#getCode()} 属性
|
||||||
|
*/
|
||||||
|
@NotNull(message = "错误码不能为空")
|
||||||
|
private Integer errorCode;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*
|
||||||
|
* 目前的结果,是使用 {@link CommonResult#getMessage()} 属性
|
||||||
|
*/
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.api.dto;
|
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员访问日志添加 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class AdminAccessLogAddDTO implements Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员编号 - 空
|
|
||||||
*/
|
|
||||||
public static final Integer ADMIN_ID_NULL = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员编号.
|
|
||||||
*
|
|
||||||
* 当管理员为空时,该值为0
|
|
||||||
*/
|
|
||||||
@NotNull(message = "管理员编号不能为空")
|
|
||||||
private Integer adminId;
|
|
||||||
/**
|
|
||||||
* 访问地址
|
|
||||||
*/
|
|
||||||
@NotNull(message = "访问地址不能为空")
|
|
||||||
private String uri;
|
|
||||||
/**
|
|
||||||
* 参数
|
|
||||||
*/
|
|
||||||
@NotNull(message = "请求参数不能为空")
|
|
||||||
private String queryString;
|
|
||||||
/**
|
|
||||||
* http 方法
|
|
||||||
*/
|
|
||||||
@NotNull(message = "http 请求方法不能为空")
|
|
||||||
private String method;
|
|
||||||
/**
|
|
||||||
* User Agent
|
|
||||||
*/
|
|
||||||
@NotNull(message = "User-Agent 不能为空")
|
|
||||||
private String userAgent;
|
|
||||||
/**
|
|
||||||
* ip
|
|
||||||
*/
|
|
||||||
@NotNull(message = "ip 不能为空")
|
|
||||||
private String ip;
|
|
||||||
/**
|
|
||||||
* 请求时间
|
|
||||||
*/
|
|
||||||
@NotNull(message = "请求时间不能为空")
|
|
||||||
private Date startTime;
|
|
||||||
/**
|
|
||||||
* 响应时长 -- 毫秒级
|
|
||||||
*/
|
|
||||||
@NotNull(message = "响应时长不能为空")
|
|
||||||
private Integer responseTime;
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,17 @@
|
|||||||
|
package cn.iocoder.mall.admin.convert;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface AccessLogConvert {
|
||||||
|
|
||||||
|
AccessLogConvert INSTANCE = Mappers.getMapper(AccessLogConvert.class);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
AccessLogDO convert(AccessLogAddDTO accessLogAddDTO);
|
||||||
|
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.convert;
|
|
||||||
|
|
||||||
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
|
|
||||||
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.Mappings;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
@Mapper
|
|
||||||
public interface AdminAccessLogConvert {
|
|
||||||
|
|
||||||
AdminAccessLogConvert INSTANCE = Mappers.getMapper(AdminAccessLogConvert.class);
|
|
||||||
|
|
||||||
@Mappings({})
|
|
||||||
AdminAccessLogDO convert(AdminAccessLogAddDTO adminAccessLogAddDTO);
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,11 @@
|
|||||||
|
package cn.iocoder.mall.admin.dao;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AccessLogMapper {
|
||||||
|
|
||||||
|
void insert(AccessLogDO entity);
|
||||||
|
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.dao;
|
|
||||||
|
|
||||||
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public interface AdminAccessLogMapper {
|
|
||||||
|
|
||||||
void insert(AdminAccessLogDO entity);
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,84 @@
|
|||||||
|
package cn.iocoder.mall.admin.dataobject;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员访问日志 DO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class AccessLogDO extends DeletableDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*
|
||||||
|
* 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
|
||||||
|
*/
|
||||||
|
private String traceId;
|
||||||
|
/**
|
||||||
|
* 用户编号.
|
||||||
|
*
|
||||||
|
* 当管理员为空时,该值为 {@link cn.iocoder.mall.admin.api.dto.AccessLogAddDTO#USER_ID_NULL}
|
||||||
|
*/
|
||||||
|
private Integer userId;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
private Integer userType;
|
||||||
|
/**
|
||||||
|
* 应用名
|
||||||
|
*
|
||||||
|
* 目前读取 spring.application.name
|
||||||
|
*/
|
||||||
|
private String applicationName;
|
||||||
|
/**
|
||||||
|
* 访问地址
|
||||||
|
*/
|
||||||
|
private String uri;
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
private String queryString;
|
||||||
|
/**
|
||||||
|
* http 方法
|
||||||
|
*/
|
||||||
|
private String method;
|
||||||
|
/**
|
||||||
|
* userAgent
|
||||||
|
*/
|
||||||
|
private String userAgent;
|
||||||
|
/**
|
||||||
|
* ip
|
||||||
|
*/
|
||||||
|
private String ip;
|
||||||
|
/**
|
||||||
|
* 请求时间
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
/**
|
||||||
|
* 响应时长 -- 毫秒级
|
||||||
|
*/
|
||||||
|
private Integer responseTime;
|
||||||
|
/**
|
||||||
|
* 错误码
|
||||||
|
*
|
||||||
|
* 目前的结果,是使用 {@link CommonResult#getCode()} 属性
|
||||||
|
*/
|
||||||
|
private Integer errorCode;
|
||||||
|
/**
|
||||||
|
* 错误提示
|
||||||
|
*
|
||||||
|
* 目前的结果,是使用 {@link CommonResult#getMessage()} 属性
|
||||||
|
*/
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
package cn.iocoder.mall.admin.dataobject;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员访问日志 DO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class AdminAccessLogDO extends DeletableDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编号
|
|
||||||
*/
|
|
||||||
private Integer id;
|
|
||||||
/**
|
|
||||||
* 管理员编号.
|
|
||||||
*
|
|
||||||
* 当管理员为空时,该值为0
|
|
||||||
*/
|
|
||||||
private Integer adminId;
|
|
||||||
/**
|
|
||||||
* 访问地址
|
|
||||||
*/
|
|
||||||
private String uri;
|
|
||||||
/**
|
|
||||||
* 参数
|
|
||||||
*/
|
|
||||||
private String queryString;
|
|
||||||
/**
|
|
||||||
* http 方法
|
|
||||||
*/
|
|
||||||
private String method;
|
|
||||||
/**
|
|
||||||
* userAgent
|
|
||||||
*/
|
|
||||||
private String userAgent;
|
|
||||||
/**
|
|
||||||
* ip
|
|
||||||
*/
|
|
||||||
private String ip;
|
|
||||||
/**
|
|
||||||
* 请求时间
|
|
||||||
*/
|
|
||||||
private Date startTime;
|
|
||||||
/**
|
|
||||||
* 响应时长 -- 毫秒级
|
|
||||||
*/
|
|
||||||
private Integer responseTime;
|
|
||||||
|
|
||||||
}
|
|
@ -1,12 +1,11 @@
|
|||||||
package cn.iocoder.mall.admin.service;
|
package cn.iocoder.mall.admin.service;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.util.StringUtil;
|
import cn.iocoder.common.framework.util.StringUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.mall.admin.api.SystemLogService;
|
||||||
import cn.iocoder.mall.admin.api.AdminAccessLogService;
|
import cn.iocoder.mall.admin.api.dto.AccessLogAddDTO;
|
||||||
import cn.iocoder.mall.admin.api.dto.AdminAccessLogAddDTO;
|
import cn.iocoder.mall.admin.convert.AccessLogConvert;
|
||||||
import cn.iocoder.mall.admin.convert.AdminAccessLogConvert;
|
import cn.iocoder.mall.admin.dao.AccessLogMapper;
|
||||||
import cn.iocoder.mall.admin.dao.AdminAccessLogMapper;
|
import cn.iocoder.mall.admin.dataobject.AccessLogDO;
|
||||||
import cn.iocoder.mall.admin.dataobject.AdminAccessLogDO;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ import java.util.Date;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.AdminAccessLogService.version}")
|
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.AdminAccessLogService.version}")
|
||||||
public class AdminAccessLogServiceImpl implements AdminAccessLogService {
|
public class SystemLogServiceImpl implements SystemLogService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求参数最大长度。
|
* 请求参数最大长度。
|
||||||
@ -30,12 +29,12 @@ public class AdminAccessLogServiceImpl implements AdminAccessLogService {
|
|||||||
private static final Integer USER_AGENT_MAX_LENGTH = 1024;
|
private static final Integer USER_AGENT_MAX_LENGTH = 1024;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AdminAccessLogMapper adminAccessLogMapper;
|
private AccessLogMapper accessLogMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<Boolean> addAdminAccessLog(AdminAccessLogAddDTO adminAccessLogAddDTO) {
|
public void addAccessLog(AccessLogAddDTO adminAccessLogAddDTO) {
|
||||||
// 创建 AdminAccessLogDO
|
// 创建 AdminAccessLogDO
|
||||||
AdminAccessLogDO accessLog = AdminAccessLogConvert.INSTANCE.convert(adminAccessLogAddDTO);
|
AccessLogDO accessLog = AccessLogConvert.INSTANCE.convert(adminAccessLogAddDTO);
|
||||||
accessLog.setCreateTime(new Date());
|
accessLog.setCreateTime(new Date());
|
||||||
// 截取最大长度
|
// 截取最大长度
|
||||||
if (accessLog.getUri().length() > URI_MAX_LENGTH) {
|
if (accessLog.getUri().length() > URI_MAX_LENGTH) {
|
||||||
@ -48,9 +47,7 @@ public class AdminAccessLogServiceImpl implements AdminAccessLogService {
|
|||||||
accessLog.setUserAgent(StringUtil.substring(accessLog.getUserAgent(), USER_AGENT_MAX_LENGTH));
|
accessLog.setUserAgent(StringUtil.substring(accessLog.getUserAgent(), USER_AGENT_MAX_LENGTH));
|
||||||
}
|
}
|
||||||
// 插入
|
// 插入
|
||||||
adminAccessLogMapper.insert(accessLog);
|
accessLogMapper.insert(accessLog);
|
||||||
// 返回成功
|
|
||||||
return CommonResult.success(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="cn.iocoder.mall.admin.dao.AccessLogMapper">
|
||||||
|
|
||||||
|
<!--<sql id="FIELDS">-->
|
||||||
|
<!--id, username, nickname, password, status,-->
|
||||||
|
<!--create_time-->
|
||||||
|
<!--</sql>-->
|
||||||
|
|
||||||
|
<insert id="insert" parameterType="AccessLogDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
||||||
|
INSERT INTO access_log (
|
||||||
|
trace_id, user_id, user_type, uri, query_string, method, user_agent,
|
||||||
|
ip, start_time, response_time, error_code, error_message, create_time
|
||||||
|
) VALUES (
|
||||||
|
#{traceId}, #{userId}, #{userType}, #{uri}, #{queryString}, #{method}, #{userAgent},
|
||||||
|
#{ip}, #{startTime}, #{responseTime}, #{errorCode}, #{errorMessage}, #{createTime}
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="cn.iocoder.mall.admin.dao.AdminAccessLogMapper">
|
|
||||||
|
|
||||||
<!--<sql id="FIELDS">-->
|
|
||||||
<!--id, username, nickname, password, status,-->
|
|
||||||
<!--create_time-->
|
|
||||||
<!--</sql>-->
|
|
||||||
|
|
||||||
<insert id="insert" parameterType="AdminAccessLogDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
|
||||||
INSERT INTO admin_access_log (
|
|
||||||
admin_id, uri, query_string, method, user_agent,
|
|
||||||
ip, start_time, response_time, create_time
|
|
||||||
) VALUES (
|
|
||||||
#{adminId}, #{uri}, #{queryString}, #{method}, #{userAgent},
|
|
||||||
#{ip}, #{startTime}, #{responseTime}, #{createTime}
|
|
||||||
)
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
</mapper>
|
|
@ -74,8 +74,8 @@
|
|||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>swagger-bootstrap-ui</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -2,9 +2,10 @@ package cn.iocoder.mall.user.application;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.user"})
|
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.user"})
|
||||||
|
@EnableAsync(proxyTargetClass = true)
|
||||||
public class UserApplication {
|
public class UserApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
package cn.iocoder.mall.user.application.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2
|
|
||||||
public class SwaggerConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("cn.iocoder.mall.user.application.controller"))
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApiInfo apiInfo() {
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
.title("用户子系统")
|
|
||||||
.description("用户子系统")
|
|
||||||
.termsOfServiceUrl("http://www.iocoder.cn")
|
|
||||||
.version("1.0.0")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,3 +7,9 @@ server:
|
|||||||
port: 18082
|
port: 18082
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /user-api/
|
context-path: /user-api/
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
title: 用户子系统
|
||||||
|
description: 用户子系统
|
||||||
|
version: 1.0.0
|
||||||
|
base-package: cn.iocoder.mall.user.application.controller
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
package cn.iocoder.mall.user.sdk.interceptor;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.util.HttpUtil;
|
|
||||||
import cn.iocoder.mall.user.api.UserAccessLogService;
|
|
||||||
import cn.iocoder.mall.user.api.dto.UserAccessLogAddDTO;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
|
||||||
import org.apache.dubbo.config.annotation.Reference;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 访问日志拦截器
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class UserAccessLogInterceptor extends HandlerInterceptorAdapter {
|
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始时间
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Date> START_TIME = new ThreadLocal<>();
|
|
||||||
/**
|
|
||||||
* 管理员编号
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<Integer> USER_ID = new ThreadLocal<>();
|
|
||||||
|
|
||||||
@Reference(validation = "true", version = "${dubbo.provider.UserAccessLogService.version:1.0.0}")
|
|
||||||
private UserAccessLogService userAccessLogService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
|
||||||
// TODO 芋艿,临时拿来处理 vue axios options 请求的问题。
|
|
||||||
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
|
|
||||||
|
|
||||||
return false; // 通过这样的方式,让前端知道允许的 header 等等。
|
|
||||||
}
|
|
||||||
// 记录当前时间
|
|
||||||
START_TIME.set(new Date());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
|
||||||
UserAccessLogAddDTO accessLog = new UserAccessLogAddDTO();
|
|
||||||
try {
|
|
||||||
accessLog.setUserId(USER_ID.get());
|
|
||||||
if (accessLog.getUserId() == null) {
|
|
||||||
accessLog.setUserId(UserAccessLogAddDTO.USER_ID_NULL);
|
|
||||||
}
|
|
||||||
accessLog.setUri(request.getRequestURI()); // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
|
||||||
accessLog.setQueryString(HttpUtil.buildQueryString(request));
|
|
||||||
accessLog.setMethod(request.getMethod());
|
|
||||||
accessLog.setUserAgent(HttpUtil.getUserAgent(request));
|
|
||||||
accessLog.setIp(HttpUtil.getIp(request));
|
|
||||||
accessLog.setStartTime(START_TIME.get());
|
|
||||||
accessLog.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime()));// 默认响应时间设为0
|
|
||||||
userAccessLogService.addUserAccessLog(accessLog);
|
|
||||||
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
|
||||||
} catch (Throwable th) {
|
|
||||||
logger.error("[afterCompletion][插入管理员访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
|
||||||
} finally {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setUserId(Integer userId) {
|
|
||||||
USER_ID.set(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clear() {
|
|
||||||
START_TIME.remove();
|
|
||||||
USER_ID.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
package cn.iocoder.mall.user.sdk.interceptor;
|
package cn.iocoder.mall.user.sdk.interceptor;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
import cn.iocoder.common.framework.exception.ServiceException;
|
import cn.iocoder.common.framework.exception.ServiceException;
|
||||||
import cn.iocoder.common.framework.util.HttpUtil;
|
import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
|
import cn.iocoder.common.framework.util.MallUtil;
|
||||||
import cn.iocoder.mall.user.api.OAuth2Service;
|
import cn.iocoder.mall.user.api.OAuth2Service;
|
||||||
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
import cn.iocoder.mall.user.api.bo.OAuth2AuthenticationBO;
|
||||||
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
import cn.iocoder.mall.user.sdk.annotation.PermitAll;
|
||||||
@ -26,8 +28,10 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
// 设置当前访问的用户类型。注意,即使未登陆,我们也认为是用户
|
||||||
|
MallUtil.setUserType(request, MallConstants.USER_TYPE_USER);
|
||||||
// 校验访问令牌是否正确。若正确,返回授权信息
|
// 校验访问令牌是否正确。若正确,返回授权信息
|
||||||
String accessToken = HttpUtil.obtainAccess(request);
|
String accessToken = HttpUtil.obtainAuthorization(request);
|
||||||
OAuth2AuthenticationBO authentication = null;
|
OAuth2AuthenticationBO authentication = null;
|
||||||
if (accessToken != null) {
|
if (accessToken != null) {
|
||||||
authentication = oauth2Service.checkToken(accessToken); // TODO 芋艿,如果访问的地址无需登录,这里也不用抛异常
|
authentication = oauth2Service.checkToken(accessToken); // TODO 芋艿,如果访问的地址无需登录,这里也不用抛异常
|
||||||
@ -39,7 +43,7 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
|
// AdminSecurityInterceptor 执行后,会移除 AdminSecurityContext 信息,这就导致 AdminAccessLogInterceptor 无法获得管理员编号
|
||||||
// 因此,这里需要进行记录
|
// 因此,这里需要进行记录
|
||||||
if (authentication.getUserId() != null) {
|
if (authentication.getUserId() != null) {
|
||||||
UserAccessLogInterceptor.setUserId(authentication.getUserId());
|
MallUtil.setUserId(request, authentication.getUserId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 校验是否需要已授权
|
// 校验是否需要已授权
|
||||||
|
Loading…
Reference in New Issue
Block a user