복붙노트

[SPRING] @Configuration 및 @Controller 클래스를 주석 처리했습니다. 리팩토링에 도움이 필요하다.

SPRING

@Configuration 및 @Controller 클래스를 주석 처리했습니다. 리팩토링에 도움이 필요하다.

아래는 @Configuration과 @Controller를 모두 사용해야하는 클래스입니다. Thymeleaf 인스턴스가 하나 뿐이므로 전체 애플리케이션에서 예외가 발생합니다. 다른 클래스에는 @RequestScope 주석이 달려 있으므로 singleton scoped bean을 사용할 수 없습니다. 그래서 나는 결과를 얻기 위해 컨피규레이션과 컨트롤러를 섞어 놓았지 만 나쁜 습관이라고 생각한다. 코드를 리팩토링하고 나쁜 습관을 없애는 데 도움이 될만한 것에 감사드립니다.

최신 정보

나는 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/");
    }
}

최신 정보

또한 다른 클래스에 요청 범위가 있으므로 아래 답변을 받아 들일 수없는 이유를 언급했습니다.

최신 정보

아래 @RequestScopelike 클래스가 있습니다.

@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";
    }
}

해결법

  1. ==============================

    1.Spring Boot를 사용하고 있다고 가정 할 때, 태그를 가지고 있기 때문에, Thymeleaf를 사용하기 위해 어떤 설정도 필요하지 않습니다.

    Spring Boot를 사용하고 있다고 가정 할 때, 태그를 가지고 있기 때문에, Thymeleaf를 사용하기 위해 어떤 설정도 필요하지 않습니다.

    이 의존성을 갖춤으로써 다음을 수행 할 수 있습니다.

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

    그리고 그것은 효과가있다.

    그건 그렇고, 같은 클래스에 @Configuration과 @Controller를 갖는 것이 결코 필요하지 않은 것입니다.

  2. ==============================

    2.주석 (Spring 5)의 소스 코드를 보았다면 :

    주석 (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.
         * <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 어노테이션을 포함한다). 따라서이 사실을 봄으로써 둘 다 사용하는 것은 의미가 없습니다. 더 중요한 것은, 스프링이 사용법을 설명해야하는 이러한 주석의 의미를 나타내는 태그를 제공하려고한다는 것입니다.

    구성은 시작 단계에서 제대로 작동하기 위해 응용 프로그램에 필요한 부분을 연결하는 데 사용됩니다.

    Controller는 외부 세계에 대한 인터페이스 역할을하는 클래스를 정의하는 데 사용됩니다. 즉, 다른 액터가 응용 프로그램을 어떻게 사용할 수 있습니까?

    보시다시피, 그것들을 함께 사용하는 것은 거의 의미가 없습니다.

  3. ==============================

    3.스프링 부트 문서의 일반적인 레이아웃을 살펴보십시오.

    스프링 부트 문서의 일반적인 레이아웃을 살펴보십시오.

    또한이 기사 SOLID 프로그래밍 원리

    Spring Boot Thymeleaf (@Bean 설정이 필요 없습니다)

    두 단어로 분리해야합니다.  1. MyThymeleafConfig 구성  2. viewTemplates () 및 다른 끝점이있는 TemplateController

  4. ==============================

    4.리팩토링하기 위해 @Bean 메서드를 별도의 @Configuration 클래스로 분리하는 것이 쉽고 간단합니다.

    리팩토링하기 위해 @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 클래스는 빈 메소드를 호출 한 횟수와 상관없이 동일한 빈 인스턴스를 리턴한다.

    이제 컨트롤러에서 :

    @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);
        }
    }
    

    그러나 솔직히, 나는 왜 Spring-thymeleaf가 주어진 변수로 템플릿을 자동으로 처리하기 때문에 TemplateEngine / SpringTemplateEngine과 수동으로 상호 작용해야하는지 모른다. (@sedooe 예와 같이)

  5. ==============================

    5.구성 클래스 내에 요청 매핑을 두지 마십시오. 관심사 분리 원칙을 위반합니다. 아래처럼 접근 할 수 있습니다.

    구성 클래스 내에 요청 매핑을 두지 마십시오. 관심사 분리 원칙을 위반합니다. 아래처럼 접근 할 수 있습니다.

    모든 응용 프로그램 광역 bean은 클래스 경로의 루트에있는 Application 클래스에 설정됩니다. Application 클래스는 응용 프로그램 범위를 가지고 있기 때문에 thymeleaf 및 정적 자원 구성을 보유하기에 가장 적합한 응용 프로그램 클래스입니다.

    @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;
       }
    }
    

    staticpath를 classpath에 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는 당신이 당신이 좋아하는 방법으로 그것을 할 수 있지만, 당신은 더 나은 일반적인 접근 방식에 충실해야합니다.

  6. ==============================

    6.이 두 주석은 다른 것들을위한 것이므로 동일한 클래스에서 사용하지 않는 것이 좋습니다. 그것은 Separation of Concerns 교장에 반대하기 때문입니다.

    이 두 주석은 다른 것들을위한 것이므로 동일한 클래스에서 사용하지 않는 것이 좋습니다. 그것은 Separation of Concerns 교장에 반대하기 때문입니다.

  7. from https://stackoverflow.com/questions/51636312/annotated-a-class-with-configuration-and-controller-need-help-in-refactoring by cc-by-sa and MIT license