1.攔截器
攔截器使您可以攔截對控制器的調用,并增強或阻止其行為。 在第一個示例應用程序中,我們向MyLogger添加了顯式調用,以將消息記錄到控制臺。 如果我們擴大規模,并且您想在每個控制器方法調用中都使用這個非常有用的插件,那么您將編寫大量樣板代碼。 攔截器使我們能夠自動應用動作,從而減少樣板。
1.1添加代碼
在app目錄中,創建一個名為action的新程序包。 在這里,我們將添加LogMe注釋,以及將在存在注釋時執行的LogMeAction。
此時,LogMe.java是一個非常簡單的注釋,不帶任何參數
package actions;import play.mvc.With;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author Steve Chaloner (steve@objectify.be)*/
@With(LogMeAction.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Inherited
@Documented
public @interface LogMe
{
}
看一下注釋,然后您將看到(LogInAction.class)–這讓Play知道遇到此注釋時,它應該在實際目標之前執行LogInAction。
package actions;import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;/*** @author Steve Chaloner (steve@objectify.be)*/
public class LogMeAction extends Action{@Overridepublic Result call(Http.Context context) throws Throwable{System.out.println("MyLogger: " + context.request().path());return delegate.call(context);}
}
這是非常優雅的東西–動作具有LogMe的通用參數類型,該參數類型可以訪問提供給LogMe批注的任何參數。 這使您可以自定義動作的行為。 當我們添加一些額外的功能時,我們將看到這一點。 一旦完成您的代碼(在本例中為System.out的另一個類),然后您將返回proxy.class(context)的結果以恢復正常的執行流程。 同時,如果將@LogMe添加到控制器方法,則操作的路徑將記錄到控制臺; 如果將@LogMe添加到控制器,則對該控制器中任何方法的調用都會導致該路徑記錄到控制臺。
1.2更新Build.scala
由于我們擁有新版本的mylogger,因此我們應該更改版本號。 打開項目/Build.scala并進行更改
val appVersion = "1.0-SNAPSHOT"
至
val appVersion = "1.1"
1.3確保已檢測到您的項目更改
如果您已經在mylogger / project-code中運行Play控制臺,則需要執行“重新加載”以獲取對Build.scala的更改。 如果未打開控制臺,請立即將其打開-更改將在啟動時自動進行。
[mylogger] $ reload
[info] Loading project definition from C:\Temp\mylogger\project-code\project
[info] Set current project to mylogger (in build file:/C:/Temp/mylogger/project-code/)
1.4清理并發布
如前所述,在發布之前進行清理始終是一個好主意,以確保您不會推出任何不應存在的對象。
[mylogger] $ clean
[success] Total time: 0 s, completed Mar 19, 2012 9:17:25 PM
[mylogger] $ publish-local
[info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1-
1.1 -sources.jar ...
[info] Done packaging.
[info] Wrote /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1- 1.1
.pom
[info] Updating {file:/tmp/mylogger/project-code/}mylogger...
[info] Done updating.
[info] :: delivering :: mylogger#mylogger_2.9.1;1.1 :: 1.1 :: release ::
Mon Mar 19 21:17:30 CET 2012
[info] Generating API documentation for main sources...
[info] Compiling 3 Java sources to /tmp/mylogger/project-code/target/scala-2.9.1
/classes...
[info] delivering ivy file to /tmp/mylogger/project-code/target/scala-2.9.1
/ivy- 1.1 .xml
model contains 7 documentable templates
[info] API documentation generation successful.
[info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1- 1.1
-javadoc.jar ...
[info] Done packaging.
[info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1- 1.1 .jar ...
[info] Done packaging.
[info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework
/../repository/local/mylogger/mylogger_2.9.1/ 1.1 /poms/mylogger_2.9.1.pom
[info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework
/../repository/local/mylogger/mylogger_2.9.1/ 1.1 /jars/mylogger_2.9.1.jar
[info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework
/../repository/local/mylogger/mylogger_2.9.1/ 1.1 /srcs/mylogger_2.9.1-sources.jar
[info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework
/../repository/local/mylogger/mylogger_2.9.1/ 1.1 /docs/mylogger_2.9.1-javadoc.jar
[info] published ivy to /home/steve/development/play/play-2.0/framework/../repository
/local/mylogger/mylogger_2.9.1/ 1.1 /ivys/ivy.xml
[success] Total time: 3 s, completed Mar 19, 2012 9:17:31 PM
請注意,模塊的版本在日志記錄中已更改。 如果仍然看到1.0-SNAPSHOT,請確保在發布之前重新加載了項目!
1.5更新示例應用程序
返回示例應用程序,在project / Build.scala中更改所需的模塊版本
val appDependencies = Seq("mylogger" % "mylogger_2.9.1" % "1.1")
重新加載并運行“依賴項”以確保您具有正確的版本。 現在,您可以更新app / controllers / Application.java以使用以下新代碼:
package controllers;import actions.LogMe;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;@LogMe
public class Application extends Controller
{public static Result index(){return ok(index.render("Your new application is ready."));}
}
運行此示例,現在您將看到通過注釋應用的MyLogger輸出。
2.添加了攔截器參數
僅記錄請求的路徑并不是特別有用或令人興奮。 如果應該為每種控制器或控制器方法提供特定的日志消息怎么辦? 在這種情況下,我們需要添加一些參數。
2.1更改注釋簽名
上載action / LogMe.java以使用value()參數-這是默認的注釋參數,因此在使用時無需顯式命名。 該值默認為空字符串,因此如果此處不存在此消息,則可以在操作中提供標準消息。
public @interface LogMe
{String value() default "";
}
在操作中,將繼承的配置字段鍵入通用參數(在本例中為LogMe),并提供對參數的訪問。 更新call(Http.Context)方法以利用此方法。
public Result call(Http.Context context) throws Throwable
{String value = configuration.value();if (value == null || value.isEmpty()){value = context.request().path();}System.out.println("MyLogger: " + value);return delegate.call(context);
}
2.2發布更改
再次重復步驟1.2至1.4,這次將appVersion更改為1.2
2.3更新示例應用程序
像以前一樣,在Build.scala中更新依賴項版本,重新加載并使用“ dependencies”進行確認。 現在,您可以向LogMe批注添加一條消息:
@LogMe("This is my log message")
public class Application extends Controller
運行該應用程序,現在您將在控制臺中看到注釋消息。
[info] play - Application started (Dev)
MyLogger: This is my log message
3.使攔截器交互
現在,您(希望)掌握了這個要訣,我們將加快一點。 在本節中,我們將研究攔截器如何相互交互。 Play首先將攔截器應用于方法,然后應用于控制器,因此,如果在方法和控制器級別都存在相同的注釋,它將執行兩次。 LogMe批注可以同時應用于類級別和方法級別,但是,如果您對整個控制器有一條通用的日志記錄消息,但一種方法需要使用另一條消息,那該怎么辦呢? 另外,我們只希望每次調用一個日志消息。 為此,我們可以使用傳遞給每個動作的上下文。
3.1更新模塊
更新LogMeAction以使其了解以前的調用:
package actions;import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;/*** @author Steve Chaloner (steve@objectify.be)*/
public class LogMeAction extends Action{public static final String ALREADY_LOGGED = "already-logged";@Overridepublic Result call(Http.Context context) throws Throwable{Result result;if (context.args.containsKey(ALREADY_LOGGED)){// skip the logging, just continue the executionresult = delegate.call(context);}else{// we're not using the value here, only the key, but this// mechanism can also be used to pass objectscontext.args.put(ALREADY_LOGGED, "");String value = configuration.value();if (value == null || value.isEmpty()){value = context.request().path();}System.out.println("MyLogger: " + value);result = delegate.call(context);}return result;}
}
更新版本號,清理,重新加載和本地發布。
3.2更新示例應用程序
這次,我們將在index方法中添加第二個注釋。 這將覆蓋控制器級別的注釋。 因此,更新Build.scala中的依賴項編號,重新加載并運行。
package controllers;import actions.LogMe;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;@LogMe("This is my log message")
public class Application extends Controller
{@LogMe("This is my method-specific log message")public static Result index(){return ok(index.render("Your new application is ready."));}
}
當您訪問http:// localhost:9000時,現在您將在控制臺中看到以下內容:
@LogMe("This is my log message")
[info] play - Application started (Dev)
MyLogger: This is my method-specific log message
4.又是啤酒時間
您現在擁有了支持參數化操作的基礎結構。 請記住,很多東西都可以作為注釋參數傳遞,但是-重要的是-并非所有東西都可以傳遞。 您可能需要為某些任務發揮創造力!
您可以在此處下載完整的源代碼。
參考: Play 2的編寫模塊,第2部分: Objective博客上JCG合作伙伴 Steve Chaloner的攔截器 。
翻譯自: https://www.javacodegeeks.com/2012/04/writing-modules-for-play-2-part-2.html