1. 説明
最近、私は個人のウェブサイトを作成するというアイデアを思いつき、突然プログラミングを始めました。プロジェクト フレームワーク (SpringMVC+mybatis+mysql) が構築されたら、プロジェクト内のログの設計を検討し始めます。オンライン情報と組み合わせて検討した結果、アノテーションを使用してアクセス ログを記録することにしました。もちろん、現在のログ設計はまだ完璧ではなく、開発プロセス中に徐々に改善される予定です。
2. 実装
2.1 AOP と関連コメントについて
AOP と比較して、多くの人はログの管理にインターセプターを使用することを好みます。では、AOP インターセプト コントローラーを実装するにはどうすればよいでしょうか?デフォルトでは、コントローラーはプロキシ用に jdk に渡されるため、AOP がコントローラーをインターセプトできる場合は、コントローラーを cglib プロキシに割り当てる必要があります。
以下は、AOP を使用してコントローラーで使用されるアノテーションをインターセプトする方法の概要です (赤でマークされたフィールドは、使用されるアノテーションを表します) もちろん、設定ファイルを使用してそれらを定義することもできますが、個人的にはグループ化することを好みます。モジュールをまとめて構成ファイルを見つけるのは本当に面倒です~
@Target: アノテーションの目的、つまり、アノテーションが影響を与えるオブジェクト。 incluseType.Type ElementType
elementType.Annotation_Type @retentionの構成要素:アノテーションの保持位置。保持アノテーション アノテーションが有効になる範囲または条件を定義します。 ‐ ‐ ‐ ‐ ‐ to ‐ ‐ ‐ to RetentionPolicy.CLASS デフォルトの保持ポリシー、注釈はクラスのバイトコード ファイルに存在しますが、実行時に取得できませんPRETENTIONPOLICY.Runtime Noteクラスのバイトコード ファイルに存在します。
@Document: アノテーションが Javadoc に含まれることを示し、さらに javadoc のアノテーションが追加されます。
@Inherited および @Repeatableアノテーションは次のとおりです。 Javaではメタアノテーションと呼ばれます。メタアノテーションとは何ですか?
メタアノテーションの役割は、他のアノテーションに注釈を付けることです。 Java5.0 では、他のアノテーション タイプの説明を提供するために使用される 4 つの標準メタアノテーション タイプが定義されています。
と一緒に使うと合わせて使います。現時点では、コンテナはこのクラスを読み取ることができますが、それは cglib エージェントがオンになっている場合に限られます。
@Component: クラスを Bean として宣言し、それをコンテナーに注入します。Spring は起動時にそれをスキャンしてロードします。その効果は、構成ファイルで Bean を定義するのと同じです。 C @pointcut: メソッドレベルのアノテーションは、このアノテーションを使用した後、他のメソッドで引用できます。 E 拡張アノテーションとも呼ばれる、@aspect および @PointCut を使用した 5 種類の通知タイプのアノテーションもあります。 @Aterreturning リア [TRY] 通知、メソッド ヘッダーに配置、RETURNING を使用してメソッドを引用して値を返す
@aFTERTHROWING リア [CATCH] 通知、メソッド ヘッダーに配置、throw を使用して異常を引用
@Around サラウンド通知、メソッド ヘッダーに配置します。このメソッドは実際のメソッドが実行されるかどうかを決定する必要があり、戻り値が必要です
2.2 設定 CGLIB エージェント Spring-MVC に次のコードを追加します.XML ファイル: <aop:aspectj-autoproxy proxy-target-class="true" />
eeeeee
通常、カスタム アノテーションを作成する場合、@interface を使用すると、このクラスはデフォルトでアノテーションを継承します。コードは次のとおりです:
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 ""; //操作描述 }
カスタム アノテーションが作成された後、アノテーションを Bean としてコンテナに挿入し、次のコードを 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 中国語 Web サイトの他の関連記事を参照してください。