aop原理:

将共同方法封装起来,然后找到切面点插入进业务流程即可
JoinPoint要了解

框架:springcloud+consul+gateway+springboot
业务环境:系统log日志,每个操作得参数都要加入到数据库中
数据库:oracle

日志表:

package com.cuslink.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;import java.io.Serializable;
import java.time.LocalDateTime;/*** <p>* 日志表* </p>**/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("TBL_LOG")
@ApiModel(value="TblLog对象", description="日志表")
public class TblLog implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "ID",type = IdType.UUID)private String id;@ApiModelProperty(value = "访问接口路径")@TableField("URL")private String url;@ApiModelProperty(value = "客户端类型,1电脑端,2移动端")@TableField("CLIENT_TYPE")private Double clientType;@ApiModelProperty(value = "IP地址")@TableField("IP_ADDRESS")private String ipAddress;@ApiModelProperty(value = "方法名称")@TableField("FUNC_NAME")private String funcName;@ApiModelProperty(value = "方法参数")@TableField("FUNC_PARAM")private String funcParam;@ApiModelProperty(value = "类型,1操作日志,2错误日志,3系统日志")@TableField("TYPE")private Double type;@ApiModelProperty(value = "内容")@TableField("CONTENT")private String content;@ApiModelProperty("请求状态 0正常 1错误")@TableField("STATUS")private Double status;@ApiModelProperty("错误信息")@TableField("ERROR_MSG")private String errorMsg;@ApiModelProperty(value = "创建时间")@TableField("CREATE_TIME")private LocalDateTime createTime;@ApiModelProperty(value = "更新时间")@TableField("UPDATE_TIME")private LocalDateTime updateTime;@ApiModelProperty(value = "创建人")@TableField("CREATE_ID")private String createId;@ApiModelProperty(value = "更新人")@TableField("UPDATE_ID")private String updateId;@ApiModelProperty(value = "是否删除,0不删除,1删除")@TableField("DELETE_FLAG")private Double deleteFlag;}

切面编程设置一个log注解

package com.cuslink.annotation;import java.lang.annotation.*;/*** 操作日志元注解**/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {/*** 日志类型,1操作日志,2错误日志,3系统日志*/double type() default 1;/*** 是否保存请求数据*/boolean isSaveRequestData() default true;
}

log注解写在方法头上

