Проблемы с Spring Boot и Thymeleaf

Вот мои классы конфигурации:

В методе templateResolver () без параметра ServletContext я получаю ошибку компиляции, поэтому добавьте ее в качестве параметра и передайте в ServletContextTemplateResolver (servletContext);

@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"com.packtpub.springsecurity"})
public class ThymeleafConfig {

    @Bean
    public ServletContextTemplateResolver templateResolver(ServletContext servletContext) {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
        resolver.setPrefix("/WEB-INF/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCacheable(false);
        resolver.setOrder(1);
        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine(final ServletContextTemplateResolver templateResolver) {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver);
        return engine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(final SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine);
        return resolver;
    }

}

Когда я запускаю свое приложение, я получаю следующую ошибку :::

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method templateResolver in com.packtpub.springsecurity.web.configuration.ThymeleafConfig required a bean of type 'javax.servlet.ServletContext' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'javax.servlet.ServletContext' in your configuration.

Что я делаю неправильно? Благодарность

Другие файлы конфигурации:

<?xml version = "1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>chapter2</groupId>
    <artifactId>chapter2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>chapter2</name>
    <description>chapter 2 test</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>



        <!-- Thymeleaf -->  
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>





        <!-- Spring dependencies START-->
        <dependency>
           <groupId>org.springframework.security</groupId>
           <artifactId>spring-security-web</artifactId>
           </dependency>
        <dependency>
           <groupId>org.springframework.security</groupId>
           <artifactId>spring-security-config</artifactId>
           </dependency>
        <dependency>
           <groupId>org.springframework.security</groupId>
           <artifactId>spring-security-crypto</artifactId>
           </dependency>
        <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-webmvc</artifactId>
           </dependency>
        <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           </dependency>
        <!-- Servlet and JSP related dependencies -->
        <dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>javax.servlet-api</artifactId>
           <scope>provided</scope>
        </dependency>
        <dependency>
           <groupId>javax.servlet.jsp</groupId>
           <artifactId>javax.servlet.jsp-api</artifactId>
           <version>2.3.1</version>
           <scope>provided</scope>
        </dependency>
        <dependency>
           <groupId>javax.servlet.jsp.jstl</groupId>
           <artifactId>javax.servlet.jsp.jstl-api</artifactId>
           <version>1.2.1</version>
        </dependency>
        <dependency>
           <groupId>taglibs</groupId>
           <artifactId>standard</artifactId>
           <version>1.1.2</version>
        </dependency>
        <!-- For datasource configuration -->
        <dependency>
           <groupId>org.apache.commons</groupId>
           <artifactId>commons-dbcp2</artifactId>
           </dependency>
        <!-- We will be using MySQL as our database server -->
        <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>6.0.6</version>
        </dependency>   
        <!-- Spring dependencies END -->    



        <dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20170516</version>
</dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>



@Configuration
//@Import({SecurityConfig.class, DataSourceConfig.class})
@ComponentScan(basePackages =
        {
                "com.packtpub.springsecurity.dataaccess",
                "com.packtpub.springsecurity.domain",
                "com.packtpub.springsecurity.service"
        }
)
@PropertySource(value = {"classpath:application.properties"})
public class JavaConfig {

