2014-07-16 48 views
1

我想解耦發送通知電子郵件從事件導致他們。到目前爲止,我將一個郵件對象(DocumentIssuedMail)從控制器傳遞給Akka actor(EmailDispatcher),然後通過Play郵件程序插件的play-easymail封裝器發送郵件。郵件正文在被傳遞給actor後由郵件對象生成,HTML從Scala模板生成。渲染控制器外部的scala模板? (播放2)

此模板包含通過調用

@routes.SomeController.someAction().absoluteURL() 

然而,試圖呈現模板時,我得到一個RuntimeException具有絕對URL,獲得鏈接。

堆棧跟蹤如下:

java.lang.RuntimeException: There is no HTTP Context available from here. 
    at play.mvc.Http$Context.current(Http.java:30) 
    at play.mvc.Http$Context$Implicit.ctx(Http.java:196) 
    at play.core.j.PlayMagicForJava$.requestHeader(TemplateMagicForJava.scala:56) 
    at views.html.email._learner_main$.apply(_learner_main.template.scala:41) 
    at views.html.documents.email.new_doc_unregistered$.apply(new_doc_unregistered.template.scala:47) 
    at views.html.documents.email.new_doc_unregistered$.render(new_doc_unregistered.template.scala:67) 
    at views.html.documents.email.new_doc_unregistered.render(new_doc_unregistered.template.scala) 
    at email.DocumentIssuedMail.getUnregisteredMail(DocumentIssuedMail.java:71) 
    at email.DocumentIssuedMail.getMail(DocumentIssuedMail.java:67) 
    at actors.email.EmailDispatcher.onReceive(EmailDispatcher.java:32) 
    at akka.actor.UntypedActor$$anonfun$receive$1.applyOrElse(UntypedActor.scala:167) 
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498) 
    at akka.actor.ActorCell.invoke(ActorCell.scala:456) 
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237) 
    at akka.dispatch.Mailbox.run(Mailbox.scala:219) 
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386) 
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) 
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) 
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) 
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) 

是否有可能使在該位置的模板,或者我需要做的是原來的線程上?

回答

1

此問題的一種可能的解決方案是將http請求顯式傳遞給您的actor然後傳遞給郵件模板。

在模板中,你將這個請求到absoluteURL()方法

@(requestHeader: play.api.mvc.RequestHeader) 

@main("") { 
    @routes.Application.someAction().absoluteURL()(requestHeader) 
} 

隨着DocumentIssuedMail你需要傳遞給一個演員的請求。這是一個簡單的DTO。

import play.api.mvc.RequestHeader; 

public class DocumentIssuedMailWrapper { 
    private DocumentIssuedMail documentIssuedMail; 
    private RequestHeader requestHeader; 

    public DocumentIssuedMailWrapper(DocumentIssuedMail documentIssuedMail, RequestHeader requestHeader) { 
     this.documentIssuedMail = documentIssuedMail; 
     this.requestHeader = requestHeader; 
    } 

    public DocumentIssuedMail getDocumentIssuedMail() { 
     return documentIssuedMail; 
    } 

    public RequestHeader getRequestHeader() { 
     return requestHeader; 
    } 
} 

參與者將DTO的請求作爲普通參數傳遞給郵件模板。

import akka.actor.UntypedActor; 
import play.api.templates.Html; 
import views.html.mail; 

public class EmailDispatcher extends UntypedActor { 

    @Override 
    public void onReceive(Object message) throws Exception { 
     if (message instanceof DocumentIssuedMailWrapper) { 
      DocumentIssuedMailWrapper wrapper = (DocumentIssuedMailWrapper) message; 
      Html mailTemplate = mail.render(wrapper.getRequestHeader()); 
      //sending mail 
     } 
    } 

} 

在控制器,你可以通過調用CTX()._ requestHeader()方法得到的請求。現在,您只需要與演員安排一項工作,並將請求傳遞給DTO。

import akka.actor.ActorRef; 
import akka.actor.Props; 
import play.libs.Akka; 
import play.mvc.*; 

import scala.concurrent.duration.Duration; 

import java.util.concurrent.TimeUnit; 

public class Application extends Controller { 

    public static Result sendMail() { 
     DocumentIssuedMailWrapper wrapper = new DocumentIssuedMailWrapper(new DocumentIssuedMail(), ctx()._requestHeader()); 

     ActorRef emailDispatcher = Akka.system().actorOf(Props.create(EmailDispatcher.class)); 
     Akka.system().scheduler().scheduleOnce(Duration.create(0, TimeUnit.MILLISECONDS), emailDispatcher, wrapper, Akka.system().dispatcher(), null); 
     return ok("Mail sent"); 
    } 

    public static Result someAction() { 
     return ok("Some other action"); 
    } 

} 
+0

謝謝Daniel!這實際上與我提出的解決方案非常相似。最後,我們決定在conf文件中定義主機名,而不是從請求中使用主機,所以這都是沒有實際意義的。 :P – evanjdooner

+1

在我目前的項目中,我最終得到了一個類似的解決方案,並在application.conf中有主機名。我已經顯示的解決方案工作正常,如果你從控制器開始工作並有權訪問請求。如果你從Global運行一份工作,這個工作將不起作用。 –