SpringBoot 整合 JSP、Thymeleaf 、Freemarker 详细步骤

一、SpringBoot 整合 JSP

1、引入 jsp 依赖

SpringBoot 默认是不支持 JSP 的,若使用需要引入以下依赖

     <!-- 添加servlet依赖模块 -->
     <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
     </dependency>
     <!-- 添加jstl标签库依赖模块-->
     <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>jstl</artifactId>
     </dependency>
     <!-- 使用jsp引擎,springboot内置tomcat没有此依赖加上即可 -->
     <dependency>
         <groupId>org.apache.tomcat.embed</groupId>
         <artifactId>tomcat-embed-jasper</artifactId>
     </dependency>

2、添加 webapp 目录

SpringBoot 默认网站资源放置到 webapp 目录下,如果没有需要手动创建该目录,注意目录层级是在 java 下面

在这里插入图片描述

测试选中 webapp 右键是发现没有创建 JSP 的选项,如下图示:

在这里插入图片描述

此时可以按 command+; 进入以下这个界面,如下图示:

在这里插入图片描述

设置完之后,然后再点选 webapp 文件目录,右键就可以看到可以创建 JSP 文件,然后再 webapp 文件目录下在创建一个 WEB-INF 目录(安全目录),如下图示:

在这里插入图片描述

从上面可以发现文件夹样式发生变化,这表示可以创建 JSP 文件。

3、创建 JSP 文件

新建一个 abc2.jsp 文件在 webapp 目录下,abc3.jsp 在 WEB-INF 文件夹下面,代码如下:

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<h1>name===>${name}我是 abc2.jsp 测试页面hello jsp dispatcher.forward(path) Spring 只是告诉<br>
    Tomcat 它一个 path 路径,Tomcat 需要自己去动态编译 jsp 存储到 work 目录</h1>

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<h1>name===>${name}我是 abc3.jsp 测试页面hello jsp dispatcher.forward(path) Spring 只是告诉<br>
    Tomcat 它一个 path 路径,Tomcat 需要自己去动态编译 jsp 存储到 work 目录</h1>

4、直接访问 JSP 文件

文件创建好了,那么现在就看看能不能直接访问到,访问地址:http://localhost:9292/abc2.jsp 效果如下:

在这里插入图片描述

在访问 http://localhost:9292/abc3.jsp 效果如下:

在这里插入图片描述

访问不到 abc3.jsp ,是因为在 Tomcat 中有约束 WEB-INF 下资源是安全资源,只能通过 Servlet 或者 Controller 才能访问,所以定义个 ToJspController 访问。

这里需要注意下,如果以上设置都设置好了,访问页面还是 404,比如你是多模块的项目,可以做一下设置:

在这里插入图片描述

如果你还想把 Tomcat 编译过后的 JSP 源码文件显示保存,可以通过一下配置:

server:
  port: 9292
  tomcat:
    basedir: /Users/gongweiming/IdeaProjects/springcloud2022/cloud-redis-service9292

baseDir 就是 Tomcat 的 work 工作目录,也就是 JSP 页面编译后的 Java 源码文件和编译文件都在这个目录保存着。

5、通过 Controller 访问 JSP 页面

一般 JSP 页面访问都是需要携带数据,所以定义 Controller 去访问页面是比较好的,而且 WEB-INF 下面资源是不能直接访问,需要通过 Controller 跳转访问, 代码如下

@Controller
public class ToJspController {
    
    

    @RequestMapping("/toJsp")
    public ModelAndView toJsp(String cx) {
    
    
        ModelAndView view = new ModelAndView();
        System.out.println(">>>>>>toJsp...");
        System.out.println("hnhds");
        view.addObject("name", "gwm");
        view.setViewName(cx);
        return view;
    }
}

然后通过 Controller 访问 abc2.jsp 路径为:http://localhost:9292/toJsp?cx=abc2,效果如下:

在这里插入图片描述

是因为没 SpringBoot 默认 InternalResourceViewResolver 解析器没有读取到配置 prefix、suffix

在这里插入图片描述

这个设置只需要在 application.yml 文件中加上即可,配置如下:

server:
  port: 9292

spring:
  mvc:
    view:
      suffix: .jsp
      prefix: /

然后再去访问就可以访问到 abc2.jsp 页面,如果需要访问 abc3.jsp 则需要修改 yml 文件,如下所示:

server:
  port: 9292

spring:
  mvc:
    view:
      suffix: .jsp
      prefix: /WEB-INF/

然后访问地址 http://localhost:9292/toJsp?cx=abc3,效果如下:

在这里插入图片描述

6、SpringBoot 访问静态资源

SpringBoot 默认在 static 目录中存放静态页面,而 templates 中放动态页面。静态资源如下图示:

在这里插入图片描述

也可以通过 yml 位置修改位置,如下a.html 页面就在不在 static 文件夹中,而是在 html 文件夹中,配置如下:

