>  기사  >  Java  >  Java 개발 사례: springMVC는 AOP를 사용하여 액세스 로그를 관리합니다.

Java 개발 사례: springMVC는 AOP를 사용하여 액세스 로그를 관리합니다.

无忌哥哥
无忌哥哥원래의
2018-07-20 10:51:102975검색

1. 설명

최근에 개인 웹사이트를 만들겠다는 생각이 떠올라 프로그래밍의 여정을 시작했습니다. 모자 한 방울에. 프로젝트 프레임워크(SpringMVC+mybatis+mysql)가 빌드된 후 프로젝트의 로그 디자인에 대해 생각해 보세요. 검토 후 온라인 정보와 결합하여 주석을 사용하여 액세스 로그를 기록하기로 결정했습니다. 물론 현재의 로그 디자인은 아직 완벽하지 않으며 개발 과정에서 점차 개선될 예정입니다.

2. 구현

2.1 AOP 및 관련 이해

relative AOP와 관련하여 많은 사람들이 인터셉터를 사용하여 로그를 관리하는 것을 선호합니다. 이는 개인적인 생각에 따라 다릅니다. 그렇다면 AOP 차단 컨트롤러를 구현하는 방법은 무엇입니까? 기본적으로 컨트롤러는 프록시를 위해 jdk에 넘겨지므로 AOP가 컨트롤러를 가로챌 수 있으면 cglib 프록시에 할당해야 합니다.

다음은 AOP 차단 컨트롤러에서 사용하는 주석에 대한 소개입니다(빨간색으로 표시된 필드는 사용될 주석을 나타냅니다). 물론 구성 파일을 사용하여 정의할 수도 있지만 개인적으로 그렇습니다. 저는 모듈을 중앙 집중화하는 것을 선호합니다. 함께 구성 파일을 찾는 것이 정말 피곤합니다~

@Target: 주석의 목적, 즉 주석이 영향을 미칠 개체. 포함:#🎜🎜 ## 🎜🎜#Elementtype.type 인터페이스, 클래스, 열거, 주석

##Elementtype.field 필드, 열거 상수

🎜🎜

🎜 🎜

🎜🎜

🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜# #ElementType.METHOD                                                                                  

# 🎜🎜#ElementType.PARAMETER                                                메소드의 매개변수

#🎜🎜 생성자 유형.LOCAL_VARIABLE       ~ > > # @Retention: 주석의 수명 주기를 설명하는 데 사용되는 주석의 보존 위치입니다. 일반 용어로 @Retention 주석은 주석이 적용되는 범위 또는 조건을 정의하는 역할을 합니다. #🎜🎜 ###RETENTIONPOLICY.SOURCE Note는 소스 코드에만 존재하며 포함되지 않습니다#🎜🎜 ## 🎜🎜#ReTentionPolicy.class의 클래스 바이트코드 파일에 있는 기본 예약 전략은 파일에 존재하지만 그럴 수는 없습니다.                                런타임 시 리플렉션을 통해 얻을 수 있음#🎜🎜 #

          #🎜🎜 #

@Document: 다음을 나타냅니다. 주석은 주석 위의 javadoc에 포함되며

@Inherited, @Repeatable

주석을 Java에서는 메타 주석이라고 합니다. 메타 주석이란 무엇입니까?

메타 주석의 역할은 다른 주석에 주석을 다는 것입니다. Java5.0은 다른 주석 유형에 대한 설명을 제공하는 데 사용되는 네 가지 표준 메타 주석 유형을 정의합니다. #🎜🎜 ## 关于#Annotation 및 Meta Annotation에 대한 설명은 여기를 클릭하세요#🎜🎜 ## 🎜🎜#@aspect: @Aspect 선언 및 클래스 종류가 있을 때. 현재 컨테이너는 이 클래스를 읽을 수 있지만 cglib 에이전트가 켜져 있는 경우에만 가능합니다.

