1.大概介绍:
Thymeleaf和Jsp一样是一个模板引擎,但是它有几个特点:
1.动静结合,就算没有服务器对页面进行解析(解析也就解析th:xxx),它也一样可以运行,比较友好;
2.支持html,后台的数据展示只需要在html中的标签加入额外属性,就可以达到模板+数据的展示方式;
3.对于表单的提交绑定数据,属性的编辑,国际化功能都可以比较快的完成;
4.通常情况下,前端如果想要获取后端的数据,一般都是通过Ajax发送异步请求来获取后台传输的数据,然后通过Js去处理这些数据,最后通过html方法或者是其他的将其拼接成字符串传入html标签中,最后被浏览器解析,从而更新页面数据;
而使用thymeleaf后,可以直接一步到位;
2.使用:
1.首先导入依赖spring-boot-starter-thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.thymeleaf的参数配置:
如果你需要重新定义thymeleaf的属性,可以去ThymeleafAutoConfiguration类中,然后和之前一样的操作(像xxxAutoConfiguration这种,一般都是放组件的,一些执行流程,执行方法),然后里面的值就由对应的xxxProperties(也可以理解为实体类)来解决,然后里面绑定的值根据@ConfigurationProperties(prefix="xxx")就知道了:
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enableSpringElCompiler;
private boolean renderHiddenMarkersBeforeCheckboxes;
private boolean enabled;
private final ThymeleafProperties.Servlet servlet;
private final ThymeleafProperties.Reactive reactive;
3.控制层(简单逻辑):
1.当访问对应请求时,返回到login页面
/**
* 来登录页
* @return
*/
@GetMapping(value = {"/","/login"})
public String loginPage(){
return "login";
}
?输入表单信息userName与password,利用th:action="@{/login}":也就是得到一个当前项目的login请求替换前面默认的action;
<div class="container">
<!--表单提交(也就是th:action="@{/xxx}"),服务器controller层对对应的请求进行解析-->
<form class="form-signin" action="index.html" method="post" th:action="@{/login}">
<div class="form-signin-heading text-center">
<h1 class="sign-title">Sign In</h1>
<img src="images/login-logo.png" alt=""/>
</div>
<div class="login-wrap">
<!-- 取出msg文本信息-->
<label style="color: red" th:text="${msg}"></label>
<input type="text" name="userName" class="form-control" placeholder="User ID" autofocus>
<input type="password" name="password" class="form-control" placeholder="Password">
<button class="btn btn-lg btn-login btn-block" type="submit">
<i class="fa fa-check"></i>
</button>
<div class="registration">
Not a member yet?
<a class="" href="registration.html">
Signup
</a>
</div>
<label class="checkbox">
<input type="checkbox" value="remember-me"> Remember me
<span class="pull-right">
<a data-toggle="modal" href="#myModal"> Forgot Password?</a>
</span>
</label>
</div>
<!-- Modal -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="myModal"
class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Forgot Password ?</h4>
</div>
<div class="modal-body">
<p>Enter your e-mail address below to reset your password.</p>
<input type="text" name="email" placeholder="Email" autocomplete="off"
class="form-control placeholder-no-fix">
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
<button class="btn btn-primary" type="button">Submit</button>
</div>
</div>
</div>
</div>
<!-- modal -->
</form>
</div>
4.接下来我们处理这个请求:对于这个这个请求我们首先要有逻辑判断,进行简单的验证(这里不作数据库验证处理):?利用StringUtils的方法hasLength()与equals对userName与password进行验证,符合就放入session中,并且重定向到main页面,否则将错误提示信息传入请求域中并返回login页面;
@PostMapping("/login")
public String main(User user, HttpSession session, Model model){ //RedirectAttributes
if(StringUtils.hasLength(user.getUserName()) && "123456".equals(user.getPassword())){
//把登陆成功的用户保存起来
session.setAttribute("loginUser",user);
//登录成功重定向到main.html; 重定向防止表单重复提交
return "redirect:/main.html";
}else {
model.addAttribute("msg","账号密码错误");
//回到登录页面
return "login";
}
}
@GetMapping("/main.html")
public String mainPage(HttpSession session,Model model){
log.info("当前方法是:{}","mainPage");
return "main";
}
3.thymeleaf语法:
用thymeleaf处理前端时,我们常常需要将页面中的共同部分拿出来放到一个单独的页面中,这样我们可以利用thymeleaf对共同部分进行拿取;
1.th:fragment="xxx":说明这是个片段,可以在其他页面中被调用插入替换;
2.th:href="@{/css/style.css}":意思就是当前项目下的静态资源路径,static下...
th:src="@{xx/xxx}":与上述差不多,也是路径的
<head th:fragment="commonheader">
<!--common-->
<link href="css/style.css" th:href="@{/css/style.css}" rel="stylesheet">
<link href="css/style-responsive.css" th:href="@{/css/style-responsive.css}" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="js/html5shiv.js" th:src="@{/js/html5shiv.js}"></script>
<script src="js/respond.min.js" th:src="@{/js/respond.min.js}"></script>
<![endif]-->
</head>
<div th:fragment="headermenu" class="..."> ....</div>
?Thymeleaf中的语意还需要根据具体标签来判断,像<link>标签这种里面的th:href,th:src...都只是引入资源;
像如果在<a>标签中的th:href,那就是点击请求,让服务器处理请求的;
<li class="menu-list nav-active"><a href="#"><i class="fa fa-th-list"></i> <span>Data Tables</span></a>
<ul class="sub-menu-list">
<li><a th:href="@{/basic_table}"> Basic Table</a></li>
<li><a th:href="@{/dynamic_table}"> Advanced Table</a></li>
<li><a th:href="@{/responsive_table}"> Responsive Table</a></li>
<li><a th:href="@{/editable_table}"> Edit Table</a></li>
</ul>
</li>
当点击这些a标签后,控制器中对应的方法会接收到对应的请求,然后显示对应页面;
这里提一下@RequestParam中的参数:defaultValue:有0、1两种形式,0:地址不需要参数,1:需要带参数;默认defaultValue为1;
@GetMapping("/dynamic_table")
public String dynamic_table(@RequestParam(value="pn",defaultValue="1")Integer pn,Model model){
//简单遍历表单内容
List<User>user=Arrays.asList(new User("zhangsan","12345"),
new User("Fairy","1233"));
model.addAttribute("users",users);
return "table/dynamic_table";//因为thymeleaf的suffix与prefix已经设定好了,而这个页面是在Template下面一个等级的
}
@GetMapping("/responsive_table")
public String responsive_table() {
return "table/responsive_table";
}
@GetMapping("/editable_table")
public String editable_table() {
return "table/editable_table";
}
}
抽取公共元素:
?一般来说,我们对公共代码代码块需要使用thymeleaf进行统一命名:th:fragment="xxx",或者在标签中用id
<div id=leftmenu class="xxx">xxx</div>
<script th:fragment>xxx</script>
其他页面中插入公共部分:
三种方式:代替:整个标签容器连同内容一起代替
包括:只替换内容,不替换标签
插入:将公共部分的标签及其内容插入到当前页面标签下(可能会多出不要的标签)
<div th:replace="common :: headermenu"></div>
<div th:include="common :: leftmenu"></div>
<div th:insert="common :: xxx"></div>
5.视图解析的原理流程:
1.当前请求被目标方法处理的过程中,所有数据分为了两个部分:数据and视图地址。他们会被放在·ModelAndViewContainer中;
2.任何方法执行完后都会返回ModelAndView,然后processDispatcherResult会处理派发结果(页面如何响应)
最关键的:render()方法,进行页面渲染逻辑,根据方法的返回值得到View对象;
1.然后遍历所有的视图解析器看能否根据返回值得到View对象
2.得到redirect:/main.html
3.内容协商视图解析器ContentNegotiationViewResolver里面包含了所有视图解析器,利用视图解析器得到视图对象(可以自定义)
4.view.render(modelAndview,req,resp):首先获取请求的url地址,然后resp.sendRedirect(url);
|