我正在尝试将通知电子邮件的发送与导致通知电子邮件的事件分离。到目前为止,我将邮件对象 (DocumentIssuedMail
) 从 Controller 传递到 Akka actor(EmailDispatcher
),然后通过 Play 邮件程序插件的 play-easymail 包装器发送邮件。电子邮件正文由邮件对象在传递给参与者后生成,并且 HTML 是从 Scala 模板生成的。
此模板包含带有绝对 URL 的链接,通过调用获取
@routes.SomeController.someAction().absoluteURL()
但是,我在尝试渲染模板时遇到了 RuntimeException。
堆栈跟踪如下:
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)
是否可以在该位置渲染模板,或者我是否需要在原始线程上进行渲染?
最佳答案
此问题的一个可能的解决方案是将 http 请求显式传递给您的参与者,然后传递给邮件模板。
在模板中,您将此请求传递给 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
}
}
}
在 Controller 中,您可以通过调用 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");
}
}
关于java - 在 Controller 之外渲染 scala 模板? ( Play 2),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24786681/