使用@Configuration和@Controller注释一个类。 需要帮助重构

下面是我必须同时使用@Configuration@Controller类,因为在整个应用程序中应该只有一个Thymeleaf实例,否则我会得到例外。 我的其他类用@RequestScope注释,所以我不能使用单例作用域bean。 所以我有一个配置和控制器的混合来获得结果,但我觉得这是一个不好的做法。 我将不胜感激任何帮助重构代码并删除不良做法。

UPDATE

我使用的是spring-boot 1.5.14 。 我使用以下方法处理模板并将处理后的模板保持为字符串。

 @Controller @Configuration @EnableWebMvc @ApplicationScope public class MyThymeleafConfig { @GetMapping("/view-template") @ResponseBody public void viewTemplates() { Context context = new Context(); context.setVariable("mydata", "this is it"); String html = templateEngine().process("templates/view-to-process.html", context); System.out.println(html); } /* configuration for thymeleaf and template processing */ @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(thymeleafTemplateResolver()); return templateEngine; } @Bean public SpringResourceTemplateResolver thymeleafTemplateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setPrefix("classpath:"); templateResolver.setSuffix(".html"); templateResolver.setCacheable(false); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } @Bean public ThymeleafViewResolver thymeleafViewResolver() { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } } 

要为静态资源提供以下配置:

 @Configuration @EnableWebMvc public class StaticResourceConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/**") .addResourceLocations("/static/", "classpath:static/"); } } 

UPDATE

我还提到了为什么我不能接受下面提到的答案的原因,因为我的其他类有请求范围。

UPDATE

我有@RequestScope其他类,如下所示:

 @RequestScope @Controller public class SecondController { @GetMapping("/viewPage") public String viewPage(Model model) { model.addAttribute("mydata", "sjfbsdf"); model.addAttribute("somedata", "sjdfksfjhshgdfbskdfj"); return "templates/view-to-process.html"; } } 

假设您正在使用Spring Boot,因为您在标签中使用它,您不需要任何配置来使用Thymeleaf。

只需拥有此依赖关系 ,您就可以:

 @GetMapping("/view-template") public String viewTemplates(Model model) { model.addAttribute("mydata", "this is it") return "view-to-process"; } 

它应该工作。

顺便说一下,是的,在同一个类中使用@Configuration@Controller是你永远不需要的东西。

如果您看到注释的源代码(Spring 5),您有:

调节器

 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } 

组态

 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { /** * Explicitly specify the name of the Spring bean definition associated * with this Configuration class. If left unspecified (the common case), * a bean name will be automatically generated. * 

The custom name applies only if the Configuration class is picked up via * component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}. * If the Configuration class is registered as a traditional XML bean definition, * the name/id of the bean element will take precedence. * @return the suggested component name, if any (or empty String otherwise) * @see org.springframework.beans.factory.support.DefaultBeanNameGenerator */ @AliasFor(annotation = Component.class) String value() default ""; }

你注意到它们是相同的(它们都包含更通用的@Component注释)。 因此,通过看到这个事实来使用它们是没有意义的。 另一件更重要的事情是,spring试图给出一种标签意义,这些标注应该描述使用。

Configuration用于连接应用程序的必要部分,以便在启动阶段正常运行。

Controller用于定义一个作为外部世界接口的类,即:其他参与者如何使用您的应用程序。

正如您所看到的,将这两者结合使用毫无意义。

看一下Spring Boot文档的典型布局

另外这篇文章SOLID编程原理

看看Spring Boot指南Spring Boot Thymeleaf (你不需要你的@Bean配置)

用两个词你应该分开
1. MyThymeleafConfig配置
2.带有viewTemplates()和另一个端点的TemplateController

要重构它们,将@Bean方法分离到单独的@Configuration类是简单而直接的:

 @Configuration // @Controller is redundant as we have @Configuration // @EnableWebMvc is also redundant since you already annotate it in other class // @ApplicationScope is also redundant since you do not need to create bean of MyThymeleafConfig anymore public class MyThymeleafConfig { /* configuration for thymeleaf and template processing */ @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(thymeleafTemplateResolver()); return templateEngine; } @Bean public SpringResourceTemplateResolver thymeleafTemplateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setPrefix("classpath:"); templateResolver.setSuffix(".html"); templateResolver.setCacheable(false); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } @Bean public ThymeleafViewResolver thymeleafViewResolver() { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; } } 

@Configuration类返回相同的bean实例,无论你调用bean方法多少次。

现在在您的控制器中:

 @Controller public class MyThymeleafConfig { @Autowired private SpringTemplateEngine templateEngine; @GetMapping("/view-template") @ResponseBody public void viewTemplates() { Context context = new Context(); context.setVariable("mydata", "this is it"); String html = templateEngine.process("templates/view-to-process.html", context); System.out.println(html); } } 

但说实话,我不知道为什么你必须手动与TemplateEngine / SpringTemplateEngine进行交互,因为Spring-thymeleaf会自动为你提供给定变量的模板。 (像@sedooe的例子)

不要将请求映射放在配置类中,它违反了关注点分离的原则。 你可以采取如下方法。

所有应用程序范围的bean都在Application类中设置,该类存在于类路径的根目录中。 Application类也是获得百万美元静态资源配置的最佳位置,因为Application类具有应用程序范围。

 @SpringBootApplication @EnableWebMvc public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public ViewResolver viewResolver() { ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); resolver.setCharacterEncoding("UTF-8"); resolver.setCache(false); return resolver; } @Bean public TemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setEnableSpringELCompiler(true); templateEngine.addDialect(new LayoutDialect()); templateEngine.addDialect(new Java8TimeDialect()); templateEngine.setTemplateResolver(templateResolver()); return templateEngine; } private ITemplateResolver templateResolver() { SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setApplicationContext(applicationContext); resolver.setPrefix("classpath:/templates/"); resolver.setTemplateMode(TemplateMode.HTML); return resolver; } } 

如果将静态资源放在类路径中名为staticpublic的文件夹中,则springboot会将其标识为静态资源的位置。 然后您不需要覆盖addResourceHandlers方法。 如果您真的想这样做,可以在扩展WebMvcConfigurerAdapter的Application类中WebMvcConfigurerAdapter 。 您不需要单独的类来仅配置静态资源路径。

不要将请求映射放在配置类中,将它们放在单独的控制器类中,如:

 @Controller public class MyController { @GetMapping("/view-template") @ResponseBody public void viewTemplates() { Context context = new Context(); context.setVariable("mydata", "this is it"); String html = templateEngine().process("templates/view-to-process.html", context); System.out.println(html); } } 

因此,springboot允许您按照自己喜欢的方式进行,但您最好坚持一般方法。

这两个注释适用于不同的东西,因此最好不要在同一个类上使用它们。 因为它反对Separation of Concerns原则。