@RestController
@RequestMapping("/v1/param-type")
@Validated
@Api(value = "TblParamTypeController",description = "参数类型")
public class TblParamTypeController {@Autowiredprivate ITblParamTypeService iTblParamTypeService;@Log@PostMapping("/save")@ApiOperation("新增参数类型")public AjaxResult save(@Valid @RequestBody TblParamType tblParamType){if(iTblParamTypeService.saveParamType(tblParamType)){return new AjaxResult().success("true","新增成功");}return new AjaxResult().fail(ConstantsCode.FAIL_TO_SAVE,"false","新增失败");}

接下来是核心重点:
找到切入点,然后将再接口运行后将信息存到log表中

package com.cuslink.common.aspectj;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cuslink.annotation.Log;
import com.cuslink.common.mapper.TblLogMapper;
import com.cuslink.common.util.IpUtil;
import com.cuslink.common.util.ServletUtils;
import com.cuslink.entity.TblLog;
import com.cuslink.service.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;/***/
@Aspect
@Component
@Slf4j
public class LogAspectj {private TblLogMapper tblLogMapper;@Autowiredpublic void setTblLogMapper(TblLogMapper tblLogMapper) {this.tblLogMapper = tblLogMapper;}private final String[] mobileAgents = {"iphone", "android", "phone", "mobile", "wap", "netfront", "java", "opera mobi", "opera mini", "ucweb", "windows ce", "symbian", "series", "webos", "sony", "blackberry", "dopod", "nokia", "samsung", "palmsource", "xda", "pieplus", "meizu", "midp", "cldc", "motorola", "foma", "docomo", "up.browser", "up.link", "blazer", "helio", "hosin", "huawei", "novarra", "coolpad", "webos", "techfaith", "palmsource", "alcatel", "amoi", "ktouch", "nexian", "ericsson", "philips", "sagem", "wellcom", "bunjalloo", "maui", "smartphone", "iemobile", "spice", "bird", "zte-", "longcos", "pantech", "gionee", "portalmmm", "jig browser", "hiptop", "benq", "haier", "^lct", "320x320", "240x320", "176x220", "w3c ", "acs-", "alav", "alca", "amoi", "audi", "avan", "benq", "bird", "blac", "blaz", "brew", "cell", "cldc", "cmd-", "dang", "doco", "eric", "hipt", "inno", "ipaq", "java", "jigs", "kddi", "keji", "leno", "lg-c", "lg-d", "lg-g", "lge-", "maui", "maxo", "midp", "mits", "mmef", "mobi", "mot-", "moto", "mwbp", "nec-", "newt", "noki", "oper", "palm", "pana", "pant", "phil", "play", "port", "prox", "qwap", "sage", "sams", "sany", "sch-", "sec-", "send", "seri", "sgh-", "shar", "sie-", "siem", "smal", "smar", "sony", "sph-", "symb", "t-mo", "teli", "tim-", "tosh", "tsm-", "upg1", "upsi", "vk-v", "voda", "wap-", "wapa", "wapi", "wapp", "wapr", "webc", "winw", "winw", "xda", "xda-", "Googlebot-Mobile"};@Pointcut("@annotation(com.cuslink.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 o) {try {// 获得注解Log controllerLog = getAnnotationLog(joinPoint);if (controllerLog == null) {return;}HttpServletRequest request = ServletUtils.getRequest();// *========数据库日志=========*//TblLog tblLog = new TblLog();// 请求的地址String ip = IpUtil.getIpAddress(request);tblLog.setIpAddress(ip);// 返回参数// tblLog.setContent(JSONObject.toJSONString(o));tblLog.setType(controllerLog.type());tblLog.setUrl(ServletUtils.getRequest().getRequestURI());tblLog.setStatus(0d);tblLog.setCreateTime(LocalDateTime.now());tblLog.setUpdateTime(LocalDateTime.now());tblLog.setClientType(isMobile(request));if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {tblLog.setFuncParam(JSON.toJSONString(joinPoint.getArgs()[0]));}if (o != null) {tblLog.setContent(JSON.toJSONString(o));if (o instanceof AjaxResult) {String status = ((AjaxResult) o).getError();if ("true".equals(status)) {tblLog.setStatus(0d);} else {tblLog.setStatus(1d);}}}if (e != null) {//如果有异常tblLog.setStatus(1d);//tblLog.setErrorMsg(ExceptionUtils.getStackTrace(e)); 文本过大tblLog.setErrorMsg(e.getMessage());}log.info("URL : {}", request.getRequestURL().toString());log.info("HTTP_METHOD : {}", request.getMethod());log.info("IP : {}", IpUtil.getIpAddress(request));log.info("CLASS_METHOD : {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());log.info("ARGS : {}", Arrays.toString(joinPoint.getArgs()));log.info("RESPONSE : {}", o);// 设置方法名称String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();tblLog.setFuncName(className + "." + methodName + "()");// 保存数据库saveLogData(tblLog);} catch (Exception exp) {// 记录本地异常日志log.error("[日志服务]----日志记录日常,e->: {}", ExceptionUtils.getStackTrace(exp));}}protected void saveLogData(TblLog tblLog) throws Exception {tblLogMapper.insert(tblLog);}/*** 判断是否为移动端** @return 1:PC端 2.移动端*/private Double isMobile(HttpServletRequest request) {String userAgent = request.getHeader("User-Agent");if (StringUtils.isNotBlank(userAgent)) {for (String mobileAgent : mobileAgents) {if (userAgent.toLowerCase().contains(mobileAgent)) {return 2d;}}}return 1d;}/*** 是否存在注解,如果存在就获取*/private Log getAnnotationLog(JoinPoint joinPoint) throws Exception {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {return method.getAnnotation(Log.class);}return null;}
}

用到得工具类

package com.cuslink.common.util;import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;import javax.servlet.http.HttpServletRequest;
import java.util.Objects;/*** IP操作相关工具类*/
public class IpUtil {private IpUtil() {}/*** 获取IP地址** @param request 当前请求* @return IP地址*/public static String getIpAddress(HttpServletRequest request) {String xIp = request.getHeader("X-Real-IP");String xFor = request.getHeader("X-Forwarded-For");if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {//多次反向代理后会有多个IP值,第一个IP才是真实IPint index = xFor.indexOf(",");if (index != -1) {return xFor.substring(0, index);} else {return xFor;}}xFor = xIp;if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {return xFor;}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = request.getHeader("Proxy-Client-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = request.getHeader("WL-Proxy-Client-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = request.getHeader("HTTP-CLIENT-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = request.getHeader("HTTP_X_FORWARDED_FOR");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = request.getRemoteAddr();}return xFor;}public static String getIpAddress(ServerHttpRequest request){HttpHeaders headers = request.getHeaders();String xIp = headers.getFirst("X-Real-IP");String xFor = headers.getFirst("X-Forwarded-For");if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {//多次反向代理后会有多个IP值,第一个IP才是真实IPint index = xFor.indexOf(",");if (index != -1) {return xFor.substring(0, index);} else {return xFor;}}xFor = xIp;if (StringUtils.isNotEmpty(xFor) && !"unKnown".equalsIgnoreCase(xFor)) {return xFor;}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = headers.getFirst("Proxy-Client-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = headers.getFirst("WL-Proxy-Client-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = headers.getFirst("HTTP-CLIENT-IP");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = headers.getFirst("HTTP_X_FORWARDED_FOR");}if (StringUtils.isBlank(xFor) || "unKnown".equalsIgnoreCase(xFor)) {xFor = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();}return xFor;}
}

spring 面向切面(AOP)编程例子相关推荐