    /**
     * Note: If you want to use @PropertySource, you must create a static
     * PropertySourcesPlaceholderConfigurer with the @Bean as seen here.
     * @return PropertySourcesPlaceholderConfigurer
     * @throws java.io.IOException
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException {
        PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
        propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
        propertySourcesPlaceholderConfigurer.setProperties(yamlPropertiesFactoryBean().getObject());
        return propertySourcesPlaceholderConfigurer;
    }

    @Bean
    public static YamlPropertiesFactoryBean yamlPropertiesFactoryBean() {
        YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("application.yml"));
        return yaml;
    }
} // The end...



@Order(1)
public class SecurityWebAppInitializer
        extends AbstractSecurityWebApplicationInitializer {

    /**
     * Don't initialize the filter directly, the Spring WebApplicationInitializer
     * parent will take care of the initialization.
     */
    public SecurityWebAppInitializer() {
        super();
    }

} // The end...




public class WebAppInitializer
        extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { JavaConfig.class, SecurityConfig.class, DataSourceConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/*" };
    }

    @Override
    public void onStartup(final ServletContext servletContext)
            throws ServletException {

        // Register DispatcherServlet
        super.onStartup(servletContext);

        // Register H2 Admin console:
        ServletRegistration.Dynamic h2WebServlet = servletContext.addServlet("h2WebServlet",
                "org.h2.server.web.WebServlet");
        h2WebServlet.addMapping("/admin/h2/*");
        h2WebServlet.setInitParameter("webAllowOthers", "true");

    }

} // The End...




@Configuration
@EnableWebMvc
@Import({ThymeleafConfig.class})
@ComponentScan(basePackages = {
        "com.packtpub.springsecurity.web.controllers",
        "com.packtpub.springsecurity.web.model"
})
public class WebMvcConfig extends WebMvcConfigurerAdapter
{

    @Autowired
    private ThymeleafViewResolver thymeleafViewResolver;

    /**
     * We mention this in the book, but this helps to ensure that the intercept-url patterns prevent access to our
     * controllers. For example, once security has been applied for administrators try commenting out the modifications
     * to the super class and requesting <a
     * href = "http://localhost:800/calendar/events/.html">http://localhost:800/calendar/events/.html</a>. You will
     * observe that security is bypassed since it did not match the pattern we provided. In later chapters, we discuss
     * how to secure the service tier which helps mitigate bypassing of the URL based security too.
     */
    // FIXME: FInd out what this is and why it is here.
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping result = new RequestMappingHandlerMapping();
        result.setUseSuffixPatternMatch(false);
        result.setUseTrailingSlashMatch(false);
        return result;
    }

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/resources/")
                .setCachePeriod(31_556_926)
        ;
    }

    @Override
    public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
        configurer
                .ignoreAcceptHeader(false)
                .favorPathExtension(true) // .html / .json / .ms
                .defaultContentType(MediaType.TEXT_HTML) // text/html
                .mediaTypes(
                        new HashMap<String, MediaType>(){
                            {
                                put("html", MediaType.TEXT_HTML);
                                put("xml", MediaType.APPLICATION_XML);
                                put("json", MediaType.APPLICATION_JSON);
                            }
                        })
        ;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }

    /*@Bean
    public ContentNegotiatingViewResolver contentNegotiatingViewResolver() {

        ContentNegotiatingViewResolver result = new ContentNegotiatingViewResolver();
        Map<String, String> mediaTypes = new HashMap<>();
        mediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE);
//        result.setMediaTypes(mediaTypes);

        result.setDefaultViews(Collections.singletonList(jacksonView()));

        return result;
    }*/

    @Bean
    public MappingJackson2JsonView jacksonView() {
        MappingJackson2JsonView jacksonView = new MappingJackson2JsonView();
        jacksonView.setExtractValueFromSingleKeyModel(true);

        Set<String> modelKeys = new HashSet<String>();
        modelKeys.add("events");
        modelKeys.add("event");
        jacksonView.setModelKeys(modelKeys);

        return jacksonView;
    }

    @Override
    public void configureViewResolvers(final ViewResolverRegistry registry) {
        registry.viewResolver(thymeleafViewResolver);
    }


    // i18N support
    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
        resource.setBasenames("/WEB-INF/locales/messages");
        resource.setDefaultEncoding("UTF-8");
        resource.setFallbackToSystemLocale(Boolean.TRUE);
        return resource;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
        configurer.enable();
    }


}

ОБНОВЛЕНО

Я удалил следующие зависимости из POM в соответствии с @Adina в комментарии ниже, но все еще получаю ошибки

