【问题标题】:Spring - Thymeleaf - 404 Error弹簧 - Thymeleaf - 404 错误
【发布时间】:2014-06-27 15:40:53
【问题描述】:

我过去曾与 Spring 合作过一个大型项目,但我从未从头开始创建 Spring MVC Web 应用程序。

这就是我目前正在做的练习,因为我有一个项目需要它。

我成功地制作了一个使用 .JSP 页面(使用注释,没有 XML)的简单 Spring MVC Web 应用程序。 不过我想使用 Thymeleaf 并开始了我的转换过程。

好吧,现在我遇到了 404 错误,而且我的 HomeController 类似乎没有被击中。

我在控制台输出中没有收到任何错误。

我有 Google 搜索、通读教程和代码示例。第二双眼睛会很好。谢谢! :)

注意:从 .JSP 到 Thymeleaf 所做的唯一更改是添加了 ThymeleafConfig 类。我不明白它是如何从工作变成不工作的。

这是我的代码:

WebInit.java

public class WebInit implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // Creates the root application context
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(ServletConfig.class);
        appContext.setDisplayName("REPLACE ME");
        appContext.setConfigLocation("com.demo.config");

        // Creates the Spring Container shared by all Servlets and Filters
        servletContext.addListener(new ContextLoaderListener(appContext));

        // Further configures the servlet context
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
                "dispatcher", new DispatcherServlet(appContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.setAsyncSupported(true);
        dispatcher.addMapping("/");
    }
}

ServetConfig.java

@Configuration
@Import(WebConfig.class)
@ImportResource({/*"classpath:META-INF/spring/persistence-context.xml"*/})
public class ServletConfig {

}

WebConfig.java

@Configuration
@ComponentScan("com.illinois.dnr")
@EnableAspectJAutoProxy
@EnableWebMvc
@Import({ThymeleafConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter {
    // Maps resources path to webapp/resources
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations(
                "/resources/");
    }

    // Provides internationalization of messages
    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setBasename("messages");
        return source;
    }
}

Thymeleaf.java

@Configuration
public class ThymeleafConfig {
    @Bean 
    public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setOrder(1);
        return resolver;
    }

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

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

HomeController.java

@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/dnr", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,
                DateFormat.LONG, locale);
        String formattedDate = dateFormat.format(date);
        model.addAttribute("serverTime", formattedDate);
        return "home";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginPage(Locale locale, Model model) {
        logger.info("Login");
        return "login";
    }

    @RequestMapping(value = "/home", method = RequestMethod.POST)
    public String login(@Validated User user, Model model) {
        model.addAttribute("userName", user.getUserName());
        logger.info("User");
        return "user";
    }

    @RequestMapping(value = { "/", "/welcome**" }, method = RequestMethod.GET)
    public ModelAndView welcomePage() {

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security Hello World");
        model.addObject("message", "This is welcome page!");
        model.setViewName("hello");
        logger.info("Hello");
        return model;
    }

    @RequestMapping(value = "/admin**", method = RequestMethod.GET)
    public ModelAndView adminPage() {

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security Hello World");
        model.addObject("message", "This is protected page - Admin Page!");
        model.setViewName("admin");
        logger.info("admin");
        return model;
    }

    @RequestMapping(value = "/dba**", method = RequestMethod.GET)
    public ModelAndView dbaPage() {

        ModelAndView model = new ModelAndView();
        model.addObject("title", "Spring Security Hello World");
        model.addObject("message", "This is protected page - Database Page!");
        model.setViewName("admin");
        logger.info("dba");
        return model;
    }
}

【问题讨论】:

  • 使用 STS 和 tomcat7
  • 有堆栈跟踪可言吗?另外,你能不能把System.out.println()'s in your ThymeleafConfig`方法来确保它们正在运行。你所有的 Thymeleaf 模板都在 WEB-INF/views 中吗?
  • 记住你应该去localhost:8080/appName/dnr 并且页面是WEB-INF/views/dnr.html
  • CodeChimp:感谢在我的方法中运行 System.out 的想法!我自己应该想到的。

标签: java spring spring-mvc http-status-code-404 thymeleaf


【解决方案1】:

我不确定它是否有帮助,但您可以通过 extendsAbstractAnnotationConfigDispatcherServletInitializer 而不是实现 WebApplicationInitializer 来简化 WebInit。否则 Thymeleaf 配置对我来说似乎没问题(假设它被调用)。我在这里给出了配置的工作框架,以便您可以进行试验。

WebApplicationInitializer

public class WebInitializer extends
    AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

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

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

}

网络配置

@Configuration
@EnableWebMvc
@ComponentScan("com.kreuzman")
public class WebConfig {

    @Bean
    public ITemplateResolver templateResolver() {
        TemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/templates/");
    resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setCacheTTLMs(0l);

        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());

        return engine;
    }

    @Bean
    public ViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");

        return viewResolver;
    }

}

【讨论】:

  • 谢谢!希望这可以帮助其他想要一个纯粹基于注释的 Spring Web 应用程序的人。我找到了几个教程和帮助指南,但它们在如何设置方面都有自己的“风格”。我终于找到了 Spring MVC-Security-WebFlow、Hibernate 和 Thymeleaf 项目的工作示例。配置文件的设置类似于您的骨架。果断走这条路。干净多了。谢谢
【解决方案2】:

您要点击哪个页面? /WEB-INF/views/中是否存在该html页面?

它是一个 JSP 页面吗?您需要排除所有不会被 ThymeleafViewResolver 解析的页面。我还注意到您没有将 ThymeleafViewResolver 设置为顺序的第一个。

像这样

@Bean 
public ThymeleafViewResolver thymeleafViewResolver() 
{
    String[] excludedViews = new String[]{
        "login", "logout"};

    ThymeleafViewResolver resolver = new ThymeleafViewResolver();
    resolver.setTemplateEngine(templateEngine());
    /*
     * This is how we get around Thymeleaf view resolvers throwing an error instead of returning
     * of null and allowing the next view resolver in the {@see
     * DispatcherServlet#resolveViewName(String, Map<String, Object>, Locale,
     * HttpServletRequest)} to resolve the view.
     */
    resolver.setExcludedViewNames(excludedViews);
    resolver.setOrder(1);
    return resolver;
}

【讨论】:

  • 我尝试设置 setOrder(1),但没有成功。我最终删除了该项目并重新从头开始。这次唯一的不同是我使用了这个依赖:javax 6.0
  • 如果我想同时支持 .JSP 和 .html 页面,您确实帮我排除了 .JSP 页面。所以谢谢你
猜你喜欢
  • 2013-12-25
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
  • 2013-12-06
相关资源
最近更新 更多