diff --git a/databases/v1.0-beta.1.sql b/databases/v1.0-beta.1.sql index 9af13f5..1ef2170 100644 --- a/databases/v1.0-beta.1.sql +++ b/databases/v1.0-beta.1.sql @@ -27,10 +27,16 @@ CREATE TABLE `admin_logs` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `admin_id` int(11) NOT NULL DEFAULT '0' COMMENT '管理员ID', `module` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '模块', - `opt` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '操作指令', - `remark` mediumtext COLLATE utf8mb4_unicode_ci COMMENT '备注', + `title` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求方法标题', + `opt` int(2) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0 COMMENT '操作指令(0其它 1新增 2修改 3删除 4查询 5登录 6退出登录)', + `method` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求方法', + `request_method` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求方式POST,GET,PUT,DELETE', + `url` varchar(266) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '请求URL', + `param` text COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '请求参数', + `result` text COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '返回参数', `ip` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'ip', `ip_area` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '地址', + `error_msg` varchar(2000) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '错误消息', `created_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `a_m_o` (`admin_id`,`module`,`opt`) diff --git a/src/main/java/xyz/playedu/api/annotation/Log.java b/src/main/java/xyz/playedu/api/annotation/Log.java new file mode 100644 index 0000000..8284a79 --- /dev/null +++ b/src/main/java/xyz/playedu/api/annotation/Log.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.playedu.api.annotation; + +import xyz.playedu.api.constant.BusinessType; + +import java.lang.annotation.*; + +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log +{ + /** + * 标题 + */ + public String title() default ""; + + /** + * 功能 + */ + public BusinessType businessType() default BusinessType.OTHER; +} diff --git a/src/main/java/xyz/playedu/api/aspectj/AdminLogAspect.java b/src/main/java/xyz/playedu/api/aspectj/AdminLogAspect.java new file mode 100644 index 0000000..08f24d6 --- /dev/null +++ b/src/main/java/xyz/playedu/api/aspectj/AdminLogAspect.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.playedu.api.aspectj; + +import cn.hutool.json.JSONUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import xyz.playedu.api.annotation.Log; +import xyz.playedu.api.domain.AdminLog; +import xyz.playedu.api.service.AdminLogService; +import xyz.playedu.api.service.BackendAuthService; +import xyz.playedu.api.util.IpUtil; +import xyz.playedu.api.util.RequestUtil; +import xyz.playedu.api.util.StringUtil; + +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Map; + +@Aspect +@Component +@Slf4j +public class AdminLogAspect { + + @Autowired private BackendAuthService authService; + + @Autowired private AdminLogService adminLogService; + + /** + * Controller层切点 注解拦截 + */ + @Pointcut("@annotation(xyz.playedu.api.annotation.Log)") + public void logPointCut() {} + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { + handleLog(joinPoint, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "logPointCut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + handleLog(joinPoint, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { + try { + // 获取注解信息 + Log controllerLog = getAnnotationLog(joinPoint); + if (null == controllerLog) { + return; + } + + // 日志 + AdminLog adminLog = new AdminLog(); + adminLog.setAdminId(authService.userId()); + adminLog.setModule("BACKEND"); + adminLog.setTitle(controllerLog.title()); + adminLog.setOpt(controllerLog.businessType().ordinal()); + + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + adminLog.setMethod(className + "." + methodName + "()"); + + HttpServletRequest request = RequestUtil.handler(); + if (null == request) { + return; + } + adminLog.setRequestMethod(request.getMethod()); + adminLog.setUrl(request.getRequestURL().toString()); + Map parameterMap = request.getParameterMap(); + if (StringUtil.isNotEmpty(parameterMap)) { + String params = JSONUtil.toJsonStr(parameterMap); + adminLog.setParam(StringUtils.substring(params, 0, 2000)); + } + adminLog.setResult(JSONUtil.toJsonStr(jsonResult)); + adminLog.setIp(IpUtil.getIpAddress()); + adminLog.setIpArea(IpUtil.getRealAddressByIP(IpUtil.getIpAddress())); + + if (null != e) { + adminLog.setErrorMsg(StringUtil.substring(e.getMessage(), 0, 2000)); + } + adminLog.setCreatedAt(new Date()); + // 保存数据库 + adminLogService.save(adminLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:"+exp.getMessage(),e); + } + } + + /** + * 是否存在注解,如果存在就获取 + */ + private Log getAnnotationLog(JoinPoint joinPoint) throws Exception { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + + if (method != null) { + return method.getAnnotation(Log.class); + } + return null; + } +} diff --git a/src/main/java/xyz/playedu/api/constant/BusinessType.java b/src/main/java/xyz/playedu/api/constant/BusinessType.java new file mode 100644 index 0000000..c1b048d --- /dev/null +++ b/src/main/java/xyz/playedu/api/constant/BusinessType.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.playedu.api.constant; + +public enum BusinessType +{ + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 查询 + */ + GET, + + /** + * 登录 + */ + LOGIN, + + /** + * 退出登录 + */ + LOGOUT +} diff --git a/src/main/java/xyz/playedu/api/domain/AdminLog.java b/src/main/java/xyz/playedu/api/domain/AdminLog.java index 214b57e..43cee74 100644 --- a/src/main/java/xyz/playedu/api/domain/AdminLog.java +++ b/src/main/java/xyz/playedu/api/domain/AdminLog.java @@ -43,11 +43,27 @@ public class AdminLog implements Serializable { /** 模块 */ private String module; - /** 操作指令 */ - private String opt; + /** 标题 */ + private String title; - /** 备注 */ - private String remark; + /** 操作指令 */ + private Integer opt; + + /** 请求方法 */ + private String method; + + /** 请求方式 POST,GET,PUT,DELETE */ + @JsonProperty("request_method") + private String requestMethod; + + /** 请求URL */ + private String url; + + /** 请求参数 */ + private String param; + + /** 返回参数 */ + private String result; /** ip */ private String ip; @@ -56,6 +72,10 @@ public class AdminLog implements Serializable { @JsonProperty("ip_area") private String ipArea; + /** 备注 */ + @JsonProperty("error_msg") + private String errorMsg; + @JsonProperty("created_at") private Date createdAt; @@ -81,18 +101,36 @@ public class AdminLog implements Serializable { && (this.getModule() == null ? other.getModule() == null : this.getModule().equals(other.getModule())) + && (this.getTitle() == null + ? other.getTitle() == null + : this.getTitle().equals(other.getTitle())) && (this.getOpt() == null ? other.getOpt() == null : this.getOpt().equals(other.getOpt())) - && (this.getRemark() == null - ? other.getRemark() == null - : this.getRemark().equals(other.getRemark())) + && (this.getMethod() == null + ? other.getMethod() == null + : this.getMethod().equals(other.getMethod())) + && (this.getRequestMethod() == null + ? other.getRequestMethod() == null + : this.getRequestMethod().equals(other.getRequestMethod())) + && (this.getUrl() == null + ? other.getUrl() == null + : this.getUrl().equals(other.getUrl())) + && (this.getParam() == null + ? other.getParam() == null + : this.getParam().equals(other.getParam())) + && (this.getResult() == null + ? other.getResult() == null + : this.getResult().equals(other.getResult())) && (this.getIp() == null ? other.getIp() == null : this.getIp().equals(other.getIp())) && (this.getIpArea() == null ? other.getIpArea() == null : this.getIpArea().equals(other.getIpArea())) + && (this.getErrorMsg() == null + ? other.getErrorMsg() == null + : this.getErrorMsg().equals(other.getErrorMsg())) && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())); @@ -105,10 +143,16 @@ public class AdminLog implements Serializable { result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); result = prime * result + ((getAdminId() == null) ? 0 : getAdminId().hashCode()); result = prime * result + ((getModule() == null) ? 0 : getModule().hashCode()); + result = prime * result + ((getTitle() == null) ? 0 : getTitle().hashCode()); result = prime * result + ((getOpt() == null) ? 0 : getOpt().hashCode()); - result = prime * result + ((getRemark() == null) ? 0 : getRemark().hashCode()); + result = prime * result + ((getMethod() == null) ? 0 : getMethod().hashCode()); + result = prime * result + ((getRequestMethod() == null) ? 0 : getRequestMethod().hashCode()); + result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode()); + result = prime * result + ((getParam() == null) ? 0 : getParam().hashCode()); + result = prime * result + ((getResult() == null) ? 0 : getResult().hashCode()); result = prime * result + ((getIp() == null) ? 0 : getIp().hashCode()); result = prime * result + ((getIpArea() == null) ? 0 : getIpArea().hashCode()); + result = prime * result + ((getErrorMsg() == null) ? 0 : getErrorMsg().hashCode()); result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); return result; } @@ -122,10 +166,16 @@ public class AdminLog implements Serializable { sb.append(", id=").append(id); sb.append(", adminId=").append(adminId); sb.append(", module=").append(module); + sb.append(", title=").append(title); sb.append(", opt=").append(opt); - sb.append(", remark=").append(remark); + sb.append(", method=").append(method); + sb.append(", requestMethod=").append(requestMethod); + sb.append(", url=").append(url); + sb.append(", param=").append(param); + sb.append(", result=").append(result); sb.append(", ip=").append(ip); sb.append(", ipArea=").append(ipArea); + sb.append(", errorMsg=").append(errorMsg); sb.append(", createdAt=").append(createdAt); sb.append(", serialVersionUID=").append(serialVersionUID); sb.append("]"); diff --git a/src/main/java/xyz/playedu/api/listener/AdminUserLoginListener.java b/src/main/java/xyz/playedu/api/listener/AdminUserLoginListener.java index a4c2a4a..72ce4f5 100644 --- a/src/main/java/xyz/playedu/api/listener/AdminUserLoginListener.java +++ b/src/main/java/xyz/playedu/api/listener/AdminUserLoginListener.java @@ -19,18 +19,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; -import xyz.playedu.api.constant.BackendLogConstant; -import xyz.playedu.api.domain.AdminLog; import xyz.playedu.api.domain.AdminUser; import xyz.playedu.api.event.AdminUserLoginEvent; -import xyz.playedu.api.service.AdminLogService; import xyz.playedu.api.service.AdminUserService; -import xyz.playedu.api.util.IpUtil; - -import java.util.Date; @Component @Slf4j @@ -38,8 +31,6 @@ public class AdminUserLoginListener { @Autowired private AdminUserService adminUserService; - @Autowired private AdminLogService adminLogService; - @EventListener public void updateLoginInfo(AdminUserLoginEvent event) { AdminUser adminUser = new AdminUser(); @@ -51,20 +42,4 @@ public class AdminUserLoginListener { adminUserService.updateById(adminUser); } - - @Async - @EventListener - public void log(AdminUserLoginEvent event) { - String area = IpUtil.getRealAddressByIP(event.getIp()); - - AdminLog adminLog = new AdminLog(); - adminLog.setAdminId(event.getAdminId()); - adminLog.setModule(BackendLogConstant.MODULE_LOGIN); - adminLog.setOpt(BackendLogConstant.OPT_LOGIN); - adminLog.setIp(event.getIp()); - adminLog.setIpArea(area); - adminLog.setCreatedAt(new Date()); - - adminLogService.save(adminLog); - } } diff --git a/src/main/resources/mapper/AdminLogMapper.xml b/src/main/resources/mapper/AdminLogMapper.xml index 7cb1348..47892ab 100644 --- a/src/main/resources/mapper/AdminLogMapper.xml +++ b/src/main/resources/mapper/AdminLogMapper.xml @@ -8,16 +8,22 @@ - - + + + + + + + + - id,admin_id,module, - opt,remark,ip, - ip_area,created_at + id,admin_id,module,title, + opt,method,request_method,url,param,result, + ip,ip_area,error_msg,created_at