下面是我的类,在该类中,我必须同时使用@Configuration
和@Controller
,因为在整个应用程序中应该只有Thymeleaf
的一个实例,否则我会得到例外。我的其他类都用@RequestScope
注释,因此我不能使用单例范围的Bean。所以我混合使用Configuration和Controller来获得结果,但是我觉得这是一个不好的做法。我希望能对重构代码和消除不良做法提供任何帮助。
更新
我正在使用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/");
}
}
更新
我还提到了我不能接受以下提到的答案的原因,因为我的其他类都有请求范围。
更新
我还有其他@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";
}
}
答案 0 :(得分:7)
假设您使用的是Spring Boot,因为它已包含在标签中,所以不需要任何配置即可使用Thymeleaf。
只需拥有this dependency,您就可以:
@GetMapping("/view-template")
public String viewTemplates(Model model) {
model.addAttribute("mydata", "this is it")
return "view-to-process";
}
它应该可以工作。
是的,是的,@Configuration
和@Controller
在同一个类中是您永远都不需要的。
答案 1 :(得分:6)
如果您看到注释的源代码(春季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.
* <p>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
用于定义一个类,该类充当与外界的接口,即:其他参与者如何使用您的应用程序。
如您所见,将这两个一起使用几乎没有什么意义。
答案 2 :(得分:5)
看看Spring Boot文档typical layout
还有本文SOLID Programming Principles
并查看Spring Boot指南Spring Boot Thymeleaf(不需要@Bean配置)
您应该用两个词分开
1. MyThymeleafConfig
配置
2. TemplateController
与viewTemplates()
和另一个端点
答案 3 :(得分:5)
要重构它们,将@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示例)
答案 4 :(得分:2)
不要将请求映射放入配置类中,这违反了关注点分离的原则。您可以采用以下方法。
所有应用程序级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;
}
}
如果您将静态资源放在类路径中名为 static 或 public 的文件夹中,则springboot会将其标识为静态资源的位置。然后,您无需重写addResourceHandlers
方法。如果确实要执行此操作,则可以在扩展WebMvcConfigurerAdapter
的Application类中执行此操作。您不需要单独的类即可仅配置静态资源路径。
不要将请求映射放在配置类中,而是将它们放在单独的控制器类中,例如:
@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允许您以自己喜欢的方式进行操作,但最好还是采用一般方法。
答案 5 :(得分:0)
这两个注释用于不同的事物,因此最好不要在同一类上使用它们。因为它违反了Separation of Concerns
主体。