  1. spring面向切面aop拦截器

    spring中有很多概念和名词,其中有一些名字不同,但是从功能上来看总感觉是那么的相似,比如过滤器.拦截器.aop等. 过滤器filter.spring mvc拦截器Interceptor .面向切面 ...

  2. Spring 详解(三):AOP 面向切面的编程

    AOP即面向切面编程,它通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型. ...

  3. Spring面向切面编程(AOP)详解

    Spring面向切面编程(AOP)详解 面向切面编程(AOP)是Spring框架的另外一个重要的核心内容. 而在讲AOP之前,先来了解一下动态代理这个概念,因为AOP基于动态代理. 动态代理概念:在程 ...

  4. Spring面向切面编程

           JAVA就业套餐课:https://edu.csdn.net/combo/detail/1230 第1章主要介绍了Spring管理实体对象的应用,通过ApplicationContext ...

  5. Spring→面向切面编程AOP、相关概念、通知Advice类型、配置切面切入点通知、AOP相关API、AOP代理类ProxyFactoryBean、AOP注解@AspectJ

    面向切面编程AOP CGLib AOP相关概念 Advice类型 Spring实现AOP Spring配置切面aspect 配置切入点pointcut 配置通知advice 配置通知参数 调用新的父类 ...

  6. Spring 面向切面编程(AOP) D5

    Spring AOP简介 问题提出 首先我们回顾一下OOP(Object Oriented Programming-面向对象编程),OOP引入了封装.继承.多态等概念建立了一种对象层次结构,用于模拟公 ...

  7. Spring——面向切面编程(AOP)

    1 AOP概述   AOP 并不是 Spring 框架的专属名称,它的全称是 Aspect Oriented Programming ,意为:面向切面编程.   在程序运行某个方法的时候,不修改原始执 ...

  8. java spring 面向切面编程_Spring Boot实战系列(3)AOP面向切面编程

    AOP是一种与语言无关的程序思想.编程范式.项目业务逻辑中,将通用的模块以水平切割的方式进行分离统一处理,常用于日志.权限控制.异常处理等业务中. 快速导航 编程范式主要以下几大类 AOP(Aspec ...

  9. Spring 面向切面编程

    AOP,也就是面向方面编程或者说面向面编程,是一种很重要的思想.在企业级系统中经常需要打印日志.事务管理这样针对某一方面的需求,但是传统的面向对象编程无法很好的满足这些需求.因此催生了面向切面编程这样 ...

  10. Spring——面向切面编程

    本文主要依据<Spring实战>第四章内容进行总结 1.面向切面编程术语 1.1.横切关注点 散布于应用中多处的功能被称为横切关注点,通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分 ...

最新文章

  1. 新手C#string类常用函数的学习2018.08.04
  2. 用R语言做词频统计_R语言 | 词频统计
  3. 用C#获取硬盘序列号,CPU序列号,网卡MAC地址
  4. switchcase的用法
  5. leetcode--5. 最长回文子串
  6. 第一章:初识lucene
  7. 《剑指Offer》 二进制中1的个数
  8. linux整个文件夹下全部文件的属性,C/C++遍历目录下的所有文件(Windows/Linux篇,超详细)...
  9. 深入理解Java中的反射技术
  10. CAS总结之Ticket篇
  11. 怎么隐藏php版本,Linux服务器中怎样隐藏PHP版本
  12. 页面加载完就执行的设置?
  13. 准时下班系列_Word合集之第1集—批量设置嵌入型图片解决方案
  14. 42表盘直径是从哪测量_表盘直径怎么算,怎样测量手表表盘的直径
  15. 奇偶校验原理及逻辑图
  16. (目标检测)①数据集的建立(拍摄收集、数据集标注)
  17. JAVA笔记---------字符串基础与操作
  18. 统一配置中心对比介绍
  19. 工具 | 如何对 MySQL 进行 TPC-C 测试?
  20. 米思齐Mixly图形化编程---遥控灯

热门文章

  1. elastic beats 开发
  2. 24周年,“常青树”Delphi发布新版本10.3.1
  3. 设计原则-合成复用原则
  4. SQL Sever查询事务隔离级别命令
  5. SQL CREATE INDEX (mysql 创建索引)语句
  6. 利用VBA将xls文件批量转为xlsx 2020-12-11
  7. C# DotNetty (1) EchoServer
  8. 帝国cms网站迁移到新的服务器,帝国cms网站管理系统网站迁移教程
  9. 对做了b、k扩展的工具链进行构建和测试
  10. 强制性认证覆盖百余种工业产品