一、前言
SpringBoot 里面没有我们之前常规 web 开发的 WebContent(WebApp),它只有src目录,在src/main/resources
下面有两个文件夹,static 和 templates,springboot 默认 static 中放静态页面(public 文件夹中也可以),而 templates 中放动态页面。
二、静态页面
静态页面可以直接访问。这里我们直接在 static 放一个 hello.html
,然后直接输入http://localhost:8080/hello.html
便能成功访问(pubic 文件夹同理)。
也可以通过 controller 跳转:注入的时候一定要是@Controller
,而不要是@RestController
,因为它是 rest 接口(json格式)是解析不到 html:
@Controller
public class HelloController {
@RequestMapping("/hehe")
public String hehe() {
return "hello.html";
}
@RequestMapping("/haha")
public String haha() {
return "user/test.html";
}
}
hello.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试1</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
test.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试2</title>
</head>
<body>
<h1>我的第一个标题</h1>
<p>我的第一个段落。</p>
</body>
</html>
然后输入http://localhost:8080/haha
就可以成功访问
注意:@RequestMapping
中的 url 不要跟视图重名,否则会抛出 Circular view path
异常,如:
@RequestMapping("/hello")
public String hehe() {
return "hello.html";
}
三、动态页面
动态页面需要先请求服务器,访问后台应用程序,然后再转向到页面,比如访问 JSP。spring boot 建议不要使用 JSP,默认使用Thymeleaf来做动态页面。
要在 pom 中要添加 Thymeleaf 组件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
但你加上了上面的 thymeleaf 后,你必须重启工程,即使是你配置了热启动后,也要重启工程,才可以看到效果。
我们先在 templates 文件夹中也新建一个 hello.html
但内容不同,然后先试一下直接访问该页面。输入http://localhost:8080/hello.html
后结果显然访问的是静态文件夹里面的那个 hello.html
。
然后我们现在再试一下用controller:http://localhost:8080/hehe
我们需要这样改 controller,然后就可以成功跳转了:
@RequestMapping("/hehe")
public String hehe() {
return "hello";
}
如果在使用动态页面时还想跳转到 /static/xxx.html
,可以使用重定向 return "redirect:/xxx.html"
。
@RequestMapping("/hehe")
public String hehe() {
return "redirect:hello.html";
}
我们看看返回一点数据在前端利用Thyemleaf来拿:
@Controller
public class HelloController {
@RequestMapping("/Hi")
public ModelAndView sayHello() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("hello");
modelAndView.addObject("key", 12345);
return modelAndView;
}
}
Templates/hello.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Insert title here</title>
</head>
<body>
<h1>this is the hello.html in templates</h1>
<span th:text="${key}"></span>?
</body>
</html>
效果:
使用thymeleaf来达到以前jsp获取Model值这样的效果:
在文件 application.yml
或 application.property
中加配置:
# 在构建URL时预先查看名称的前缀,写/templates/也可以
spring.thymeleaf.prefix=classpath:templates/
# 构建URL时附加查看名称的后缀.
spring.thymeleaf.suffix=.html
# 模板编码
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.encoding=UTF-8
# Content-Type值
spring.thymeleaf.content-type=text/html
# 关闭thymeleaf缓存 开发时使用 否则没有实时画面
spring.thymeleaf.cache=false
<!--避坑包-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
要想使用 LEGACYHTML5
这个编码格式必须引入上面 pom 中避坑包
否则用不了。肯定有人要问为什么不用HTML5
,你可以试试。因为你可能会发现在默认配置下,thymeleaf 对 .html
的内容要求很严格,比如<meta charset="UTF-8" />
,如果少最后的标签封闭符号/
,就会报错而转到错误页。也比如你在使用 Vue.js
这样的库,然后有<div v-cloak></div>
这样的 html 代码,也会被 thymeleaf 认为不符合要求而抛出错误。因此,建议增加下面这段:spring.thymeleaf.mode = LEGACYHTML5
spring.thymeleaf.mode
的默认值是 HTML5,其实是一个很严格的检查,改为 LEGACYHTML5
可以得到一个可能更友好亲切的格式要求。需要注意的是,LEGACYHTML5
需要搭配一个额外的库 NekoHTML 才可用,也就是上面的避坑包。注意导入该依赖后你必须重启工程,即使是你配置了热启动后,也要重启工程,才可以看到效果
再写控制类时把 Model 加在参数中:
@RequestMapping(value = "/action",method = RequestMethod.GET)
public String index(Model model){
model.addAttribute("aaa","我是一个兵");
return "index";
}
index.html:
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org"> <!-- 听说要有这句话,但我没有要这个标签,也能用 -->
<head>
<body>
<h1>这里是测试</h1>
<p>Today is: <span th:text="${aaa}" </span>。</p> <!-- 不能直接${aaa},而应该写在一个标签中 -->
</html>
效果:
四、补充:热部署
就是说在项目中修改代码可以不用重新停止应用再重新启动,可以自动重启
在 pom 文件中引入 devtools 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖myboot项目的项目如果想要使用devtools,需要重新引入 -->
<optional>true</optional>
</dependency>
原理:
深层原理是使用了两个 ClassLoader,一个 Classloader 加载那些不会改变的类(第三方Jar包),另一个 ClassLoader 加载会更改的类,称为 restart ClassLoader
,这样在有代码更改的时候,原来的 restart ClassLoader
被丢弃,重新创建一个 restart ClassLoader
,由于需要加载的类相比较少,所以实现了较快的重启时间。
说明:
(1)某些资源在更改时不一定需要触发重新启动。例如,Thymeleaf 模板可以就地进行编辑。默认情况下更改资源路径包括了:/META-INF/maven
, /META-INF/resources
,/resources
,/static
,/public
或者 /templates
不会触发重新启动,但会触发实时重新加载。如果逆向排除这些路径,可以使用如下配置:spring.devtools.restart.exclude=static/**
,public/**
,WEB-INF/**
(2)如果要保留这些默认值并添加其他排除项,请使用 spring.devtools.restart.additional-exclude
属性代替。如:spring.devtools.restart.additional-paths=src/main/java
(3)通过 System.setProperty("spring.devtools.restart.enabled", "false");
方法,可以在 SpringApplication.run()
方法运行天使用关闭 devtools 。
(4)当我们再次启动的时候,使用的加载器就变为了 restartedMain 了,说明热部署已经成功。
注意:devtools 由于是双类加载机制,再结合了通用 Mapper 后可能会出现java.lang.ClassCastException
异常(例如说:class x.x.A cannot be cast to x.x.A
。)
解决:在 src/main/resources
中创建 META-INF
目录,在此目录下添加 spring-devtools.properties
配置,内容如下:
restart.include.mapper=/mapper-[\\w-\\.]+jar
restart.include.pagehelper=/pagehelper-[\\w-\\.]+jar
五、补充:查看Spring Boot内嵌的tomcat日志
Spring Boot
本身附带一个嵌入式Tomcat
服务器,非常方便。但是在默认情况下是无法看到Tomcat
的日志。
默认情况下,是未启用访问日志的。我们可以通过向application.properties
添加属性来轻松启用它们:server.tomcat.accesslog.enabled=true
,最后可在Linux上查看: