在Spring Boot应用程序中使用JSP和Thymeleaf视图 [英] Use JSP and Thymeleaf views in Spring Boot app

查看:95
本文介绍了在Spring Boot应用程序中使用JSP和Thymeleaf视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网站上和一般在网络上都有几个类似的问题,但是我无法像我尝试过的那样使它们在我的示例中发挥作用.

There are several similar questions on the site and on the web in general but I haven't been able to make them work in my example as much as I've tried.

我第一次使用Spring Boot,但是我一直试图通过 InternalResourceViewResolver 包含JSP视图.我已经有了Thymeleaf的视图.

I'm working with Spring Boot for the first time and I'm stuck trying to include JSP views via an InternalResourceViewResolver. I already got Thymeleaf views to work.

Application.java

@SpringBootApplication
@ComponentScan("controller")
@EnableWebSecurity
@Configuration
public class Application extends WebSecurityConfigurerAdapter {
    public static void main(String args[]) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ITemplateResolver templateResolver() {
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode(TemplateMode.HTML);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setCacheable(false);
        resolver.setOrder(1);
        return resolver;
    }

    //intended for the .jsp view
    @Bean
    public InternalResourceViewResolver jspResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("classpath:/templates/jsp/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        resolver.setOrder(2);
        return resolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.addTemplateResolver(new UrlTemplateResolver());
        templateEngine.addTemplateResolver(templateResolver());

        //IKD if/how I should somehow add jspResolver() here

        templateEngine.addDialect(new SpringSecurityDialect());
        templateEngine.addDialect(new LayoutDialect(new GroupingStrategy()));
        templateEngine.addDialect(new Java8TimeDialect());
        return templateEngine;
    }

