重构使用aop的方式记录异常日志-引入Spring AOP
This commit is contained in:
@@ -20,6 +20,18 @@ interface ICommandApp<TCommand : ICommand, TKey> : IApplication {
|
||||
|
||||
var service: IService<TKey>?
|
||||
|
||||
@DeleteMapping("/{id:.+}")
|
||||
fun remove(@PathVariable id: TKey): HttpMessage {
|
||||
return this.safeExecute("删除${this.name}[id: $id]失败") {
|
||||
if (this.service != null)
|
||||
it.data = this.service!!.remove(id)
|
||||
else {
|
||||
it.status = Status.Error
|
||||
it.message = "没有对应服务,无法执行该操作"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
fun add(@RequestBody command: TCommand): HttpMessage {
|
||||
return this.safeExecute("添加${this.name}数据失败 - ${if (jsonSerializer != null) jsonSerializer?.serialize(command) else ""}") {
|
||||
@@ -33,18 +45,6 @@ interface ICommandApp<TCommand : ICommand, TKey> : IApplication {
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id:.+}")
|
||||
fun remove(@PathVariable id: TKey): HttpMessage {
|
||||
return this.safeExecute("删除${this.name}[id: $id]失败") {
|
||||
if (this.service != null)
|
||||
it.data = this.service!!.remove(id)
|
||||
else {
|
||||
it.status = Status.Error
|
||||
it.message = "没有对应服务,无法执行该操作"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id:.+}")
|
||||
fun update(@PathVariable id: TKey, @RequestBody command: TCommand): HttpMessage {
|
||||
return this.safeExecute("更新${this.name}失败 - ${if (jsonSerializer != null) jsonSerializer?.serialize(command) else ""}") {
|
||||
|
||||
@@ -11,24 +11,21 @@ import org.springframework.stereotype.Component
|
||||
import java.io.File
|
||||
|
||||
@Component
|
||||
class EmailMessenger : IEmailMessenger {
|
||||
class EmailMessenger(var mailSender: JavaMailSender?) : IEmailMessenger {
|
||||
|
||||
@Autowired
|
||||
private lateinit var mailSender: JavaMailSender
|
||||
|
||||
@Value("\${spring.mail.host}")
|
||||
@Value("\${spring.mail.host:}")
|
||||
var host = ""
|
||||
|
||||
@Value("\${spring.mail.port}")
|
||||
@Value("\${spring.mail.port:}")
|
||||
var port = ""
|
||||
|
||||
@Value("\${spring.mail.sender}")
|
||||
@Value("\${spring.mail.sender:}")
|
||||
var sender = ""
|
||||
|
||||
@Value("\${spring.mail.username}")
|
||||
@Value("\${spring.mail.username:}")
|
||||
var username = ""
|
||||
|
||||
@Value("\${spring.mail.password}")
|
||||
@Value("\${spring.mail.password:}")
|
||||
var password = ""
|
||||
|
||||
@Autowired
|
||||
@@ -42,13 +39,20 @@ class EmailMessenger : IEmailMessenger {
|
||||
* @param receivers 邮件接受者
|
||||
* @param files 附件
|
||||
*/
|
||||
override fun sendMessage(subject: String, content: String, receivers: List<String>, files: Map<String, String>): Map<String, Boolean> {
|
||||
override fun sendMessage(
|
||||
subject: String,
|
||||
content: String,
|
||||
receivers: List<String>,
|
||||
files: Map<String, String>
|
||||
): Map<String, Boolean> {
|
||||
val result = mutableMapOf<String, Boolean>()
|
||||
this.check()
|
||||
receivers.forEach { receiver ->
|
||||
result[receiver] = true
|
||||
if (this.mailSender == null)
|
||||
throw Exception("没有配置JavaMailSender的实现实例,请重新配置")
|
||||
try {
|
||||
val mail = mailSender.createMimeMessage()
|
||||
val mail = this.mailSender!!.createMimeMessage()
|
||||
val mimeMessageHelper = MimeMessageHelper(mail, true, "utf-8")
|
||||
mimeMessageHelper.setFrom(sender)
|
||||
mimeMessageHelper.setTo(receiver)
|
||||
@@ -59,7 +63,7 @@ class EmailMessenger : IEmailMessenger {
|
||||
val file = FileSystemResource(File(path))
|
||||
mimeMessageHelper.addAttachment(name, file)
|
||||
}
|
||||
mailSender.send(mail) //发送
|
||||
this.mailSender!!.send(mail) //发送
|
||||
} catch (e: Exception) {
|
||||
logger.error(e, "发送邮件[$subject]至地址[$receiver]失败")
|
||||
result[receiver] = false
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.synebula.gaea.app.component.aop
|
||||
|
||||
import java.lang.Exception
|
||||
|
||||
interface AnnotationHandler {
|
||||
fun handle(clazz: Class<Any>, func: String, args: Array<Any>, exception: Exception?)
|
||||
}
|
||||
@@ -1,68 +1,86 @@
|
||||
package com.synebula.gaea.app.component.aop
|
||||
|
||||
import com.synebula.gaea.app.component.HttpMessage
|
||||
import com.synebula.gaea.app.component.aop.annotation.SafeExec
|
||||
import com.synebula.gaea.app.component.aop.annotation.ExceptionMessage
|
||||
import com.synebula.gaea.app.component.aop.annotation.Handler
|
||||
import com.synebula.gaea.app.component.aop.annotation.ModuleName
|
||||
import com.synebula.gaea.data.message.Status
|
||||
import com.synebula.gaea.log.ILogger
|
||||
import org.aspectj.lang.JoinPoint
|
||||
import org.aspectj.lang.ProceedingJoinPoint
|
||||
import org.aspectj.lang.annotation.*
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.context.request.RequestContextHolder
|
||||
import org.springframework.web.context.request.ServletRequestAttributes
|
||||
import java.util.*
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.ApplicationContext
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
class AppAspect {
|
||||
private val mapper = ObjectMapper()
|
||||
|
||||
@Autowired
|
||||
lateinit var logger: ILogger
|
||||
|
||||
@Autowired
|
||||
lateinit var applicationContext: ApplicationContext
|
||||
|
||||
@Pointcut("within(com.synebula..app.*)")
|
||||
fun log() {
|
||||
}
|
||||
|
||||
//后置异常通知
|
||||
@AfterThrowing("log()")
|
||||
fun throws(point: JoinPoint): Any {
|
||||
/**
|
||||
* 后置异常通知
|
||||
*/
|
||||
@AfterThrowing("log()", throwing = "ex")
|
||||
fun throws(point: JoinPoint, ex: Throwable) {
|
||||
val clazz = point.signature.declaringType
|
||||
println("${clazz.name} - ${point.signature.name}异常:${point.signature.name}")
|
||||
return "error"
|
||||
logger.error(
|
||||
ex,
|
||||
"${clazz.name}.${point.signature.name} exception:${ex.message}, args:${mapper.writeValueAsString(point.args)}"
|
||||
)
|
||||
}
|
||||
|
||||
//后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
|
||||
@After("log()")
|
||||
fun after(point: JoinPoint) {
|
||||
println("方法最后执行.....")
|
||||
}
|
||||
|
||||
//环绕通知,环绕增强,相当于MethodInterceptor
|
||||
/**
|
||||
* 环绕通知,环绕增强,相当于MethodInterceptor
|
||||
*/
|
||||
@Around("log()")
|
||||
fun around(point: ProceedingJoinPoint): Any? {
|
||||
val clazz = point.signature.declaringType
|
||||
val func = clazz.methods.find {
|
||||
it.name == point.signature.name
|
||||
}!!
|
||||
val clazzAnnotations = clazz.annotations
|
||||
val funcAnnotations = func.annotations ?: arrayOf()
|
||||
|
||||
val attributes = RequestContextHolder.getRequestAttributes() as ServletRequestAttributes
|
||||
val request = attributes.request
|
||||
// 记录下请求内容
|
||||
println("URL : " + request.requestURL.toString())
|
||||
println("HTTP_METHOD : " + request.method)
|
||||
println("IP : " + request.remoteAddr)
|
||||
println("CLASS_METHOD : " + clazz.name + "." + point.signature.name)
|
||||
println("ARGS : " + Arrays.toString(point.args))
|
||||
var exceptionMessage = func.name
|
||||
//遍历方法注解
|
||||
for (funcAnnotation in funcAnnotations) {
|
||||
val annotations = funcAnnotation.annotationClass.annotations
|
||||
|
||||
//尝试寻找方法注解的处理类
|
||||
val handler = annotations.find { it is Handler }
|
||||
if (handler != null && handler is Handler) {
|
||||
val handleClazz = applicationContext.getBean(handler.value.java)
|
||||
handleClazz.handle(clazz, func, point.args)
|
||||
}
|
||||
if (funcAnnotation is ExceptionMessage)
|
||||
exceptionMessage = funcAnnotation.message
|
||||
}
|
||||
|
||||
return try {
|
||||
val res = point.proceed()
|
||||
res
|
||||
} catch (ex: Throwable) {
|
||||
val msg = HttpMessage(Status.Success)
|
||||
for (item in funcAnnotations) {
|
||||
if (item.annotationClass == SafeExec::javaClass) {
|
||||
}
|
||||
//找到类的模块名称,否则使用类名
|
||||
var moduleName = clazz.name
|
||||
val name = clazz.annotations.find { it is ModuleName }
|
||||
if (name != null && name is ModuleName) {
|
||||
moduleName = name.value
|
||||
}
|
||||
println("方法${point.signature}异常: $msg - ${ex.message}")
|
||||
return "error"
|
||||
val message = "$moduleName - $exceptionMessage"
|
||||
logger.error(ex, "$message, args: ${mapper.writeValueAsString(point.args)}")
|
||||
return HttpMessage(Status.Error, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.synebula.gaea.app.component.aop.annotation
|
||||
|
||||
import com.synebula.gaea.app.component.aop.handler.AccessLogHandler
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Handler(AccessLogHandler::class)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class AccessLog
|
||||
@@ -3,8 +3,8 @@ package com.synebula.gaea.app.component.aop.annotation
|
||||
/**
|
||||
* 标记方法安全执行,由AOP负责try catch异常
|
||||
*
|
||||
* @param errorMessage 异常消息
|
||||
* @param message 异常消息
|
||||
*/
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class SafeExec(val errorMessage: String)
|
||||
annotation class ExceptionMessage(val message: String)
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.synebula.gaea.app.component.aop.annotation
|
||||
|
||||
import com.synebula.gaea.app.component.aop.handler.AnnotationHandler
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class Handler(val value: KClass<Any>)
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class Handler(val value: KClass<out AnnotationHandler>)
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.synebula.gaea.app.component.aop.annotation
|
||||
|
||||
/**
|
||||
* 模块的业务名称
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ModuleName(val value: String)
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.synebula.gaea.app.component.aop.handler
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.synebula.gaea.log.ILogger
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.context.request.RequestContextHolder
|
||||
import org.springframework.web.context.request.ServletRequestAttributes
|
||||
import java.lang.reflect.Method
|
||||
|
||||
@Component
|
||||
class AccessLogHandler : AnnotationHandler {
|
||||
private val mapper = ObjectMapper()
|
||||
|
||||
@Autowired
|
||||
lateinit var logger: ILogger
|
||||
|
||||
override fun handle(clazz: Class<Any>, func: Method, args: Array<Any>, exception: Exception?) {
|
||||
val attributes = RequestContextHolder.getRequestAttributes() as ServletRequestAttributes
|
||||
val request = attributes.request
|
||||
logger.info(
|
||||
"${request.method} ${request.requestURL} from ${request.remoteAddr}, call function ${clazz.name}.${func.name}, args: ${
|
||||
mapper.writeValueAsString(
|
||||
args
|
||||
)
|
||||
}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.synebula.gaea.app.component.aop.handler
|
||||
|
||||
import java.lang.Exception
|
||||
import java.lang.reflect.Method
|
||||
|
||||
interface AnnotationHandler {
|
||||
fun handle(clazz: Class<Any>, func: Method, args: Array<Any>, exception: Exception? = null)
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import com.synebula.gaea.query.type.Order
|
||||
*/
|
||||
data class Params(var page: Int = 1, var size: Int = 10) {
|
||||
|
||||
private var _parameters = mutableMapOf<String, Any>()
|
||||
private var _orders = mutableMapOf<String, Order>()
|
||||
private var _parameters = linkedMapOf<String, Any>()
|
||||
private var _orders = linkedMapOf<String, Order>()
|
||||
|
||||
/**
|
||||
* 数据索引,从0开始。表示数据在总量的第几条。(index = (page - 1) * size)
|
||||
@@ -24,13 +24,13 @@ data class Params(var page: Int = 1, var size: Int = 10) {
|
||||
/**
|
||||
* 排序条件。
|
||||
*/
|
||||
var orders: Map<String, Order>
|
||||
var orders: LinkedHashMap<String, Order>
|
||||
set(value) {
|
||||
this._orders = value.toMutableMap()
|
||||
this._orders = value
|
||||
}
|
||||
get() {
|
||||
if (this._parameters.keys.count { it.startsWith("@") } > 0) {
|
||||
val params = mutableMapOf<String, Any>()
|
||||
val params = linkedMapOf<String, Any>()
|
||||
this._parameters.forEach {
|
||||
if (it.key.startsWith("@")) {
|
||||
this._orders[it.key.removePrefix("@")] = Order.valueOf(it.value.toString())
|
||||
@@ -45,13 +45,13 @@ data class Params(var page: Int = 1, var size: Int = 10) {
|
||||
/**
|
||||
* 查询条件。
|
||||
*/
|
||||
var parameters: Map<String, Any>
|
||||
var parameters: LinkedHashMap<String, Any>
|
||||
set(value) {
|
||||
this._parameters = value.toMutableMap()
|
||||
this._parameters = value
|
||||
}
|
||||
get() {
|
||||
if (this._parameters.keys.count { it.startsWith("@") } > 0) {
|
||||
val params = mutableMapOf<String, Any>()
|
||||
val params = linkedMapOf<String, Any>()
|
||||
this._parameters.forEach {
|
||||
if (it.key.startsWith("@")) {
|
||||
this._orders[it.key.removePrefix("@")] = Order.valueOf(it.value.toString())
|
||||
|
||||
Reference in New Issue
Block a user