<!-- dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>javax.servlet-api</artifactId>
           <scope>provided</scope>
        </dependency>
        <dependency>
           <groupId>javax.servlet.jsp</groupId>
           <artifactId>javax.servlet.jsp-api</artifactId>
           <version>2.3.1</version>
           <scope>provided</scope>
        </dependency>
        <dependency>
           <groupId>javax.servlet.jsp.jstl</groupId>
           <artifactId>javax.servlet.jsp.jstl-api</artifactId>
           <version>1.2.1</version>
        </dependency>
        <dependency>
           <groupId>taglibs</groupId>
           <artifactId>standard</artifactId>
           <version>1.1.2</version>
        </dependency-->

Что еще я могу сделать снова

Ваш код выглядит нормально, не могли бы вы добавить зависимости приложения Spring?

Adina Rolea 20.10.2018 10:14

@Adina Я добавил дополнительные файлы конфигурации

Eddy Freeman 20.10.2018 10:22

Почему у вас есть эти зависимости, связанные с <! - сервлетами и JSP ->), и планируете ли вы развернуть свое приложение как WAR или JAR?

Simon Martinelli 20.10.2018 10:24

Развертывание @SimonMartinelli на данный момент не актуально. Я просто хочу, чтобы код работал.

Eddy Freeman 20.10.2018 10:29

@EddyFreeman, хотите ли вы использовать и jsp, и тимелеаф? Ваша инициализация не удалась, потому что он не знает, какой из них инициализировать. Это старые дебаты о stackoverflow, если вы можете использовать их оба. Если вы удалите все зависимости, связанные с jsp, и оставите только тимелеаф, ваша ошибка больше не возникнет.

Adina Rolea 20.10.2018 10:54

@Adina Я обновил свой пост. Я удалил некоторые зависимости из POM, но по-прежнему получаю сообщение об ошибке

Eddy Freeman 20.10.2018 10:59

Spring Boot автоматически настроит Thymeleaf и Spring MVC за вас. Вам почти наверняка не нужен @EnableWebMvc, и, вероятно, вам не понадобится ни один из трех бобов, связанных с Thymeleaf. В чем причина того, что нужно настраивать вещи вручную, а не позволять Spring Boot обо всем позаботиться? Кроме того, здесь имеет значение упаковка, которую вы будете использовать. WEB-INF не существует, если вы не создаете файл войны.

Andy Wilkinson 20.10.2018 11:38

Вы смотрели краткое руководство. Вам не нужен ThymeleafConfig

Simon Martinelli 20.10.2018 12:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
8
968
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После некоторой отладки вашего кода настоящая проблема заключается в том, что вы автоматически подключаете ThymeleafViewResolver в конфигурации, отвечающей за настройку контекста сервлета.

 public class WebMvcConfig implements WebMvcConfigurer{

     @Autowired
     private ThymeleafViewResolver thymeleafViewResolver;

Основная проблема заключается в том, что перед инициализацией вашего ServletContext приложение попытается инициализировать ServletContextTemplateResolver (autowired установит инициализацию порядка компонентов), и, как вы заметили, это зависит от ServletContext.

Решение:

  • удалить класс ThymeleafConfig
  • не подключайте автоматически ThymeleafViewResolver в WebMvcConfig
  • и не переопределяйте метод configureViewResolvers.

Не волнуйтесь, Thymeleaf по умолчанию будет установлен как viewResolver.

Большая часть предоставленной вами конфигурации уже «позаботилась» с помощью spring -boot-starter-thymeleaf. Если вы хотите просто изменить преобразователь каталога просмотра по умолчанию, вы можете просто добавить application.properties

spring.mvc.view.prefix=/WEB-INF/templates/
spring.mvc.view.suffix=.html

P.S: Будьте особенно осторожны, когда вы отменяете определение по умолчанию из Spring Starters, поскольку вы можете видеть, что эти типы ошибок нелегко найти.

Другие вопросы по теме