赞
踩
提示:随意记录
提示:以下是本篇文章正文内容,下面案例可供参考
注解在Java中,与类、接口、枚举类似,因此其声明语法基本一致,只是所使用的关键字有所不同@interface。在底层实现上,所有定义的注解都会自动继承java.lang.annotation.Annotation接口。
代码如下(示例):
@Target(ElementType.METHOD)//@Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。它使用一个枚举类型定义
@Retention(RetentionPolicy.RUNTIME)//@Retention注解,翻译为持久力、保持力。即用来修饰自定义注解的生命力。
//注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段。同样使用了
public @interface InterfaceLog {
String value() default "";
}
代码如下(示例):
import com.alibaba.fastjson.JSONObject; import com.opensymphony.xwork2.ActionContext; import org.apache.struts2.ServletActionContext; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; 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; @Aspect @Component public class InterfaceLogAspect { //private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired InterfaceCallLogServiceImpl interfaceCallLogService; @Pointcut("@annotation(com.XXXX.XXXXX.common.InterfaceLog)") private void pointCut() { } /** * 环绕通知 * * @param joinPoint 连接点 * @return 切入点返回值 * @throws Throwable 异常信息 */ @Around(value = "pointCut() && @annotation(around)") //around 与 下面参数名around对应 public Object apiLog(ProceedingJoinPoint joinPoint, InterfaceLog around) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); ActionContext context = ActionContext.getContext(); HttpServletRequest request = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST); String userAgent = request.getHeader("user-agent"); String ip = IpUtil.getIp(request); String methodName = this.getMethodName(joinPoint); String params = LogAspectUtil.getMethodParams(joinPoint); MethodSignature msig = (MethodSignature) joinPoint.getSignature(); Method pointMethod = joinPoint.getTarget().getClass().getMethod(msig.getName(), msig.getParameterTypes()); String methodPath = String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(), pointMethod.getName()); System.out.println("开始请求方法:[{"+methodName+"}] 服务:[{"+methodPath+"}] 参数:[{"+params+"}] IP:[{"+ip+"}] userAgent [{"+userAgent+"}]"); long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long end = System.currentTimeMillis(); String outResult = LogAspectUtil.deleteSensitiveContent(result); System.out.println("结束请求方法:[{"+methodName+"}] 参数:[{"+params+"}] 返回结果[{"+outResult+"}] 耗时:[{"+(end - start)+"}]毫秒 "); /** InterfaceCallLog interfaceCallLog = new InterfaceCallLog(); interfaceCallLog.setIlInterfaceName(methodName); JSONObject jsonObject = JSONObject.parseObject(params); interfaceCallLog.setIlCaller(jsonObject.get("caller")!=null?jsonObject.get("caller").toString():""); interfaceCallLog.setIlCallerIp(ip); interfaceCallLog.setIlInParameter(params); interfaceCallLog.setIlOutParameter(outResult); interfaceCallLogService.save(interfaceCallLog); */ return result; } private String getMethodName(ProceedingJoinPoint joinPoint) { String methodName = joinPoint.getSignature().toShortString(); String shortMethodNameSuffix = "(..)"; if (methodName.endsWith(shortMethodNameSuffix)) { methodName = methodName.substring(0, methodName.length() - shortMethodNameSuffix.length()); } return methodName; } }
代码如下(示例):
import com.opensymphony.xwork2.ActionContext; import org.apache.struts2.ServletActionContext; import javax.servlet.http.HttpServletRequest; /** * @description: * @projectName:sydj0112 * @see:com.XXX.XXX.util * @author:gongsi * @createTime:2021/4/26 9:06 * @version:1.0 */ public class IpUtil { public static String getIp(HttpServletRequest request){ String ip = null; //X-Forwarded-For:Squid 服务代理 String ipAddresses = request.getHeader("X-Forwarded-For"); if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //Proxy-Client-IP:apache 服务代理 ipAddresses = request.getHeader("Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //WL-Proxy-Client-IP:weblogic 服务代理 ipAddresses = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //HTTP_CLIENT_IP:有些代理服务器 ipAddresses = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //X-Real-IP:nginx服务代理 ipAddresses = request.getHeader("X-Real-IP"); } //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP if (ipAddresses != null && ipAddresses.length() != 0) { ip = ipAddresses.split(",")[0]; } //还是不能获取到,最后再通过request.getRemoteAddr();获取 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { ip = request.getRemoteAddr(); } // ip配置 if (ip.equals("127.0.0.1") || ip.endsWith("0:0:0:0:0:0:1")) { // 根据网卡取本机配置的IP ip = "127.0.0.1"; } return ip; } }
代码如下(示例):
import net.sf.json.JSONObject; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.web.multipart.MultipartFile; import org.testng.v6.Lists; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Field; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; /** * Created with IntelliJ IDEA. * Description: * AOP记录日志的一些共用方法 * @author LErry.li * Date: 2018-06-17 * Time: 15:19 */ public class LogAspectUtil { private LogAspectUtil(){ } /** * 获取需要记录日志方法的参数,敏感参数用*代替 * @param joinPoint 切点 * @return 去除敏感参数后的Json字符串 */ public static String getMethodParams(ProceedingJoinPoint joinPoint){ Object[] arguments = joinPoint.getArgs(); StringBuilder sb = new StringBuilder(); if(arguments ==null || arguments.length <= 0){ return sb.toString(); } for (Object arg : arguments) { //移除敏感内容 String paramStr; if (arg instanceof HttpServletResponse) { paramStr = HttpServletResponse.class.getSimpleName(); } else if (arg instanceof HttpServletRequest) { paramStr = HttpServletRequest.class.getSimpleName(); } else if (arg instanceof MultipartFile) { long size = ((MultipartFile) arg).getSize(); paramStr = MultipartFile.class.getSimpleName() + " size:" + size; } else { paramStr = deleteSensitiveContent(arg); } sb.append(paramStr).append(","); } return sb.deleteCharAt(sb.length() - 1).toString(); } /** * 删除参数中的敏感内容 * @param obj 参数对象 * @return 去除敏感内容后的参数对象 */ public static String deleteSensitiveContent(Object obj) { JSONObject jsonObject = new JSONObject(); if (obj == null || obj instanceof Exception) { return jsonObject.toString(); } List<String> sensitiveFieldList = getSensitiveFieldList(); if(obj instanceof Map<?,?>||obj instanceof Vector<?>||obj instanceof List<?>||obj instanceof Set<?>){ try { jsonObject = JSONObject.fromObject(obj); }catch (Exception e) { return String.valueOf(obj); } }else{ Class cls = obj.getClass(); Field[] fields = cls.getDeclaredFields(); for(int i=0; i<fields.length; i++){ Field f = fields[i]; f.setAccessible(true); try { if(f.get(obj)!=null){ jsonObject.put(f.getName(),f.get(obj)); } } catch (IllegalAccessException e) { e.printStackTrace(); } } } for (String sensitiveField : sensitiveFieldList) { if (jsonObject.containsKey(sensitiveField)) { String value=jsonObject.get(sensitiveField).toString(); value = desensitization(value); jsonObject.put(sensitiveField,value); } } return jsonObject.toString(); } /** * 敏感字段列表(当然这里你可以更改为可配置的) */ private static List<String> getSensitiveFieldList() { List<String> sensitiveFieldList = Lists.newArrayList(); sensitiveFieldList.add("pwd"); sensitiveFieldList.add("password"); return sensitiveFieldList; } /** * 敏感字段列表(当然这里你可以更改为可配置的) */ private static String desensitization(String value) { if (value.length() < 1) { value = "****"; } else if (value.length() == 1) { value = "*" + value; } else if (value.length() == 2) { value = "*" + value.substring(1); } else if (value.length() == 3) { value = "**" + value.substring(2); } else if(value.length() > 3 && value.length() < 7) { value = value.substring(0,2) + "****" + value.substring(3); }else{ value = value.substring(0,2) + "****" + value.substring(value.length()-4); } return value; } }
注意:1.使用spring boot时aop注解@Component会自动生效。
2.使用springMvc 时,aop无效;
查询发现Spring与SpringMVC是2个不同的父子容器, @Aspect如果被spring容器加载的话,而@Controller注解的这些类的实例化以及注入却是由SpringMVC来完成。 @Aspect如果被spring容器加载的时候,可能Spring MVC容器还未初始化, Controller类还未初始化,所以无法正常织入。
解决:把 aop:aspectj-autoproxy 从applicationContext.xml移入springmvc配置文件中,并定义bean,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 这个配置一定要配置在component-scan以后 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <bean id="paramValidAspect" class="com.gs.log.LogAspect"/>
注意:做一次记录
create table INTERFACE_CALL_LOG
(
il_cdate DATE,
il_udate DATE,
il_status VARCHAR2(8),
il_ord NUMBER,
il_interface_name VARCHAR2(800),
il_caller_ip VARCHAR2(48),
il_caller VARCHAR2(200),
il_in_parameter CLOB,
il_out_parameter CLOB
)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。