Finish system log
This commit is contained in:
15
src/main/kotlin/top/fatweb/api/config/SysLogConfig.kt
Normal file
15
src/main/kotlin/top/fatweb/api/config/SysLogConfig.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package top.fatweb.api.config
|
||||
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
||||
import top.fatweb.api.interceptor.SysLogInterceptor
|
||||
|
||||
@Configuration
|
||||
class SysLogConfig(
|
||||
private val sysLogInterceptor: SysLogInterceptor
|
||||
) : WebMvcConfigurer {
|
||||
override fun addInterceptors(registry: InterceptorRegistry) {
|
||||
registry.addInterceptor(sysLogInterceptor).addPathPatterns("/**").excludePathPatterns("/error/thrown")
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package top.fatweb.api.entity;
|
||||
package top.fatweb.api.entity
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.TableField
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import java.io.Serializable
|
||||
import java.time.LocalDateTime
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -96,7 +96,7 @@ class SysLog : Serializable {
|
||||
* 执行时间
|
||||
*/
|
||||
@TableField("execute_time")
|
||||
var executeTime: Int? = null
|
||||
var executeTime: Long? = null
|
||||
|
||||
/**
|
||||
* 用户代理
|
||||
@@ -104,19 +104,7 @@ class SysLog : Serializable {
|
||||
@TableField("user_agent")
|
||||
var userAgent: String? = null
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
@TableField("device_name")
|
||||
var deviceName: String? = null
|
||||
|
||||
/**
|
||||
* 浏览器名称
|
||||
*/
|
||||
@TableField("browser_name")
|
||||
var browserName: String? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "SysLog(id=$id, logType=$logType, operateUserId=$operateUserId, operateTime=$operateTime, requestUri=$requestUri, requestMethod=$requestMethod, requestParams=$requestParams, requestIp=$requestIp, requestServerAddress=$requestServerAddress, isException=$isException, exceptionInfo=$exceptionInfo, startTime=$startTime, endTime=$endTime, executeTime=$executeTime, userAgent=$userAgent, deviceName=$deviceName, browserName=$browserName)"
|
||||
return "SysLog(id=$id, logType=$logType, operateUserId=$operateUserId, operateTime=$operateTime, requestUri=$requestUri, requestMethod=$requestMethod, requestParams=$requestParams, requestIp=$requestIp, requestServerAddress=$requestServerAddress, isException=$isException, exceptionInfo=$exceptionInfo, startTime=$startTime, endTime=$endTime, executeTime=$executeTime, userAgent=$userAgent)"
|
||||
}
|
||||
}
|
||||
|
||||
110
src/main/kotlin/top/fatweb/api/interceptor/SysLogInterceptor.kt
Normal file
110
src/main/kotlin/top/fatweb/api/interceptor/SysLogInterceptor.kt
Normal file
@@ -0,0 +1,110 @@
|
||||
package top.fatweb.api.interceptor
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.core.MethodParameter
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.converter.HttpMessageConverter
|
||||
import org.springframework.http.server.ServerHttpRequest
|
||||
import org.springframework.http.server.ServerHttpResponse
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||
import org.springframework.web.servlet.HandlerInterceptor
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice
|
||||
import top.fatweb.api.entity.SysLog
|
||||
import top.fatweb.api.entity.common.ResponseResult
|
||||
import top.fatweb.api.service.ISysLogService
|
||||
import top.fatweb.api.util.WebUtil
|
||||
import java.net.URI
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@ControllerAdvice
|
||||
class SysLogInterceptor(
|
||||
val customThreadPoolTaskExecutor: Executor, val sysLogService: ISysLogService
|
||||
) : HandlerInterceptor, ResponseBodyAdvice<Any> {
|
||||
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||
private val sysLogThreadLocal = ThreadLocal<SysLog>()
|
||||
private val resultThreadLocal = ThreadLocal<Any>()
|
||||
|
||||
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
|
||||
val sysLog = SysLog().apply {
|
||||
operateUserId = WebUtil.getLoginUserId() ?: -1
|
||||
startTime = LocalDateTime.now(ZoneOffset.UTC)
|
||||
requestUri = URI(request.requestURI).path
|
||||
requestParams = formatParams(request.parameterMap)
|
||||
requestMethod = request.method
|
||||
requestIp = request.remoteAddr
|
||||
requestServerAddress = "${request.scheme}://${request.serverName}:${request.serverPort}"
|
||||
userAgent = request.getHeader("User-Agent")
|
||||
}
|
||||
|
||||
sysLogThreadLocal.set(sysLog)
|
||||
|
||||
logger.info("开始计时: {} URI: {} IP: {}", sysLog.startTime, sysLog.requestUri, sysLog.requestIp)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun afterCompletion(
|
||||
request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?
|
||||
) {
|
||||
val sysLog = sysLogThreadLocal.get()
|
||||
val result = resultThreadLocal.get()
|
||||
sysLog.endTime = LocalDateTime.now(ZoneOffset.UTC)
|
||||
sysLog.executeTime = ChronoUnit.MILLIS.between(sysLog.startTime, sysLog.endTime)
|
||||
if (result is ResponseResult<*>) {
|
||||
if (result.success) {
|
||||
sysLog.apply {
|
||||
logType = "INFO"
|
||||
isException = "N"
|
||||
}
|
||||
} else {
|
||||
sysLog.apply {
|
||||
logType = "ERROR"
|
||||
isException = "Y"
|
||||
exceptionInfo = result.msg
|
||||
}
|
||||
}
|
||||
|
||||
customThreadPoolTaskExecutor.execute(SaveLogThread(sysLog, sysLogService))
|
||||
}
|
||||
sysLogThreadLocal.remove()
|
||||
}
|
||||
|
||||
private fun formatParams(parameterMap: Map<String, Array<String>>): String {
|
||||
val params = StringJoiner("&")
|
||||
|
||||
parameterMap.forEach {
|
||||
params.add("${it.key}=${if (it.key.endsWith("password", true)) "*" else it.value.joinToString(",")}")
|
||||
}
|
||||
|
||||
return params.toString()
|
||||
}
|
||||
|
||||
private class SaveLogThread(val sysLog: SysLog, val sysLogService: ISysLogService) : Thread() {
|
||||
override fun run() {
|
||||
sysLog.operateTime = LocalDateTime.now(ZoneOffset.UTC)
|
||||
sysLogService.save(sysLog)
|
||||
}
|
||||
}
|
||||
|
||||
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
|
||||
true
|
||||
|
||||
override fun beforeBodyWrite(
|
||||
body: Any?,
|
||||
returnType: MethodParameter,
|
||||
selectedContentType: MediaType,
|
||||
selectedConverterType: Class<out HttpMessageConverter<*>>,
|
||||
request: ServerHttpRequest,
|
||||
response: ServerHttpResponse
|
||||
): Any? {
|
||||
resultThreadLocal.set(body)
|
||||
return body
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import org.springframework.stereotype.Service
|
||||
import top.fatweb.api.constant.SecurityConstants
|
||||
import top.fatweb.api.entity.permission.LoginUser
|
||||
import top.fatweb.api.entity.permission.User
|
||||
import top.fatweb.api.exception.TokenHasExpiredException
|
||||
import top.fatweb.api.service.IUserService
|
||||
import top.fatweb.api.service.permission.IAuthenticationService
|
||||
import top.fatweb.api.util.JwtUtil
|
||||
@@ -56,10 +57,11 @@ class AuthenticationServiceImpl(
|
||||
return LoginVo(jwt, loginUser.user.lastLoginTime, loginUser.user.lastLoginIp)
|
||||
}
|
||||
|
||||
override fun logout(token: String): Boolean =
|
||||
redisUtil.delObject("${SecurityConstants.jwtIssuer}_login:" + token)
|
||||
override fun logout(token: String): Boolean = redisUtil.delObject("${SecurityConstants.jwtIssuer}_login:" + token)
|
||||
|
||||
override fun renewToken(token: String): TokenVo {
|
||||
val loginUser = WebUtil.getLoginUser() ?: let { throw TokenHasExpiredException() }
|
||||
|
||||
val oldRedisKey = "${SecurityConstants.jwtIssuer}_login:" + token
|
||||
redisUtil.delObject(oldRedisKey)
|
||||
val jwt = JwtUtil.createJwt(WebUtil.getLoginUserId().toString())
|
||||
@@ -70,10 +72,7 @@ class AuthenticationServiceImpl(
|
||||
|
||||
val redisKey = "${SecurityConstants.jwtIssuer}_login:" + jwt
|
||||
redisUtil.setObject(
|
||||
redisKey,
|
||||
WebUtil.getLoginUser(),
|
||||
SecurityConstants.redisTtl,
|
||||
SecurityConstants.redisTtlUnit
|
||||
redisKey, loginUser, SecurityConstants.redisTtl, SecurityConstants.redisTtlUnit
|
||||
)
|
||||
|
||||
return TokenVo(jwt)
|
||||
|
||||
@@ -6,9 +6,10 @@ import top.fatweb.api.constant.SecurityConstants
|
||||
import top.fatweb.api.entity.permission.LoginUser
|
||||
|
||||
object WebUtil {
|
||||
fun getLoginUser() = SecurityContextHolder.getContext().authentication.principal as LoginUser
|
||||
fun getLoginUser() = if (SecurityContextHolder.getContext().authentication.principal is String) null
|
||||
else SecurityContextHolder.getContext().authentication.principal as LoginUser
|
||||
|
||||
fun getLoginUserId() = getLoginUser().user.id
|
||||
fun getLoginUserId() = getLoginUser()?.user?.id
|
||||
|
||||
fun getToken(tokenWithPrefix: String) = tokenWithPrefix.removePrefix(SecurityConstants.tokenPrefix)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user