Complete core functions #9

Merged
FatttSnake merged 171 commits from FatttSnake into dev 2024-02-23 11:56:35 +08:00
10 changed files with 169 additions and 12 deletions
Showing only changes of commit b2b4ac5302 - Show all commits

View File

@@ -12,6 +12,7 @@ import top.fatweb.api.annotation.EventLogRecord
import top.fatweb.api.entity.system.EventLog
import top.fatweb.api.service.system.IEventLogService
import top.fatweb.api.util.WebUtil
import top.fatweb.api.vo.permission.LoginVo
/**
* Event log record aspect
@@ -27,16 +28,18 @@ class EventLogAspect(
private val logger: Logger = LoggerFactory.getLogger(this::class.java)
@Pointcut("@annotation(top.fatweb.api.annotation.EventLogRecord)")
fun eventLogPointcut() {}
fun eventLogPointcut() {
}
@AfterReturning("eventLogPointcut()")
fun doAfter(joinPoint: JoinPoint) {
@AfterReturning(value = "eventLogPointcut()", returning = "retValue")
fun doAfter(joinPoint: JoinPoint, retValue: Any) {
val annotation = (joinPoint.signature as MethodSignature).method.getAnnotation(EventLogRecord::class.java)
try {
eventLogService.save(EventLog().apply {
this.event = annotation.event
operateUserId = WebUtil.getLoginUserId() ?: -1
operateUserId = WebUtil.getLoginUserId()
?: if (retValue is LoginVo) retValue.userId else -1
})
} catch (e: Exception) {
logger.error("Cannot record event!!!", e)

View File

@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.Operation
import org.springframework.web.bind.annotation.GetMapping
import top.fatweb.api.annotation.BaseController
import top.fatweb.api.entity.common.ResponseResult
import top.fatweb.api.param.system.ActiveInfoGetParam
import top.fatweb.api.param.system.OnlineInfoGetParam
import top.fatweb.api.service.system.IStatisticService
import top.fatweb.api.vo.system.*
@@ -72,7 +73,7 @@ class StatisticController(
fun storage(): ResponseResult<StorageInfoVo> = ResponseResult.success(data = statisticService.storage())
/**
* Get the number of online users information
* Get the history of online users information
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
@@ -81,4 +82,15 @@ class StatisticController(
@GetMapping("/online")
fun online(onlineInfoGetParam: OnlineInfoGetParam?): ResponseResult<OnlineInfoVo> =
ResponseResult.success(data = statisticService.online(onlineInfoGetParam))
/**
* Get the history of active information
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Operation(summary = "获取用户活跃信息")
@GetMapping("/active")
fun active(activeInfoGetParam: ActiveInfoGetParam): ResponseResult<ActiveInfoVo> =
ResponseResult.success(data = statisticService.active(activeInfoGetParam))
}

View File

@@ -16,6 +16,7 @@ import top.fatweb.api.entity.common.ResponseResult
import top.fatweb.api.entity.system.SysLog
import top.fatweb.api.service.system.ISysLogService
import top.fatweb.api.util.WebUtil
import top.fatweb.api.vo.permission.LoginVo
import java.net.URI
import java.time.LocalDateTime
import java.time.ZoneOffset
@@ -33,7 +34,8 @@ import java.util.concurrent.Executor
*/
@ControllerAdvice
class SysLogInterceptor(
@Qualifier("applicationTaskExecutor") private val customThreadPoolTaskExecutor: Executor, private val sysLogService: ISysLogService
@Qualifier("applicationTaskExecutor") private val customThreadPoolTaskExecutor: Executor,
private val sysLogService: ISysLogService
) : HandlerInterceptor, ResponseBodyAdvice<Any> {
private val sysLogThreadLocal = ThreadLocal<SysLog>()
private val resultThreadLocal = ThreadLocal<Any>()
@@ -77,6 +79,9 @@ class SysLogInterceptor(
} ?: SysLog.LogType.INFO
exception = 0
}
if (result.data is LoginVo) {
sysLog.operateUserId = result.data.userId ?: -1
}
} else {
sysLog.apply {
logType = SysLog.LogType.ERROR

View File

@@ -0,0 +1,26 @@
package top.fatweb.api.param.system
import com.baomidou.mybatisplus.annotation.EnumValue
import com.fasterxml.jackson.annotation.JsonValue
data class ActiveInfoGetParam(
val scope: Scope = Scope.WEAK
) {
enum class Scope(@field:EnumValue @field:JsonValue val code: String) {
WEAK("WEAK"),
MONTH("MONTH"),
QUARTER("QUARTER"),
YEAR("YEAR"),
TWO_YEARS("TWO_YEARS"),
THREE_YEARS("THREE_YEARS"),
FIVE_YEARS("FIVE_YEARS"),
ALL("ALL")
}
}

View File

@@ -70,7 +70,7 @@ class AuthenticationServiceImpl(
val redisKey = "${SecurityProperties.jwtIssuer}_login_${userId}:" + jwt
redisUtil.setObject(redisKey, loginUser, SecurityProperties.redisTtl, SecurityProperties.redisTtlUnit)
return LoginVo(jwt, loginUser.user.currentLoginTime, loginUser.user.currentLoginIp)
return LoginVo(jwt, loginUser.user.id, loginUser.user.currentLoginTime, loginUser.user.currentLoginIp)
}
@EventLogRecord(EventLog.Event.LOGOUT)

View File

@@ -1,5 +1,6 @@
package top.fatweb.api.service.system
import top.fatweb.api.param.system.ActiveInfoGetParam
import top.fatweb.api.param.system.OnlineInfoGetParam
import top.fatweb.api.vo.system.*
@@ -51,10 +52,18 @@ interface IStatisticService {
fun storage(): StorageInfoVo
/**
* Get the number of online users information
* Get the history of online users information
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
fun online(onlineInfoGetParam: OnlineInfoGetParam?): OnlineInfoVo
/**
* Get the history of active information
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
fun active(activeInfoGetParam: ActiveInfoGetParam?): ActiveInfoVo
}

View File

@@ -1,20 +1,26 @@
package top.fatweb.api.service.system.impl
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import org.springframework.stereotype.Service
import oshi.SystemInfo
import oshi.hardware.CentralProcessor
import top.fatweb.api.entity.system.EventLog
import top.fatweb.api.entity.system.StatisticLog
import top.fatweb.api.param.system.ActiveInfoGetParam
import top.fatweb.api.param.system.OnlineInfoGetParam
import top.fatweb.api.properties.SecurityProperties
import top.fatweb.api.properties.ServerProperties
import top.fatweb.api.service.system.IEventLogService
import top.fatweb.api.service.system.IStatisticLogService
import top.fatweb.api.service.system.IStatisticService
import top.fatweb.api.util.ByteUtil
import top.fatweb.api.util.RedisUtil
import top.fatweb.api.vo.system.*
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.concurrent.TimeUnit
@@ -27,7 +33,8 @@ import java.util.concurrent.TimeUnit
@Service
class StatisticServiceImpl(
private val redisUtil: RedisUtil,
private val statisticLogService: IStatisticLogService
private val statisticLogService: IStatisticLogService,
private val eventLogService: IEventLogService
) : IStatisticService {
private val systemProperties: Properties = System.getProperties()
private val systemInfo: SystemInfo = SystemInfo()
@@ -171,8 +178,8 @@ class StatisticServiceImpl(
OnlineInfoGetParam.Scope.FIVE_YEARS -> minusYears(5)
else -> minusWeeks(1)
}
},
LocalDateTime.now(ZoneOffset.UTC)
}.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
LocalDateTime.now(ZoneOffset.UTC).plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
)
).map {
OnlineInfoVo.HistoryVo(
@@ -187,4 +194,35 @@ class StatisticServiceImpl(
history = history
)
}
override fun active(activeInfoGetParam: ActiveInfoGetParam?): ActiveInfoVo {
fun getHistory(event: String) = eventLogService.listMaps(
QueryWrapper<EventLog?>().select("strftime('%Y-%m-%d', operate_time) time, count(distinct operate_user_id) count")
.eq("event", event).groupBy("time").between(
activeInfoGetParam?.scope != ActiveInfoGetParam.Scope.ALL,
"operate_time",
LocalDateTime.now(ZoneOffset.UTC).run {
when (activeInfoGetParam?.scope) {
ActiveInfoGetParam.Scope.MONTH -> minusMonths(1)
ActiveInfoGetParam.Scope.QUARTER -> minusMonths(3)
ActiveInfoGetParam.Scope.YEAR -> minusYears(1)
ActiveInfoGetParam.Scope.TWO_YEARS -> minusYears(2)
ActiveInfoGetParam.Scope.THREE_YEARS -> minusYears(3)
ActiveInfoGetParam.Scope.FIVE_YEARS -> minusYears(5)
else -> minusWeeks(1)
}
}.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
LocalDateTime.now(ZoneOffset.UTC).plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
)
).map {
ActiveInfoVo.HistoryVo(
LocalDate.parse(
it["time"] as String,
DateTimeFormatter.ofPattern("yyyy-MM-dd")
), it["count"] as Int
)
}
return ActiveInfoVo(getHistory("REGISTER"), getHistory("LOGIN"))
}
}

View File

@@ -1,5 +1,7 @@
package top.fatweb.api.vo.permission
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
import io.swagger.v3.oas.annotations.media.Schema
import java.time.LocalDateTime
@@ -22,6 +24,19 @@ data class LoginVo(
example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYTllYjFkYmVmZDQ0OWRkOThlOGNjNzZlNzZkMDgyNSIsInN1YiI6IjE3MDk5ODYwNTg2Nzk5NzU5MzgiLCJpc3MiOiJGYXRXZWIiLCJpYXQiOjE2OTY1MjgxMTcsImV4cCI6MTY5NjUzNTMxN30.U2ZsyrGk7NbsP-DJfdz9xgWSfect5r2iKQnlEsscAA8"
) val token: String,
/**
* User ID
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Schema(
description = "User ID",
example = "1709986058679975938"
)
@JsonSerialize(using = ToStringSerializer::class)
val userId: Long?,
/**
* Last login time
*

View File

@@ -0,0 +1,48 @@
package top.fatweb.api.vo.system
import top.fatweb.api.vo.system.ActiveInfoVo.HistoryVo
import java.time.LocalDate
/**
* Active information value object
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
data class ActiveInfoVo(
/**
* Register user number history
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
val registerHistory: List<HistoryVo>,
/**
* Login user number history
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
* @see HistoryVo
*/
val loginHistory: List<HistoryVo>
) {
data class HistoryVo(
/**
* Time
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
* @see LocalDate
*/
val time: LocalDate,
/**
* Count
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
val count: Int
)
}

View File

@@ -1,5 +1,6 @@
package top.fatweb.api.vo.system
import top.fatweb.api.vo.system.OnlineInfoVo.HistoryVo
import java.time.LocalDateTime
/**