SpringBoot自定义注解+异步+观察者模式实现业务日志保存( 二 )

四、主要功能大体思路:先手写一个注解--->切面来进行获取要保存的数据--->一个发布者来发布要保存的数据--->一个监听者监听后保存(异步)
完整项目架构图如下:

SpringBoot自定义注解+异步+观察者模式实现业务日志保存

文章插图
1. 编写注解import com.example.demo.constant.BusinessTypeEnum;import java.lang.annotation.*;/** * 自定义操作日志记录注解 * @author wangzhenjun * @date 2022/10/26 15:37 */@Target(ElementType.METHOD) // 注解只能用于方法@Retention(RetentionPolicy.RUNTIME) // 修饰注解的生命周期@Documentedpublic @interface Log {String value() default "";/*** 模块*/String title() default "测试模块";/*** 功能*/BusinessTypeEnum businessType() default BusinessTypeEnum.OTHER;}2. 业务类型枚举/** * @author wangzhenjun * @date 2022/10/26 11:22 */public enum BusinessTypeEnum {/*** 其它*/OTHER(0,"其它"),/*** 新增*/INSERT(1,"新增"),/*** 修改*/UPDATE(2,"修改"),/*** 删除*/DELETE(3,"删除");private Integer code;private String message;BusinessTypeEnum(Integer code, String message) {this.code = code;this.message = message;}public Integer getCode() {return code;}public String getMessage() {return message;}}3. 编写切片这里小编是以切片后进行发起的,当然规范流程是要加异常后的切片,这里以最简单的进行测试哈,大家按需进行添加!!
import com.example.demo.annotation.Log;import com.example.demo.entity.SysLog;import com.example.demo.listener.EventPubListener;import com.example.demo.utils.IpUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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 javax.servlet.http.HttpServletRequest;import java.time.LocalDateTime;/** * @author wangzhenjun * @date 2022/10/26 15:39 */@Aspect@Componentpublic class SysLogAspect {private final Logger logger = LoggerFactory.getLogger(SysLogAspect.class);@Autowiredprivate EventPubListener eventPubListener;/*** 以注解所标注的方法作为切入点*/@Pointcut("@annotation(com.example.demo.annotation.Log)")public void sysLog() {}/*** 在切点之后织入* @throws Throwable*/@After("sysLog()")public void doAfter(JoinPoint joinPoint) {Log log = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(Log.class);ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String method = request.getMethod();String url = request.getRequestURL().toString();String ip = IpUtils.getIpAddr(request);SysLog sysLog = new SysLog();sysLog.setBusinessType(log.businessType().getCode());sysLog.setTitle(log.title());sysLog.setRequestMethod(method);sysLog.setOperIp(ip);sysLog.setOperUrl(url);// 从登录中token获取登录人员信息即可sysLog.setOperName("我是测试人员");sysLog.setOperTime(LocalDateTime.now());// 发布消息eventPubListener.pushListener(sysLog);logger.info("=======日志发送成功,内容:{}",sysLog);}}4. ip工具类import com.baomidou.mybatisplus.core.toolkit.StringUtils;import javax.servlet.http.HttpServletRequest;/** * @author wangzhenjun * @date 2022/10/26 16:27 * 获取IP方法 * * @author jw */public class IpUtils {/*** 获取客户端IP** @param request 请求对象* @return IP地址*/public static String getIpAddr(HttpServletRequest request) {if (request == null) {return "unknown";}String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Forwarded-For");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);}/*** 从多级反向代理中获得第一个非unknown IP地址** @param ip 获得的IP地址* @return 第一个非unknown IP地址*/public static String getMultistageReverseProxyIp(String ip) {// 多级反向代理检测if (ip != null && ip.indexOf(",") > 0) {final String[] ips = ip.trim().split(",");for (String subIp : ips) {if (false == isUnknown(subIp)) {ip = subIp;break;}}}return ip;}/*** 检测给定字符串是否为未知,多用于检测HTTP请求相关** @param checkString 被检测的字符串* @return 是否未知*/public static boolean isUnknown(String checkString) {return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);}}

经验总结扩展阅读