    @Bean
    @Description("Thymeleaf View Resolver")
    public ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setOrder(0);
        return viewResolver;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/users/**").hasRole("USER")//USER role can access /users/**
                .antMatchers("/admin/**").hasRole("ADMIN")//ADMIN role can access /admin/**
                .antMatchers("/quests/**").permitAll()// anyone can access /quests/**
                .anyRequest().authenticated()//any other request just need authentication
                .and()
                .formLogin();//enable form login
    }

    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.inMemoryAuthentication()
                .passwordEncoder(passwordEncoder())
                .withUser("tim").password(passwordEncoder().encode("123")).roles("ADMIN")
                .and()
                .withUser("joe").password(passwordEncoder().encode("234")).roles("USER");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

MainController.java

@Controller
public class MainController {
@GetMapping("/")
ModelAndView index(Principal principal) {
    ModelAndView mv = new ModelAndView("home");
    if (principal != null) {
        mv.addObject("message", principal.getName());
    } else {
        mv.addObject("message", "anon.");
    }

    return mv;
}

@GetMapping("/**")
String request(HttpServletRequest request, Model model) {
    Authentication auth = SecurityContextHolder.getContext()
            .getAuthentication();
    ModelAndView mv = new ModelAndView("home");
    model.addAttribute("uri", request.getRequestURI())
            .addAttribute("user", auth.getName())
            .addAttribute("roles", auth.getAuthorities());

    return "html"; //<-- whenever I change this to return "jsp/jsp"; it breaks
}

html.html (胸腺)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
    <body>
        <p>
            URI: <h3 th:text="${uri}"></h3>
        User: <h3 th:text="${user}"></h3>
        Roles: <h3 th:text="${roles}"></h3>
        <a href="/admin/">/admin/</a><br/>
        <a href="/users/">/users/</a><br/>
        <a href="/others/">/others/</a><br/>
        <a href="/quests/">/quests/</a><br/><br/>
    </p>
    <form th:action="@{/logout}" method="post">
        <input type="hidden"
               name="${_csrf.parameterName}"
               value="${_csrf.token}"/>
        <input type="submit" value="Logout">
    </form>
</body>
</html>

当我尝试很好地处理JSP文件时,浏览器仅输出

When I try to make this work with a JSP file well, the browswer only outputs

HTTP状态500?内部服务器错误

以及在NetBeans Output 窗口中,gradle的任务运行正在运行,日志显示在最顶端(整个日志相当广泛):

and in NetBeans Output window, where gradle's task run is, well, running, the log shows this at the very top (the whole log is quite extensive):

2018-10-07 18:09:40.070错误6024 --- [nio-8080-exec-4] org.thymeleaf.TemplateEngine:[THYMELEAF] [http-nio-8080-exec-4]异常处理模板"jsp/jsp":模板解析期间发生错误(模板:类路径资源[templates/jsp/jsp.html]")

我要包含的JSP视图

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
    <body>
        <p>URI: ${uri} <br/>
            User :  ${user} <br/>
            roles:  ${roles} <br/><br/>
            <a href="/admin/">/admin/</a><br/>
            <a href="/users/">/users/</a><br/>
            <a href="/others/">/others/</a><br/>
            <a href="/quests/">/quests/</a><br/><br/>
        </p>
        <form action="/logout" method="post">
            <input type="hidden"
                   name="${_csrf.parameterName}"
                   value="${_csrf.token}"/>
            <input type="submit" value="Logout">
        </form>
    </body>
</html>

最后,我的项目树:

我的假设是,应用程序不知道文件夹 templates/jsp 中的文件 jsp.jsp ,这就是为什么我要针对此问题来查看解析器的原因,但是正如我说的那样,我很容易就错了.

My assumption is that the app does not know about the file jsp.jsp inside folder templates/jsp, which is why I'm aiming the question to view resolvers, but as I said, I could easily be wrong about it.

这只是我试图实现并继续发展的一个示例,请随时提出一些建议,而不是x.

This is just an example I'm trying to materialize and build on, so feel free to shred it with suggestions, thanx.

推荐答案

仅仅为jsp添加一个视图解析器是行不通的,我们还需要为jsp添加一个模板解析器,并将其连接到spring模板引擎.下面的代码在Spring Boot 2中有效.

Just adding one more view resolver for jsp won't do, we also need to add one more template resolver for jsp and connect it to spring template engine. The code below works in Spring Boot 2.

package org.jwebshop.webshop.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;

import javax.annotation.Resource;

@Configuration
@EnableWebMvc
public class ViewConfiguration implements WebMvcConfigurer {

    @Resource
    protected ApplicationContext applicationContext;

    @Resource
    protected SpringTemplateEngine springTemplateEngine;

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(){
        final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setViewNames(new String[] {"thyme/*"});
        viewResolver.setExcludedViewNames(new String[] {"jsp/*"});
        viewResolver.setTemplateEngine(springTemplateEngine);
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }

    @Bean
    public InternalResourceViewResolver jspViewResolver(){
        final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewNames("jsp/*");
        return viewResolver;
    }

    @Bean
    public SpringResourceTemplateResolver thymeleafTemplateResolver(){
        final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(false);
        templateResolver.setOrder(0);
        return templateResolver;
    }

    @Bean
    public SpringResourceTemplateResolver jspTemplateResolver(){
        final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".jsp");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(false);
        templateResolver.setOrder(1);
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
        registry.addResourceHandler("/images/**").addResourceLocations("/images/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    }
}

package org.jwebshop.webshop.controller.web.thymeleaf;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class RootController {

    @Secured("ROLE_CUSTOMER")
    @GetMapping({"/", "/index"})
    public String root() {
        return "thyme/index";
    }
}

package org.jwebshop.webshop.controller.web.jsp;

import org.jwebshop.webshop.dto.converter.impl.UserDataConverter;
import org.jwebshop.webshop.dto.data.UserData;
import org.jwebshop.webshop.entity.User;
import org.jwebshop.webshop.service.UserService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import javax.annotation.Resource;

@Controller
public class LuckyController {

    @Resource
    protected UserService userService;

    @Resource
    protected UserDataConverter userDataConverter;

    @Secured("ROLE_CUSTOMER")
    @GetMapping("/lucky")
    public String hello(final Model model, final Authentication auth) {
        final User user = userService.findByEmail(auth.getName());
        final UserData userData = userDataConverter.convertFrom(user);
        model.addAttribute("userData", userData);
        return "jsp/lucky";
    }
}

Folder structure: 
 webapp
   |
 WEB-INF
   |
  views
  |   |
jsp thyme

https://imgur.com/qOTgYZW

这篇关于在Spring Boot应用程序中使用JSP和Thymeleaf视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