spring:
  mvc:
    view:
      suffix: .jsp
      prefix: /WEB-INF/
    # 访问静态资源时需要加上前缀 /boot 
    static-path-pattern: /boot/**
  resources:
  	# 访问的静态资源在以下文件夹仲可以找到
    static-locations: classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/, classpath:/html/

/boot/** 表示访问静态资源时需要带上这个 /boot 前缀。

如访问 static 下面的 abc2.html,访问路径名为 http://localhost:9292/boot/abc2.html
如访问 static 下面的 text.txt,访问路径名为 http://localhost:9292/boot/text.txt
如访问 html 下面的 a.html,访问路径名为 http://localhost:9292/boot/a.html

/ 表示 classpath 类路径,表示编译后的路径存放位置,classes 等于 classpath 根路径,所以要访问 html 下面的静态资源,就可以配置 /html/ 访问到,而不是配置 /resources/html/ ,编译后路径如下图示:

在这里插入图片描述

所以加上配置 classpath:/html/ 可以访问到 html 文件夹下静态资源 a.html,访问路劲为http://localhost:9292/boot/a.html

7、手动开启 @EnableWebMvc 注解(看自己需要)

如果你要在 SpringBoot 框架中开启 @EnableWebMvc 注解,表示你要完全接管 SpringMVC 功能,SpringBoot 不会去管理 SpringMVC,源码如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
    
     Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({
    
     DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
    

}

可以从 SpringBoot 装载 WebMvcAutoConfiguration 自动类时看出,是有条件约束的,其中有个条件是 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 表示 Spring 容器中必须不存在 WebMvcConfigurationSupport 类才会装载这个配置类。

回过头看到手动开启的 @EnableWebMvc 注解,源码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
    
    
}

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    
    
}

发现恰好在这里通过 @Import 注解导入了 WebMvcConfigurationSupport 类,这样就会让 Spring 容器中存在一个 WebMvcConfigurationSupport 实例 bean,导致 WebMvcAutoConfiguration 不自动装配。所以在 SpringBoot 中开启这个注解要慎重。

@EnableWebMvc 注解有一些组件在 spring-webmvc 模块中有默认配置的,比如视图解析器 InternalResourceViewResolver,源码如下:

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    
    

	@Bean
	public ViewResolver mvcViewResolver(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
    
    
		ViewResolverRegistry registry =
				new ViewResolverRegistry(contentNegotiationManager, this.applicationContext);
		configureViewResolvers(registry);

		if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
    
    
			String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
					this.applicationContext, ViewResolver.class, true, false);
			if (names.length == 1) {
    
    
				registry.getViewResolvers().add(new InternalResourceViewResolver());
			}
		}
		return composite;
	}
}

从上述源码可以看出,只有 Spring 容器中存在一个 ViewResolver 接口实现时才会默认装载 InternalResourceViewResolver 视图解析器,如果存在两个就不装载。在 SpringBoot 中刚好有个处理错误页面的视图解析器存在,所以这里就会导致 InternalResourceViewResolver 不会被装载。这里可以关闭这个错误页处理器,通过 yml 配置即可,配置如下:

server:
  error:
    whitelabel:
      enabled: false

但是这里只是装载的视图解析器,并没有指定 prefixsuffix 前后缀。所以在访问的时候,你自己需要带上前后缀格式。

比如要访问上面说的 abc2.jsp 页面,访问路径为:http://localhost:9292/toJsp?cx=abc2.jsp 前后缀分别是 / .jsp ,访问 abc3.jsp 页面,访问路径为:http://localhost:9292/toJsp?cx=/WEB-INF/abc3.jsp 前后缀分别是 /WEB-INF/ .jsp 。一般是不会这样访问,那就需要自定义配置,自己指定视图解析器 prefixsuffix 前后缀。

7.1、实现 WebMvcConfigurer 接口添加配置实现自定义配置(看自己需要)

更早版本是实现 WebMvcConfigurerAdapter 类,但是现在已经过期,推荐使用 WebMvcConfigurer 接口,缺少那部分功能就添加对应功能即可。

MvcConfig 配置类如下:

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    
    
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
    
    
        registry.jsp().suffix(".jsp").prefix("/");
    }
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
    
    
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/","classpath:/html/" };

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    

        registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
    }
}

在这里自定义两个组件,一个是视图解析器组件,一个是静态资源解析组件。@EnableWebMvc 注解默认是没有打开静态资源解析,需手动开启,通过 addResourceHandlers() 方法添加需解析的静态资源。

其中/** 表示访问静态资源时,不限制访问层级目录。一般会像下面配置,通过访问路径隔开资源文件,如下:

Spring boot 默认对 /** 的访问 是可以直接访问类路径下的四个静态资源目录下的文件:

  • classpath:/public/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/META-INFO/resouces/
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
	
		registry.addResourceHandler("/dist/**").addResourceLocations("classpath:/static/dist/");
		registry.addResourceHandler("/theme/**").addResourceLocations("classpath:/static/theme/");
		registry.addResourceHandler("/boot/*").addResourceLocations("classpath:/static/");
		// registry.addResourceHandler("/boot/**").addResourceLocations("classpath:/static/");
		// registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
	}

二、SpringBoot 整合 Thymeleaf

轻量级的模板引擎(负责逻辑业务的不推荐,解析DOM或者XML 会占用多的内存)可以直接在浏览器中打开且正确显示模板页面,直接是 html 结尾。

1、引入依赖

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

2、配置 yml 文件

spring:
  freemarker:
    suffix: .ftlh
    enabled: true
    prefix: /

3、templates 下新建 html 页面

在 templates 文件夹下面新建 html 页面,声明域名解析是 http://www.thymeleaf.org ,这样在页面中使用 Thymeleaf 标签才能够生效,最常用是 th: 标签

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"> </meta>
    <title>Thymeleaf project</title>
</head>
<body>
<h1>thymeleaf 页面</h1><h1 th:text="${name}"></h1>
</body>
</html>

在这里插入图片描述

4、通过 Controller 访问

@Controller
public class ToJspController {
    
    

    @RequestMapping("/toJsp")
    public ModelAndView toJsp(String cx) {
    
    
        ModelAndView view = new ModelAndView();
        System.out.println(">>>>>>toJsp...");
        System.out.println("hnhds");
        view.addObject("name", "gwm");
        view.setViewName(cx);
        return view;
    }
}

访问路径为:http://localhost:9292/toJsp?cx=abc3 页面效果如下:

在这里插入图片描述

可以发现 Controller 封装的 Model 的 name 值。这个就是 Thymeleaf 提供的 th: 标签可以做到。

然后再试试以静态资源的形式去访问,路径为:http://localhost:9292/boot/abc3.html 效果如下:

在这里插入图片描述

可以发现 abc3.html 直接就被 write() 在浏览器上了,就是被当做事一个静态资源打印出。

三、SpringBoot 整合 Freemarker

FreeMarker Template Language 文件一般保存为 xxx.ftlh 或者 xxx.ftl 严格依赖 MVC模式,不依赖 Servlet 容器(不占用 JVM 内存)内建函数。

1、引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22</version>
        </dependency>

2、编写模板文件

一般 thymeleaf 默认.htmlfreemarker 默认 .ftl 放在 resources 下面的 templates 目录下(默认访问路径)

在这里插入图片描述

3、编写 Controller 层代码

public class Users {
    
    
    private String username;
    private String usersex;
    private String userage;

    public Users(String username, String usersex, String userage) {
    
    
        this.username = username;
        this.usersex = usersex;
        this.userage = userage;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getUsersex() {
    
    
        return usersex;
    }

    public void setUsersex(String usersex) {
    
    
        this.usersex = usersex;
    }

    public String getUserage() {
    
    
        return userage;
    }

    public void setUserage(String userage) {
    
    
        this.userage = userage;
    }
}
@Controller
public class TestController {
    
    

    @RequestMapping("/myfreemarker")
    public String showUsers(Model model) {
    
    
        List<Users> list = new ArrayList<>();
        list.add(new Users("aa", "F", "21"));
        list.add(new Users("bb", "M", "20"));
        list.add(new Users("cc", "F", "22"));
        model.addAttribute("list", list);

        return "myfreemarker";
    }
}

4、效果展示

访问地址: http://localhost:9292/myfreemarker

在这里插入图片描述

四、总结

1、以上 JSP、Thymeleaf、Freemarker 全部共存时,SpringBoot 默认做了排序,优先是静态文件资源,最后是 JSP 资源。因为 JSP 在 Spring 中是不会真正去判断存不存在该文件,而是交给 Tomcat 去自己处理判断。而 Thymeleaf、Freemarker 两种后端模版引擎直接会先去判断文件收存在。从源码可以看出他们的优先级,如下图示:

在这里插入图片描述

2、JSP 现在很少用,现在就看 Thymeleaf 和 Freemarker 谁更好用?

如果你选了 Thymeleaf,非常不幸截至到现在 Thymeleaf 已经两年没更新了,不知道会不会Velocity 停止更新7年之久很多年前也有人问 Velocity 和 Freemarker 选哪个?Velocity 可是Apache 背书。但时间证明freemarker自始至终都是一种明智得选择过去的20年,Freemarker 经历过4次重构和长期更新迭代,尽可能保持了向后兼容,它能良好的支持 JSP 标签、JSON 格式数据、XML 格式数据,能方便的让你实现 java 扩展,拥有完善的字符串、数字、序列、哈希表等数据处理方法,对 html,url,js,json 等安全转义等,它可以用于任何模板引擎可以应用的场景,自带国际化解决方案,清晰的异常日志(包含错误原因、错误位置、错误提示、模板堆栈、java 堆栈)能让你第一时间找到模板中错误的问题所在,强大到完全可以创造一门新的动态语言,却又严守模板引擎边界,其强大、完整、安全性可以超越任何一款不仅限于 java 语言的模板引擎。

猜你喜欢

转载自blog.csdn.net/qq_35971258/article/details/128736203