@Component: 클래스를 빈으로 선언하고 컨테이너에 주입하면 스프링이 시작 시 이를 스캔하고 로드합니다. 효과는 구성 파일에서 Bean을 정의하는 것과 동일합니다.

@Pointcut: 이 주석을 사용한 후 다른 메서드에서 참조할 수 있습니다. #🎜🎜 ## 与#and@aspect,@POINTCUT에는 향상된 주석이라고도 하는 5개의 알림 유형 주석도 있습니다.

🎜🎜#@장소 알림 전에 실행#🎜 🎜 ## 🎜🎜 ## 🎜🎜#@#@aft post 알림

@Aterreturning Rear [TRY] 알림 [try] 메소드 반환 값을 참조하려면 return을 사용하세요.                 @Around Surround 알림, 상단에 배치 이 메서드는 실제 메서드가 실행되는지 여부를 결정하며 반환 값이 있어야 합니다.

🎜🎜#

2.2 cglib 에이전트 구성

#🎜 🎜#다음 코드 추가 spring-mvc.xml 파일에:

<aop:aspectj-autoproxy proxy-target-class="true" />
2.3 로그 정보를 설명하는 사용자 정의 주석

General 사용자 정의 주석을 생성할 때 @를 사용하여 인터페이스를 사용하면 이 클래스가 기본적으로 주석을 상속하게 됩니다. 코드는 다음과 같습니다:

package com.t1heluosh1.system.log.annotion;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 日志controller层注解
 * 
 * @author xuyong
 *
 */
//作用于参数和方法上
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysControllerLog {

	int logType() default 100;				//日志类型,默认为100-系统
	
	int module() default 100;				//操作模块,默认为100-登录
	
	String description() default "";		//操作描述
}

사용자 정의 주석이 생성된 후 주석을 컨테이너에 빈으로 삽입하고 다음 코드를 spring-mvc.xml 파일에 추가해야 합니다. #🎜 🎜#

<context:component-scan base-package="com.t1heluosh1.system.log" >
         <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

2.4 로깅 기능을 구현하기 위한 관점 클래스 정의

여기서는 더 이상 말할 것이 없습니다. 코드를 살펴보세요.

package com.t1heluosh1.system.log.aspect;

import java.lang.reflect.Method;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.t1heluosh1.pullulate.biz.sysLog.service.SysLogService;
import com.t1heluosh1.pullulate.biz.sysLog.vo.SysLogVo;
import com.t1heluosh1.pullulate.biz.user.model.User;
import com.t1heluosh1.system.constant.SysParams;
import com.t1heluosh1.system.log.annotion.SysControllerLog;
import com.t1heluosh1.util.IPUtil;


/**
 * 日志切点类即实现类
 * 
 * @author xuyong
 *
 */
@Aspect  
@Component 
public class SysLogAspect {

	//本地异常日志记录对象
	private static final Logger logger = Logger.getLogger(SysLogAspect.class);
	
	@Resource
	private SysLogService logService;
	
	
	//切入点定义:controller
	@Pointcut("@annotation(com.t1heluosh1.system.log.annotion.SysControllerLog)")
	public void controllerAspect() {
		System.out.println("---------------------controllerAspect for log start----------------------------");
	}
	
	
	
