文章目录
1、模板引擎-Thymeleaf
1)thymeleaf简介
现代化、服务端Java模板引擎
2)基本语法
3)字面量
文本值: ‘one text’ , ‘Another one!’
数字: 0 , 34 , 3.0 , 12.3
布尔值: true , false
空值: null
变量: one,two,变量不能有空格
4)文本操作
字符串拼接: +
变量替换: |The name is ${name}|
5)数学运算
运算符: + , - , * , / , %
6)布尔运算
运算符: and , or
一元运算: ! , not
7)比较运算
比较: > , < , >= , <= ( gt , lt , ge , le )等式: == , != ( eq , ne )
8)条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
9)thymeleaf使用
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
页面开发
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2>
<a href="www.atguigu.com" th:href="${link}">去百度</a> <br/>
</h2>
</body>
</html>
2、构建后台管理系统
1)项目创建
thymeleaf、web-starter、devtools、lombok
2)静态资源处理
自动配置好,我们只需要把所有静态资源放到 static 文件夹下
3)路径构建
th:action=“@{/login}”
4)模板抽取
th:insert/replace/include
So an HTML fragment like this:
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
…included three times in host <div> tags, like this:
<body>
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>
…will result in:
<body>
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
5)页面跳转
@PostMapping("/login")
public String main(User user, HttpSession session, Model model){
if(StringUtils.hasLength(user.getUserName()) && "123456".equals(user.getPassword())){
//把登录成功的用户保存起来
session.setAttribute("loginUser",user);
//登录成功重定向到main.html; 重定向防止表单重复提交
return "redirect:/main";
}else {
model.addAttribute("msg","账号密码错误");
//回到登录页面
return "login";
}
}
6)遍历数据
<table class="display table table-bordered" id="hidden-table-info">
<thead>
<tr>
<th>#</th>
<th>用户名</th>
<th>密码</th>
</tr>
</thead>
<tbody>
<tr class="gradeX" th:each="user,stats:${users}">
<td th:text="${stats.count}">Trident</td>
<td th:text="${user.userName}">Internet</td>
<td >[[${user.password}]]</td>
</tr>
</tbody>
</table>
3、拦截器
1)HandlerInterceptor 接口
/**
* 登录检查
* 1、配置好拦截器要拦截哪些请求
* 2、把这些配置放在容器中
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 控制器方法执行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("preHandle拦截的请求路径是{}",requestURI);
//登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
//放行
return true;
}
//拦截住,未登录,跳转到登录页
request.setAttribute("msg","请先登录");
// re.sendRedirect("/");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
/**
* 控制器方法执行完成以后
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle执行{}",modelAndView);
}
/**
* 页面渲染以后
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行异常{}",ex);
}
}
2)配置拦截器
/**
* 1、编写一个拦截器实现HandlerInterceptor接口
* 2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
* 3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
*/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //所有请求都被拦截包括静态资源
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求
}
}
3)拦截器原理
1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有拦截器】
2、先顺序执行所有拦截器的 preHandle方法
a>如果当前拦截器prehandler返回为true,则执行下一个拦截器的preHandle
b>如果当前拦截器返回为false,直接倒序执行所有已经执行了的拦截器的 afterCompletion;
3、如果任何一个拦截器返回false,直接跳出不执行目标方法
4、所有拦截器都返回True,执行目标方法
5、倒序执行所有拦截器的postHandle方法
6、前面的步骤有任何异常都会直接倒序触发 afterCompletion
7、页面成功渲染完成以后,也会倒序触发 afterCompletion
4、文件上传
1)页面表单
<form method="post" th:action="@{/upload}" enctype="multipart/form-data">
用户名: <input type="text" name="username"><br>
头像: <input type="file" name="headerImg"><br>
生活照: <input type="file" name="photos" multiple><br>
<input type="submit" value="提交">
</form>
2)文件上传代码
/**
* MultipartFile 自动封装上传过来的文件
* @param username
* @param headerImg
* @param photos
* @return
*/
@PostMapping("/upload")
public String upload(
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
log.info("上传的信息:username={},headerImg={},photos={}",
username,headerImg.getSize(),photos.length);
if(!headerImg.isEmpty()){
//保存到文件服务器,OSS服务器
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("D:\\Study\\"+originalFilename));
}
if(photos.length > 0){
for (MultipartFile photo : photos) {
if(!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("D:\\Study\\"+originalFilename));
}
}
}
return "main";
}
3)文件上传大小设置
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-request-size=100MB
5、异常处理
错误处理
1、默认规则
默认情况下,Spring Boot提供/error处理所有错误的映射
对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
2、error/下的4xx,5xx页面会被自动解析