Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
6bcad5d5
提交
6bcad5d5
authored
4月 21, 2020
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
完善 Access Log 的记录
上级
cc969693
隐藏空白字符变更
内嵌
并排
正在显示
24 个修改的文件
包含
274 行增加
和
328 行删除
+274
-328
MallUtil.java
.../main/java/cn/iocoder/common/framework/util/MallUtil.java
+2
-0
pom.xml
common/mall-spring-boot-starter-swagger/pom.xml
+0
-2
pom.xml
common/mall-spring-boot-starter-web/pom.xml
+1
-0
CommonWebAutoConfiguration.java
...n/iocoder/mall/web/config/CommonWebAutoConfiguration.java
+35
-5
CommonMallConstants.java
...ava/cn/iocoder/mall/web/constant/CommonMallConstants.java
+30
-0
GlobalResponseBodyHandler.java
...n/iocoder/mall/web/handler/GlobalResponseBodyHandler.java
+43
-19
AccessLogInterceptor.java
...cn/iocoder/mall/web/interceptor/AccessLogInterceptor.java
+68
-84
CommonWebUtil.java
...src/main/java/cn/iocoder/mall/web/util/CommonWebUtil.java
+35
-0
SwaggerAutoConfiguration.java
...er/mall/spring/boot/swagger/SwaggerAutoConfiguration.java
+0
-58
SwaggerProperties.java
...n/iocoder/mall/spring/boot/swagger/SwaggerProperties.java
+0
-16
GlobalResponseBodyHandler.java
...ll/spring/boot/web/handler/GlobalResponseBodyHandler.java
+0
-31
AccessLogInterceptor.java
...all/spring/boot/web/interceptor/AccessLogInterceptor.java
+0
-102
spring.factories
...-spring-boot/src/main/resources/META-INF/spring.factories
+0
-1
application.yaml
...em/system-application/src/main/resources/application.yaml
+1
-1
AccessLogAddDTO.java
...n/iocoder/mall/system/biz/dto/system/AccessLogAddDTO.java
+5
-0
pom.xml
system/system-rpc-api/pom.xml
+5
-1
AccessLogAddRequest.java
...r/mall/system/rpc/request/system/AccessLogAddRequest.java
+11
-1
SystemLogRPCImpl.java
...java/cn/iocoder/mall/system/rpc/rpc/SystemLogRPCImpl.java
+1
-1
rpc.yaml
system/system-rpc/src/main/resources/rpc.yaml
+4
-0
pom.xml
user/user-rest/pom.xml
+8
-1
TestController.java
.../cn/iocoder/mall/user/rest/controller/TestController.java
+18
-0
package-info.java
...va/cn/iocoder/mall/user/rest/controller/package-info.java
+1
-0
package-info.java
...src/main/java/cn/iocoder/mall/user/rest/package-info.java
+1
-0
pom.xml
user/user-rpc/pom.xml
+5
-5
没有找到文件。
common/common-framework/src/main/java/cn/iocoder/common/framework/util/MallUtil.java
浏览文件 @
6bcad5d5
...
...
@@ -25,10 +25,12 @@ public class MallUtil {
request
.
setAttribute
(
MallConstants
.
REQUEST_ATTR_USER_TYPE_KEY
,
userType
);
}
@Deprecated
public
static
CommonResult
getCommonResult
(
ServletRequest
request
)
{
return
(
CommonResult
)
request
.
getAttribute
(
MallConstants
.
REQUEST_ATTR_COMMON_RESULT
);
}
@Deprecated
public
static
void
setCommonResult
(
ServletRequest
request
,
CommonResult
result
)
{
request
.
setAttribute
(
MallConstants
.
REQUEST_ATTR_COMMON_RESULT
,
result
);
}
...
...
common/mall-spring-boot-starter-swagger/pom.xml
浏览文件 @
6bcad5d5
...
...
@@ -12,8 +12,6 @@
<artifactId>
mall-spring-boot-starter-swagger
</artifactId>
<dependencies>
<!-- Spring 核心 -->
<dependency>
<groupId>
org.springframework.boot
</groupId>
...
...
common/mall-spring-boot-starter-web/pom.xml
浏览文件 @
6bcad5d5
...
...
@@ -17,6 +17,7 @@
<groupId>
cn.iocoder.mall
</groupId>
<artifactId>
system-rpc-api
</artifactId>
<version>
1.0-SNAPSHOT
</version>
<optional>
true
</optional>
</dependency>
<!-- Spring 核心 -->
...
...
common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/config/CommonWebAutoConfiguration.java
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
web
.
config
;
import
cn.iocoder.mall.web.constant.CommonMallConstants
;
import
cn.iocoder.mall.web.handler.GlobalResponseBodyHandler
;
import
cn.iocoder.mall.web.interceptor.AccessLogInterceptor
;
import
org.apache.dubbo.config.annotation.Reference
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.NoSuchBeanDefinitionException
;
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.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
;
@Configuration
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
SERVLET
)
// TODO 芋艿,未来可能考虑 REACTIVE
@ConditionalOnWebApplication
(
type
=
ConditionalOnWebApplication
.
Type
.
SERVLET
)
public
class
CommonWebAutoConfiguration
implements
WebMvcConfigurer
{
@Reference
(
validation
=
"true"
,
version
=
"${dubbo.consumer.AdminAccessLogService.version:1.0.0}"
)
// @Reference(validation = "true", version = "1.0.0")
// private SystemLogRPC systemLogRPC;
private
Logger
logger
=
LoggerFactory
.
getLogger
(
getClass
());
// ========== 全局处理器 ==========
@Bean
@ConditionalOnMissingBean
(
GlobalResponseBodyHandler
.
class
)
public
GlobalResponseBodyHandler
globalResponseBodyHandler
()
{
return
new
GlobalResponseBodyHandler
();
}
// ========== 拦截器相关 ==========
@Bean
@ConditionalOnClass
(
name
=
"cn.iocoder.mall.system.rpc.api.SystemLogRPC"
)
@ConditionalOnMissingBean
(
AccessLogInterceptor
.
class
)
public
AccessLogInterceptor
accessLogInterceptor
()
{
return
new
AccessLogInterceptor
();
}
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
try
{
AccessLogInterceptor
accessLogInterceptor
=
this
.
accessLogInterceptor
();
if
(
accessLogInterceptor
!=
null
)
{
registry
.
addInterceptor
(
accessLogInterceptor
)
.
addPathPatterns
(
CommonMallConstants
.
ROOT_PATH_ADMIN
+
"/**"
,
CommonMallConstants
.
ROOT_PATH_USER
+
"/**"
);
}
}
catch
(
NoSuchBeanDefinitionException
e
)
{
logger
.
warn
(
"[addInterceptors][无法获取 AccessLogInterceptor 拦截器,因此不启动 AccessLog 的记录]"
);
}
}
}
common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/constant/CommonMallConstants.java
0 → 100644
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
web
.
constant
;
public
interface
CommonMallConstants
{
// 全局请求路径枚举类,用于定义不同用户类型的根请求路径
/**
* 根路径 - 用户
*/
String
ROOT_PATH_USER
=
"/users"
;
/**
* 根路径 - 管理员
*/
String
ROOT_PATH_ADMIN
=
"/admins"
;
// HTTP Request Attr
/**
* HTTP Request Attr - 账号编号
*/
String
REQUEST_ATTR_USER_ID_KEY
=
"mall_account_id"
;
/**
* HTTP Request Attr - Controller 执行返回
*/
String
REQUEST_ATTR_COMMON_RESULT
=
"mall_common_result"
;
/**
* HTTP Request Attr - 访问开始时间
*/
String
REQUEST_ATTR_ACCESS_START_TIME
=
"mall_access_start_time"
;
}
common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/handler/GlobalResponseBodyHandler.java
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
web
.
handler
;
//@ControllerAdvice
//public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
//
// @Override
// public boolean supports(MethodParameter returnType, Class converterType) {
// if (returnType.getMethod() == null) {
// return false;
// }
// return returnType.getMethod().getReturnType() == 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;
// }
//
//}
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.web.util.CommonWebUtil
;
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
;
/**
* 全局响应结果(ResponseBody)处理器
*
* 不同于在网上看到的很多文章,会选择自动将 Controller 返回结果包上 {@link CommonResult},
* 在 onemall 中,是 Controller 在返回时,主动自己包上 {@link CommonResult}。
* 原因是,GlobalResponseBodyHandler 本质上是 AOP,它不应该改变 Controller 返回的数据结构
*
* 目前,GlobalResponseBodyHandler 的主要作用是,记录 Controller 的返回结果,
* 方便 {@link cn.iocoder.mall.web.interceptor.AccessLogInterceptor} 记录访问日志
*/
@ControllerAdvice
public
class
GlobalResponseBodyHandler
implements
ResponseBodyAdvice
{
@Override
@SuppressWarnings
(
"NullableProblems"
)
// 避免 IDEA 警告
public
boolean
supports
(
MethodParameter
returnType
,
Class
converterType
)
{
if
(
returnType
.
getMethod
()
==
null
)
{
return
false
;
}
// 只拦截返回结果为 CommonResult 类型
return
returnType
.
getMethod
().
getReturnType
()
==
CommonResult
.
class
;
}
@Override
@SuppressWarnings
(
"NullableProblems"
)
// 避免 IDEA 警告
public
Object
beforeBodyWrite
(
Object
body
,
MethodParameter
returnType
,
MediaType
selectedContentType
,
Class
selectedConverterType
,
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
// 记录 Controller 结果
CommonWebUtil
.
setCommonResult
(((
ServletServerHttpRequest
)
request
).
getServletRequest
(),
(
CommonResult
)
body
);
return
body
;
}
}
common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/interceptor/AccessLogInterceptor.java
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
web
.
interceptor
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContextAware
;
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.system.rpc.api.SystemLogRPC
;
import
cn.iocoder.mall.system.rpc.request.system.AccessLogAddRequest
;
import
cn.iocoder.mall.web.util.CommonWebUtil
;
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.util.Assert
;
import
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
java.util.Date
;
/**
* 访问日志拦截器
*/
public
class
AccessLogInterceptor
extends
HandlerInterceptorAdapter
implements
InitializingBean
,
ApplicationContextAware
{
public
class
AccessLogInterceptor
extends
HandlerInterceptorAdapter
{
private
Logger
logger
=
LoggerFactory
.
getLogger
(
getClass
());
private
ApplicationContext
context
;
@Reference
(
validation
=
"true"
,
version
=
"${dubbo.consumer.SystemLogRPC.version}"
)
private
SystemLogRPC
systemLogRPC
;
//
// 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 systemAccessLogService;
//
// @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
// initAccessLog(accessLog, request);
// // 执行插入 accessLog
// addAccessLog(accessLog);
// // TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
// } catch (Throwable th) {
// logger.error("[afterCompletion][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
// } finally {
// clear();
// }
// }
//
// private void initAccessLog(AccessLogAddDTO accessLog, HttpServletRequest request) {
// // 设置用户编号
// 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
// }
//
// @Async // 异步入库
// public void addAccessLog(AccessLogAddDTO accessLog) {
// try {
// systemAccessLogService.addAccessLog(accessLog);
// } catch (Throwable th) {
// logger.error("[addAccessLog][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
// }
// }
//
// private static void clear() {
// START_TIME.remove();
// }
//
@Value
(
"${spring.application.name}"
)
private
String
applicationName
;
@Override
public
void
setApplicationContext
(
ApplicationContext
context
)
throws
BeansException
{
this
.
context
=
context
;
public
boolean
preHandle
(
HttpServletRequest
request
,
HttpServletResponse
response
,
Object
handler
)
{
// 记录当前时间
CommonWebUtil
.
setAccessStartTime
(
request
,
new
Date
());
return
true
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
System
.
out
.
println
();
public
void
afterCompletion
(
HttpServletRequest
request
,
HttpServletResponse
response
,
Object
handler
,
Exception
ex
)
{
AccessLogAddRequest
accessLog
=
new
AccessLogAddRequest
();
try
{
// 初始化 accessLog
initAccessLog
(
accessLog
,
request
);
// 执行插入 accessLog
addAccessLog
(
accessLog
);
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
}
catch
(
Throwable
th
)
{
logger
.
error
(
"[afterCompletion][插入访问日志({}) 发生异常({})"
,
JSON
.
toJSONString
(
accessLog
),
ExceptionUtils
.
getRootCauseMessage
(
th
));
}
}
private
void
initAccessLog
(
AccessLogAddRequest
accessLog
,
HttpServletRequest
request
)
{
// 设置用户编号
accessLog
.
setAccountId
(
CommonWebUtil
.
getAccountId
(
request
));
// 设置访问结果
CommonResult
result
=
CommonWebUtil
.
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
(
CommonWebUtil
.
getAccessStartTime
(
request
))
.
setResponseTime
((
int
)
(
System
.
currentTimeMillis
()
-
accessLog
.
getStartTime
().
getTime
()));
// 默认响应时间设为 0
}
@Async
// 异步入库
public
void
addAccessLog
(
AccessLogAddRequest
accessLog
)
{
try
{
systemLogRPC
.
addAccessLog
(
accessLog
);
}
catch
(
Throwable
th
)
{
logger
.
error
(
"[addAccessLog][插入访问日志({}) 发生异常({})"
,
JSON
.
toJSONString
(
accessLog
),
ExceptionUtils
.
getRootCauseMessage
(
th
));
}
}
}
common/mall-spring-boot-starter-web/src/main/java/cn/iocoder/mall/web/util/CommonWebUtil.java
0 → 100644
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
web
.
util
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.web.constant.CommonMallConstants
;
import
javax.servlet.ServletRequest
;
import
java.util.Date
;
public
class
CommonWebUtil
{
public
static
Integer
getAccountId
(
ServletRequest
request
)
{
return
(
Integer
)
request
.
getAttribute
(
CommonMallConstants
.
REQUEST_ATTR_USER_ID_KEY
);
}
public
static
void
setAccountId
(
ServletRequest
request
,
Integer
userId
)
{
request
.
setAttribute
(
CommonMallConstants
.
REQUEST_ATTR_USER_ID_KEY
,
userId
);
}
public
static
CommonResult
getCommonResult
(
ServletRequest
request
)
{
return
(
CommonResult
)
request
.
getAttribute
(
CommonMallConstants
.
REQUEST_ATTR_COMMON_RESULT
);
}
public
static
void
setCommonResult
(
ServletRequest
request
,
CommonResult
result
)
{
request
.
setAttribute
(
CommonMallConstants
.
REQUEST_ATTR_COMMON_RESULT
,
result
);
}
public
static
void
setAccessStartTime
(
ServletRequest
request
,
Date
startTime
)
{
request
.
setAttribute
(
CommonMallConstants
.
REQUEST_ATTR_ACCESS_START_TIME
,
startTime
);
}
public
static
Date
getAccessStartTime
(
ServletRequest
request
)
{
return
(
Date
)
request
.
getAttribute
(
CommonMallConstants
.
REQUEST_ATTR_ACCESS_START_TIME
);
}
}
common/mall-spring-boot/src/main/java/cn/iocoder/mall/spring/boot/swagger/SwaggerAutoConfiguration.java
deleted
100644 → 0
浏览文件 @
cc969693
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
)
@Deprecated
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
();
}
}
common/mall-spring-boot/src/main/java/cn/iocoder/mall/spring/boot/swagger/SwaggerProperties.java
deleted
100644 → 0
浏览文件 @
cc969693
package
cn
.
iocoder
.
mall
.
spring
.
boot
.
swagger
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
@Data
@ConfigurationProperties
(
"swagger"
)
@Deprecated
public
class
SwaggerProperties
{
private
String
title
;
private
String
description
;
private
String
version
;
private
String
basePackage
;
}
common/mall-spring-boot/src/main/java/cn/iocoder/mall/spring/boot/web/handler/GlobalResponseBodyHandler.java
deleted
100644 → 0
浏览文件 @
cc969693
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
()
==
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
;
}
}
common/mall-spring-boot/src/main/java/cn/iocoder/mall/spring/boot/web/interceptor/AccessLogInterceptor.java
deleted
100644 → 0
浏览文件 @
cc969693
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.system.api.SystemLogService
;
import
cn.iocoder.mall.system.api.dto.systemlog.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
systemAccessLogService
;
@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
initAccessLog
(
accessLog
,
request
);
// 执行插入 accessLog
addAccessLog
(
accessLog
);
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
}
catch
(
Throwable
th
)
{
logger
.
error
(
"[afterCompletion][插入访问日志({}) 发生异常({})"
,
JSON
.
toJSONString
(
accessLog
),
ExceptionUtils
.
getRootCauseMessage
(
th
));
}
finally
{
clear
();
}
}
private
void
initAccessLog
(
AccessLogAddDTO
accessLog
,
HttpServletRequest
request
)
{
// 设置用户编号
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
}
@Async
// 异步入库
public
void
addAccessLog
(
AccessLogAddDTO
accessLog
)
{
try
{
systemAccessLogService
.
addAccessLog
(
accessLog
);
}
catch
(
Throwable
th
)
{
logger
.
error
(
"[addAccessLog][插入访问日志({}) 发生异常({})"
,
JSON
.
toJSONString
(
accessLog
),
ExceptionUtils
.
getRootCauseMessage
(
th
));
}
}
private
static
void
clear
()
{
START_TIME
.
remove
();
}
}
common/mall-spring-boot/src/main/resources/META-INF/spring.factories
浏览文件 @
6bcad5d5
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.iocoder.mall.spring.boot.web.AdminMVCAutoConfiguration, \
cn.iocoder.mall.spring.boot.web.UserMVCAutoConfiguration, \
cn.iocoder.mall.spring.boot.swagger.SwaggerAutoConfiguration, \
cn.iocoder.mall.spring.boot.metrics.MetricsAutoConfiguration
system/system-application/src/main/resources/application.yaml
浏览文件 @
6bcad5d5
spring
:
# Application 的配置项
application
:
name
:
admin
-application
name
:
system
-application
# Profile 的配置项
profiles
:
active
:
local
system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/system/AccessLogAddDTO.java
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
system
.
biz
.
dto
.
system
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
javax.validation.constraints.NotNull
;
import
java.util.Date
;
/**
* 访问日志添加 DTO
*/
@Data
@Accessors
(
chain
=
true
)
public
class
AccessLogAddDTO
{
/**
...
...
system/system-rpc-api/pom.xml
浏览文件 @
6bcad5d5
...
...
@@ -19,11 +19,15 @@
<version>
1.0-SNAPSHOT
</version>
</dependency>
<!-- 工具类 -->
<!-- 工具类
相关
-->
<dependency>
<groupId>
javax.validation
</groupId>
<artifactId>
validation-api
</artifactId>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
</dependencies>
...
...
system/system-rpc-api/src/main/java/cn/iocoder/mall/system/rpc/request/system/AccessLogAddRequest.java
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
system
.
rpc
.
request
.
system
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
javax.validation.constraints.NotNull
;
import
java.util.Date
;
/**
* 访问日志添加请求
*/
@Data
@Accessors
(
chain
=
true
)
public
class
AccessLogAddRequest
{
/**
...
...
@@ -10,7 +18,9 @@ public class AccessLogAddRequest {
*/
public
static
final
Integer
ACCOUNT_ID_NULL
=
0
;
@NotNull
(
message
=
"链路追踪编号不能为空"
)
/**
* 链路追踪编号
*/
private
String
traceId
;
/**
* 账号编号
...
...
system/system-rpc/src/main/java/cn/iocoder/mall/system/rpc/rpc/SystemLogRPCImpl.java
浏览文件 @
6bcad5d5
...
...
@@ -9,7 +9,7 @@ import cn.iocoder.mall.system.rpc.request.system.AccessLogAddRequest;
import
org.apache.dubbo.config.annotation.Service
;
import
org.springframework.beans.factory.annotation.Autowired
;
@Service
(
version
=
"
dubbo.provider.SystemLogRPC.version
"
,
validation
=
"true"
)
@Service
(
version
=
"
${dubbo.provider.SystemLogRPC.version}
"
,
validation
=
"true"
)
public
class
SystemLogRPCImpl
implements
SystemLogRPC
{
@Autowired
...
...
system/system-rpc/src/main/resources/rpc.yaml
浏览文件 @
6bcad5d5
...
...
@@ -15,3 +15,7 @@ dubbo:
filter
:
-exception
SystemLogRPC
:
version
:
1.0.0
# Dubbo 服务消费者的配置
consumer
:
SystemLogRPC
:
# 用于 AccessLogInterceptor 等拦截器,记录 HTTP API 请求的访问日志
version
:
1.0.0
user/user-rest/pom.xml
浏览文件 @
6bcad5d5
...
...
@@ -15,10 +15,17 @@
<!-- Mall 相关 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.mall</groupId>-->
<!-- <artifactId>
system
-biz</artifactId>-->
<!-- <artifactId>
user
-biz</artifactId>-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!-- </dependency>-->
<!-- Mall 相关 -->
<dependency>
<groupId>
cn.iocoder.mall
</groupId>
<artifactId>
common-framework
</artifactId>
<version>
1.0-SNAPSHOT
</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>
cn.iocoder.mall
</groupId>
...
...
user/user-rest/src/main/java/cn/iocoder/mall/user/rest/controller/TestController.java
0 → 100644
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
user
.
rest
.
controller
;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.web.constant.CommonMallConstants
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
@RestController
@RequestMapping
(
CommonMallConstants
.
ROOT_PATH_USER
+
"/test"
)
public
class
TestController
{
@GetMapping
(
"/echo"
)
public
CommonResult
<
Boolean
>
echo
()
{
return
CommonResult
.
success
(
true
);
}
}
user/user-rest/src/main/java/cn/iocoder/mall/user/rest/controller/package-info.java
0 → 100644
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
user
.
rest
.
controller
;
user/user-rest/src/main/java/cn/iocoder/mall/user/rest/package-info.java
0 → 100644
浏览文件 @
6bcad5d5
package
cn
.
iocoder
.
mall
.
user
.
rest
;
user/user-rpc/pom.xml
浏览文件 @
6bcad5d5
...
...
@@ -13,11 +13,11 @@
<dependencies>
<!-- Mall 相关 -->
<dependency
>
<groupId>
cn.iocoder.mall
</groupId
>
<artifactId>
system-rpc-api
</artifactId
>
<version>
1.0-SNAPSHOT
</version
>
</dependency
>
<!-- <dependency>--
>
<!-- <groupId>cn.iocoder.mall</groupId>--
>
<!-- <artifactId>system-rpc-api</artifactId>--
>
<!-- <version>1.0-SNAPSHOT</version>--
>
<!-- </dependency>--
>
<dependency>
<groupId>
cn.iocoder.mall
</groupId>
<artifactId>
user-rpc-api
</artifactId>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论