	/**
	 * controller切入点方法实现
	 * 
	 * @param joinPoint
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) {
		 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder  
	                .getRequestAttributes()).getRequest();
		 
		 //获取登录用户的信息
		 User user = (User)request.getSession().getAttribute(SysParams.CURRENT_USER);
		 
		 //获取请求IP地址
		 String ip = IPUtil.getRemoteHost(request);
		 
		 try {
			 String methodDesc = getControllerMethodDescription(joinPoint);
			 System.out.println("request method : " + joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName()+"()");
			 System.out.println("method description : " + methodDesc);
			 System.out.println("request username : " + (user==null?"no login info found":user.getUserName()));
			 
			 System.out.println("request ip address : "+ ip);
			 
			 System.out.println("insert log infos into db start ...");
			 
			 //获取相关日志参数
			 Object[] orgs = joinPoint.getArgs();
			 SysLogVo sysLogVo = null;
			 if (orgs != null && orgs.length > 0) {
				 for (Object obj:orgs) {
					 if (obj instanceof SysLogVo)
						 sysLogVo = (SysLogVo)obj;
					 
				 }
			 }
			 if (sysLogVo == null) {
				 sysLogVo = new SysLogVo();
			 }
			 //执行日志入库操作
			 
			 //获取注解的信息
			 MethodSignature ms = (MethodSignature)joinPoint.getSignature();
			 Method method = ms.getMethod();
			 SysControllerLog log = method.getAnnotation(SysControllerLog.class);
			 sysLogVo.setLogType(log.logType());
			 sysLogVo.setModule(log.module());
			 sysLogVo.setIpAddr(ip);
			 sysLogVo.setUrl(request.getRequestURI());
			 sysLogVo.setMethodName(joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName()+"()");
			 sysLogVo.setMethodDesc(methodDesc);
			 //TODO:remark可根据业务来进行改变,暂时为方法描述
			 sysLogVo.setRemark(log.description());
			 Date date = new Date();
			 sysLogVo.setAddTime(date);
			 sysLogVo.setAddUser(user==null?SysParams.ADMIN_ID:String.valueOf(user.getId()));
			 sysLogVo.setUpdateTime(date);
			 sysLogVo.setUpdateUser(user==null?SysParams.ADMIN_ID:String.valueOf(user.getId()));
			 logService.save(sysLogVo);
			 System.out.println("insert log infos into db successful.");
		 } catch (Exception e) {
			 logger.error("--------------controllerAspect for log fail-----------------------");  
	         logger.error("exception info : ", e);  
		 }
		 
	}
	
	 
	/**
	 * 获取方法的描述
	 * 
	 * @param joinPoint
	 * @return
	 * @throws Exception 
	 */
	@SuppressWarnings("rawtypes")
	private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		 //获取目标类名  
        String targetName = joinPoint.getTarget().getClass().getName();  
        //获取方法名  
        String methodName = joinPoint.getSignature().getName();  
        //获取相关参数  
        Object[] arguments = joinPoint.getArgs();  
        //生成类对象  
        Class targetClass = Class.forName(targetName);  
        //获取该类中的方法  
        Method[] methods = targetClass.getMethods();  
          
        String description = "";  
          
        for(Method method : methods) {  
            if(!method.getName().equals(methodName)) {  
                continue;  
            }  
            Class[] clazzs = method.getParameterTypes();  
            if(clazzs.length != arguments.length) {  
                continue;  
            }  
            description = method.getAnnotation(SysControllerLog.class).description();  
        }  
        return description;  
	}
	
	
}
#🎜🎜 #2.5 데모 사용

구체적인 방법은 다음과 같습니다.

/**
	 * 跳转到登陆页面
	 * 
	 * @param request
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping(value="login")
	@SysControllerLog(description="跳转到登录页面",logType=100,module=100)
	public ModelAndView gotoLogin(HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView("/show/login");
		return modelAndView;
	}

사용자가 페이지를 새로 고치면 콘솔이 관련 액세스 정보를 인쇄하고 해당 정보를 도서관에 입력하십시오. 물론, 로그의 사용 여부는 프로젝트에 따라 결정되어야 하며, 각 방법 앞에 주석을 추가해야 합니다. 첫째, 시스템 성능에 영향을 미치고 둘째, 여전히 로그를 기록하는 방식입니다. 성적인 코드에 대한 특정 침입이 있습니다. 마지막으로 데이터베이스에 기록된 정보를 살펴보세요.

위 내용은 Java 개발 사례: springMVC는 AOP를 사용하여 액세스 로그를 관리합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.