今回は、Aspectクラスで対象メソッドの引数・戻り値・メソッド名・リクエストURLを取得してみたので、そのサンプルプログラムを共有する。
前提条件
下記記事の実装が完了していること。
IntelliJ IDEA上でGradleを使ってWeb画面のSpring Bootプロジェクトを作成してみたSpring Bootのプロジェクトを新規作成を「IntelliJ IDEA」のメニューから実施しようとしたところ、無料の「Commun...
サンプルプログラムの作成
作成したサンプルプログラムの構成は以下の通り。
なお、上記の赤枠は、前提条件のプログラムから変更したプログラムである。
アスペクトクラスの内容は以下の通りで、endLogメソッド内で、対象メソッドの引数・戻り値・メソッド名・リクエストURLを取得している。
package com.example.demo; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; 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 javax.servlet.http.HttpServletRequest; @Aspect @Component public class DemoInvocation { //ログ出力のためのクラス private Logger logger = LogManager.getLogger(DemoInvocation.class); /** * Beforeアノテーションにより、指定したメソッドの前に処理を追加する * Beforeアノテーションの引数には、Pointcut式 execution(戻り値 パッケージ.クラス.メソッド(引数))を * 指定し、ここではControllerクラスの全メソッドの実行前にログ出力するようにしている * * @param jp 横断的な処理を挿入する場所 */ @Before("execution(public * com.example.demo.*Controller.*(..))") public void startLog(JoinPoint jp){ //開始ログを出力 String signature = jp.getSignature().toString(); logger.info("開始ログ : " + signature); } /** * AfterReturningアノテーションにより、指定したメソッドが正常終了した場合に、 * 指定したメソッドの後に処理を追加する * AfterReturningアノテーションの引数には、Pointcut式を指定 * * @param jp 横断的な処理を挿入する場所 * @param returnValue 指定したメソッドの戻り値 */ @AfterReturning(value = "execution(public * com.example.demo.*Controller.*(..))" , returning = "returnValue") public void endLog(JoinPoint jp, Object returnValue){ //引数を取得しログに出力 logger.info("引数 : " + getArgStr(jp)); //戻り値を取得しログに出力 logger.info("戻り値 : " + returnValue); //メソッド名を取得しログに出力 String methodName = ((MethodSignature)jp.getSignature()).getMethod().getName(); logger.info("メソッド名 : " + methodName); //リクエストURLを取得しログに出力 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) .getRequest(); logger.info("リクエストURL : " + request.getRequestURL().toString()); //終了ログを出力 String signature = jp.getSignature().toString(); logger.info("終了ログ : " + signature); logger.info(""); } /** * 指定したメソッドの引数の文字列を取得する * * @param jp 横断的な処理を挿入する場所 * @return 指定したメソッドの引数 */ private String getArgStr(JoinPoint jp){ StringBuilder sb = new StringBuilder(); Object[] args = jp.getArgs(); if(args.length > 0){ for(Object arg : args){ sb.append(arg + ", "); } sb.delete(sb.length() - 2, sb.length() - 1); }else{ sb.append("(なし)"); } return sb.toString(); } }
また、コントローラクラス・Formクラスの内容は以下の通り。
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.servlet.ModelAndView; @Controller @SessionAttributes(types = DemoForm.class) public class DemoController { /** * Formオブジェクトを初期化して返却する * @return Formオブジェクト */ @ModelAttribute("demoForm") public DemoForm createDemoForm(){ DemoForm demoForm = new DemoForm(); return demoForm; } /** * 初期表示画面に遷移する * @return 初期表示画面へのパス */ @GetMapping("/") public String index(){ return "index"; } /** * 確認画面に遷移する * @param demoForm demoFormオブジェクト * @param mav ModelAndViewオブジェクト * @return ModelAndViewオブジェクト */ @PostMapping("/confirm") public ModelAndView confirm(DemoForm demoForm, ModelAndView mav){ System.out.println("demoForm name : " + demoForm.getName()); mav.setViewName("confirm"); return mav; } }
package com.example.demo; import lombok.Data; @Data public class DemoForm { /** 名前 */ private String name; }
さらに、HTMLファイルの内容は以下の通り。
<!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>入力画面</title> </head> <body> <p>下記必要事項を記載の上、「確認」ボタンを押下してください。</p><br/> <form method="post" th:action="@{/confirm}" th:object="${demoForm}"> 名前: <input type="text" th:value="*{name}" th:field="*{name}" /> <br/><br/> <input type="submit" value="確認" /> </form> </body> </html>
<!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>確認画面</title> </head> <body> <p>入力内容を確認してください。</p><br/> <form method="post" th:object="${demoForm}"> <span th:text="'名前: ' + *{name}">ここに名前が表示されます</span> <br/><br/> <input type="button" value="戻る" onclick="history.back();" /> </form> </body> </html>
フリーランスエンジニアのエージェントは就業中でも無料で登録できるITエンジニアには、フリーランスという働き方がある。 フリーランスとは、会社や団体などに所属せず、仕事に応じて自由に契約する人のこ...
その他、build.gradle、application.propertiesの内容は以下の通り。
plugins { id 'org.springframework.boot' version '2.1.7.RELEASE' id 'java' } apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' //AOPを利用するための設定 implementation 'org.springframework.boot:spring-boot-starter-aop' //lombokを利用するための設定 compileOnly 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10' }
server.port = 8084 logging.level.root = INFO logging.level.com.example.demo = DEBUG logging.file = C:/work/logs/demo.log
サンプルプログラムの実行結果
サンプルプログラムの実行結果は、以下の通り。
1) Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下の画面が表示される
2) このときのログ出力内容は以下の通りで、赤枠の引数・戻り値・メソッド名・リクエストURLが出力されていることが確認できる
3) 画面上で名前を入力し、「確認」ボタンを押下すると、以下のように、確認画面に入力した名前が表示される
4) このときのログ出力内容は以下の通りで、赤枠の引数・戻り値・メソッド名・リクエストURLが出力されていることが確認できる
要点まとめ
- Aspectクラスで、JoinPointクラス等を利用して、対象メソッドの引数・戻り値・メソッド名・リクエストURLを取得することができる。