当前位置: 首页 > 知识库问答 >
问题:

从thymeleaf电子邮件模板访问应用程序上下文bean

尉迟卓
2023-03-14

我遵循了这篇Thymeleaf教程“使用Thymeleaf在Spring生成丰富的HTML电子邮件”,使用Thymeleaf模板生成了一封电子邮件。一切正常,但我无法访问应用程序中其他地方使用的ApplicationContext bean。

更具体地说,在我的电子邮件模板中,我希望有如下内容:

<span th:text="${@myBean.doSomething()}">

其中“myBean”是一个@组件。这可能吗?我不是在寻找像这样的解决方法

<span th:text="${myBean.doSomething()}">

其中bean作为变量添加到模板处理上下文中。

配置:

@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
public class MyWebConfig extends WebMvcConfigurerAdapter {
[....]
public ClassLoaderTemplateResolver emailTemplateResolver() {
    ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
    resolver.setPrefix("emailtemplates/");
    resolver.setSuffix(".html");
    resolver.setCharacterEncoding("UTF-8");
    resolver.setTemplateMode("HTML5");
    return resolver;
}

@Bean
public SpringTemplateEngine emailTemplateEngine() {
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.addTemplateResolver(emailTemplateResolver());
    engine.addDialect(new LayoutDialect()); // thymeleaf-layout-dialect
    addSpringSecurityDialect(engine); // thymeleaf-SpringSecurity-dialect
    return engine;
}
[....]
}

电子邮件服务:

@Service
public class MyEmailService {
@Resource SpringTemplateEngine emailTemplateEngine;
[....]
public boolean sendHtmlEmail(...) {
    final Context ctx = new Context(locale);
    ctx.setVariable("someVariable", "someValue"); // Don't want to add myBean here
    final String body = this.emailTemplateEngine.process("myTemplate", ctx);
    [....]

组件:

@Component
public class MyBean {
    public String doSomething() {
        return "Something done!";
    }
}

模板:

<span th:text="${@myBean.doSomething()}">

错误:

EL1057E:(位置1):上下文中没有注册bean解析器来解析对bean“myBean”的访问

我正在使用thymeleaf-2.1.4和spring-4.1.6

编辑:

请注意,我不能使用HttpServletRequest,因为我以@Async方法发送大部分电子邮件,其中请求不能可靠地使用。这就是我使用Context而不是WebContext的原因(尽管我不知道SpringWebContext-我想如果有人制作了通过“bean”变量访问bean的类,那么使用@myBean表示法一定是不可能的)。

共有3个答案

步联
2023-03-14

只需将完整的上下文放在MeleAF上下文中

@Service
   public class MyEmailService {
   @Resource SpringTemplateEngine emailTemplateEngine;
   [....]
   public boolean sendHtmlEmail(...) {
       final Context ctx = new Context(locale);
      ctx.setVariable("beans", new Beans(appContext)); 
    final String body = this.emailTemplateEngine.process("myTemplate", ctx);
      [....]



<span th:text="${beans.myBean.doSomething()}">

@符号可能是个问题,因为如果我理解正确的话,模板a将使用spring el表达式进行计算。也许这是可以做到的,但会很耗时。

长孙泉
2023-03-14

找到后,您需要在SpringWebContext中添加一个bean解析器。Bean Resolver由ThymeleafEvalue ationContext创建。

    Map<String, Object> mergedModel = new HashMap<>();
    ConversionService conversionService = (ConversionService) this.request
            .getAttribute(ConversionService.class.getName()); // might be null!
    ThymeleafEvaluationContext evaluationContext = new ThymeleafEvaluationContext(this.ac,
            conversionService);
    mergedModel.put(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME,
            evaluationContext);
    SpringWebContext ctx = new SpringWebContext(this.request, this.response,
            this.request.getServletContext(), this.request.getLocale(), mergedModel, this.ac);
魏冷勋
2023-03-14

这很令人困惑,因为我们这里有三种不同的背景:

  • 如果我们以计划的方式发送邮件,则Spring应用程序上下文不是WebApplicationContext
  • 胸腺组织。百里香叶。上下文设置/添加变量的上下文
  • SpEL评估上下文组织。springframework。表示EvaluationContext,用于计算SpEL表达式。对于Thymeleaf,这是ThymeleafEvaluationContext

如果没有Spring web上下文,只需将引用应用程序上下文的ThymeleafEvaluationContext添加到Thymeleaf上下文中作为变量:

静态编程语言

@Service
class TemplateService(
        private val templateEngine: TemplateEngine,
        private val applicationContext: ApplicationContext
) {

    fun processTemplate(locale: Locale, template: String, vararg variables: Pair<String, Any?>): String {
        val context = Context(locale)

        // Set the Thymeleaf evaluation context to allow access to Spring beans with @beanName in SpEL expressions
        context.setVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME,
                ThymeleafEvaluationContext(applicationContext, null))

        // Set additional variables
        variables.forEach { (key, value) -> context.setVariable(key, value) }

        return templateEngine.process(template, context)
    }
}
 类似资料:
  • 我有一个spring mvc应用程序,我试图将日期LocalDate呈现为字符串,对于普通视图,它可以工作,但对于电子邮件,它不工作,并抛出以下错误: 原因:org.springframework.core.convert.converterNotFoundException:找不到能够从[java.time.localdate]类型转换为[java.lang.string]类型的转换器 代码:

  • 最直接的例子可能是处理表单或输入: app/app.component.html 这不是一个只有表单或输入的神奇功能,而是一种引用模板中子组件实例的方法。使用该引用,您可以访问该组件的公共属性和方法。 app/profile.component.ts

  • 我正在开发一个应用程序,它在iframe中使用DocuSign签名,该应用程序位于一个专有的web应用程序中。签名者可以在同一个web应用程序中访问嵌入的iframe签名视图。 编辑:已解决 正如在答案的注释中提到的,通过根据收件人的值正确设置每个模板角色的ClientUserId,这个问题得到了解决。这允许使用模板角色签名者进行嵌入签名。

  • 编写一个简单的spring程序从filepathxmlapplication上下文中读取bean,但得到以下异常。 但我确信在可以访问xml bean定义文件。

  • 问题内容: 在我的AngularJS Web应用程序之一中,我需要通过向相关人员发送电子邮件来确认密码。如何在AngularJS中实现呢?我是.NET专家,正在使用Visual Studio 2013。 问题答案: 我已经通过网络服务实现了,请参考下面的代码片段 和ajax调用为