StandardEvaluationContext中的Spring StandardTypeLocator:注册新的导入前缀以在Thymeleaf模板中使用

问题描述 投票:0回答:3

我们正在使用视图层中的Thymeleaf模板库开发Spring MVC(v4)Web应用程序,并使用Thymeleaf SpringTemplateEngine提供SPEL支持。

当我们在模板中引用类型时(例如,访问静态实用程序方法或枚举),我们必须包含完全限定名称,因为Spring StandardEvaluationContext StandardTypeLocator默认只知道java.lang包。我可以在Spring API中看到我们需要使用registerImport(String prefix)方法将我们自己的包添加到类型定位器中,但我无法弄清楚如何获取模板中使用的默认评估上下文能够做到这一点。

我希望通过替换这类东西来消除我们的Thymeleaf HTML模板:

T(org.apache.commons.io.FileUtils).byteCountToDisplaySize(1024)

附:

T(FileUtils).byteCountToDisplaySize(1024)

我尝试将一个EvaluationContext自动装入一个控制器,看看我是否可以抓住它,但Spring告诉我没有找到符合条件的bean。任何建议赞赏!

java spring spring-mvc spring-el
3个回答
2
投票

我正在使用基于JAVA的spring配置。所以在spring安全配置类(必须有@EnableGlobalMethodSecurity(prePostEnabled = true)注释)中,我正在注入一个自定义的MethodSecurityExpressionHandler bean:

    @Bean
    public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
      DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler() {

        @Override
        public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) {

          StandardEvaluationContext evaluationContext = super.createEvaluationContextInternal(auth, mi);

          //Register custom package paths, since StandardTypeLocator is only aware of "java.lang"
          //So there will be no need to provide a fully qualified path
          ((StandardTypeLocator) evaluationContext.getTypeLocator()).registerImport("desired.path");

          return evaluationContext;
        }
      };

      expressionHandler.setPermissionEvaluator(new ExpressionAccessPermissionEvaluator()); //register some custom PermissionEvaluator if any
      return expressionHandler;
    }
  }

谢谢


1
投票

我不确定这是否解决了您的问题,但是ThymeleafViewResolver类具有addStaticVariable方法,该方法在处理视图之前将变量添加到上下文中。

我做了一点测试:

@Autowired
ThymeleafViewResolver thymeleafViewResolver;

@PostConstruct
public void postConstruct() {
    thymeleafViewResolver.addStaticVariable("myUtil", new StringUtils());
}

使用如下的StringUtils:

public class StringUtils {
    public static String print() {
        return "Printed";
    }
}

并且观点:

<div th:text="${T(some.package.StringUtils).print()}">Test</div>
<div th:text="${myUtil.print()}">Test</div>

两者都很好。如果您的方法不是静态的,后者也会起作用。

希望能帮助到你。


0
投票

我设法通过包装EngineContextFactory类来实现这一点,所以我在Thymeleaf配置类中添加如下:

@Bean
public SpringTemplateEngine springTemplateEngine(SpringResourceTemplateResolver templateResolver,
                                                                 IDialect springSecurityDialect)
{
    SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver);
    templateEngine.setEngineContextFactory(engineContextFactory());
    templateEngine.addDialect(springSecurityDialect);
    return templateEngine;
}

private IEngineContextFactory engineContextFactory()
    {
        return new EngineContextFactoryWrapper()
            // packages to register
            .registerImport("java.util")
            .registerImport("java.math")
            .registerImport("com.mainsys.fhome.gui.util");
    }

public static class EngineContextFactoryWrapper
    implements IEngineContextFactory
{
    private final IEngineContextFactory delegate;
    private final List<String> typeLocatorPrefixes;

    public EngineContextFactoryWrapper()
    {
        super();
        delegate = new StandardEngineContextFactory();
        typeLocatorPrefixes = new ArrayList<String>();
    }

    @Override
    public IEngineContext createEngineContext(IEngineConfiguration configuration,
                                                            TemplateData templateData,
                                                            Map<String, Object> templateResolutionAttributes,
                                                            IContext context)
    {
        IEngineContext engineCtx = delegate.createEngineContext(configuration, templateData, templateResolutionAttributes, context);
        EvaluationContext evaluationContext;
        if (engineCtx.containsVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME))
        {
            evaluationContext = (EvaluationContext) engineCtx.getVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME);
        }
        else
        {
            evaluationContext = new ThymeleafEvaluationContextWrapper(new StandardEvaluationContext());
        }
        for (String prefix : typeLocatorPrefixes)
        {
            ((StandardTypeLocator) evaluationContext.getTypeLocator()).registerImport(prefix);
        }
        return engineCtx;
    }

    public EngineContextFactoryWrapper registerImport(String prefix)
    {
        typeLocatorPrefixes.add(prefix);
        return this;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.