Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02

Spring Boot****整合视图层技术*

这一节我们主要学习如何整合视图层技术:

  • Jsp

  • Freemarker

  • Thymeleaf

在之前的案例中,我们都是通过 @RestController 来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?

Spring Boot推荐使用模板引擎

模板引擎实现伪html 达到seo优化 使动态页面静态化

在动态html上实现Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。

Spring Boot提供了默认配置的模板引擎主要有以下几种:

  • Thymeleaf
  • FreeMarker
  • Velocity
  • Groovy
  • Mustache

Spring Boot建议使用这些模板引擎,避免使用jsp。

1.Jsp

创建项目

创建 war 项目,编写pom.xml

  
    UTF-8
    1.8
    1.8
  

  
    org.springframework.boot
    spring-boot-starter-parent
    2.1.6.RELEASE
  

  
    
    
      org.springframework.boot
      spring-boot-starter-web
    

视图解析器

resources/application.properties

#配置视图解析器
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

实体类

User.java

public class User implements Serializable {

    private Integer id;
    private String username;
    private Integer age;

    public User() {
    }

    public User(Integer id, String username, Integer age) {
        this.id = id;
        this.username = username;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
    

控制层

UserController.java

@Controller
public class UserController {

    @RequestMapping("/showUser")
    public String showUser(Model model) {
        List list = new ArrayList<>();
        list.add(new User(1, "张三", 18));
        list.add(new User(2, "李四", 20));
        list.add(new User(3, "王五", 22));
        model.addAttribute("list", list);
        // 跳转视图
        return "userList";
    }

}

视图层

userList.jsp

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



    
    用户展示


    
            
ID Name Age
${user.id} ${user.username} ${user.age}

启动类

App.java

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

结果

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第1张图片
image.png
2.Freemarker

创建项目

创建 war 项目,编写pom.xml

 
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
    

  
    
    
      org.springframework.boot
      spring-boot-starter-web
    

视图解析器

该文件内容不一定非得需要,可以不添加,不添加使用默认值。

resources/application.properties

实体类

User.java

同上user实体类

控制层

UserController.java

@Controller
public class UserController {

    @RequestMapping("/showUser")
    public String showUser(Model model) {
        List list = new ArrayList<>();
        list.add(new User(1, "张三", 18));
        list.add(new User(2, "李四", 20));
        list.add(new User(3, "王五", 22));
        model.addAttribute("list", list);
        // 跳转视图
        return "userList";
    }

}

视图层

Spring Boot要求模板形式的视图层技术的文件必须要放到 src/main/resources 目录下的 templates 目录。

该目录内的模板文件名称必须是 ftl 的后缀结尾。

userList.ftl




    用户展示
    



    <#list list as user >
        
用户信息
ID Name Age
${user.id} ${user.username} ${user.age}

启动类

App.java

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

结果

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第2张图片
image.png
3.Thymeleaf (重点讲解)

入门案例

创建项目

创建 war 项目,编写pom.xml

    
      
      org.springframework.boot
      spring-boot-starter-thymeleaf
      

控制层

ThymeleafController.java

@Controller
public class ThymeleafController {

    @RequestMapping("/show")
    public String show(Model model) {
        model.addAttribute("message", "Thymeleaf 入门");
        return "msg";
    }

}


视图层

Spring Boot要求模板形式的视图层技术的文件必须要放到 src/main/resources 目录下的 templates 目录。

msg.html




    
    Thymeleaf入门


    
    



启动类

App.java

@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第3张图片
image.png

运行结果出现异常(如果是 Spring Boot 1.X.X 版本才会出现此异常):

1   org.xml.sax.SAXParseException: 元素类型 "meta" 必须由匹配的结束标记 "" 终止。

异常处理

如果是 Spring Boot 1.X.X 版本需要以下操作,本案例是 Spring Boot 2.1.6 版本,所以不需要更改。

方式一:编写风格严谨的HTML代码

1

**方式二:更换hymeleaf的****jar包版本

thymeleaf.jar:更新为 3.0 以上的版本


3.0.11.RELEASE 



运行结果

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第4张图片
image.png

Thymeleaf 语法详解

Thymeleaf 内置对象语法:

  • 调用内置对象一定要用 #
  • 大部分的内置对象都以 s 结尾 strings 、 numbers 、 dates

准备数据

实体类

User.java

public class User implements Serializable {

    private Integer id;
    private String username;
    private Integer age;

    public User() {
    }

    public User(Integer id, String username, Integer age) {
        this.id = id;
        this.username = username;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
    
}

控制层

ThymeleafController.java

@Controller
public class ThymeleafController {

    @RequestMapping("/show")
    public String showMsg(Model model,
                          HttpServletRequest request,
                          HttpServletResponse response) {

        // 字符串
        model.addAttribute("msg", "Thymeleaf 入门案例");
        // 日期时间
        model.addAttribute("myDate", new Date());
        // 条件判断if
        model.addAttribute("sex", 1);
        // 条件判断switch
        model.addAttribute("id", 1);
        // 对象
        model.addAttribute("user", new User(1, "张三", 20));

        // 迭代遍历list
        List userList = new ArrayList<>();
        userList.add(new User(1, "张三", 20));
        userList.add(new User(2, "李四", 22));
        userList.add(new User(3, "王五", 24));
        model.addAttribute("userList", userList);

        // 迭代遍历map
        Map userMap = new HashMap<>();
        userMap.put("u1", new User(1, "张三", 20));
        userMap.put("u2", new User(2, "李四", 22));
        userMap.put("u3", new User(3, "王五", 24));
        model.addAttribute("userMap", userMap);

        // 域对象操作
        request.setAttribute("req", "HttpServletRequest");
        request.getSession().setAttribute("sess", "HttpSession");
        request.getSession().getServletContext().setAttribute("app", "Application");
        return "msg";

    }

    /**
     * URL表达式-相对路径
     * @return
     */
    @RequestMapping("/index")
    public String index() {
        return "index";
    }

    /**
     * URL表达式-普通传参
     * @param id
     * @param username
     * @return
     */
    @RequestMapping("/user")
    public String user(Integer id, String username) {
        System.out.println("id:" + id + " username:" + username);
        return "user";
    }

    /**
     * URL表达式-restful传参
     * @param id
     * @param username
     * @return
     */
    @RequestMapping("/person/{id}/{username}")
    public String person(@PathVariable Integer id, @PathVariable String username) {
        System.out.println("id:" + id + " username:" + username);
        return "person";
    }

}

视图层

index.html




    
    Thymeleaf


index



user.html




    
    Thymeleaf


user


person.html




    
    Thymeleaf


person



字符串

字符串操作

${#strings.isEmpty(key)} :判断字符串是否为空

${#strings.contains(msg, 'T')} :判断字符串是否包含子串

${#strings.startsWith(msg, 'T')} :判断字符串是否以子串开头

${#strings.endsWith(msg, 'T')} :判断字符串是否以子串结尾

``

${#strings.length(msg)} :返回字符串的长度

``

${#strings.indexOf(msg, 'T')} :查找子串的位置,并返回该子串的下标,如果没找到则返回-1

${#strings.substring(msg, 5)} :截取子串,从指定下标开始截止到末尾结束

${#strings.substring(msg, 5, 12)} :截取子串,从指定下标开始截止到指定下标结束

``

${#strings.toUpperCase(msg)} :将字符串转大写

${#strings.toLowerCase(msg)} :将字符串转小写

日期时间

${#dates.format(key)} :格式化日期,以浏览器默认语言为格式化标准

${#dates.format(key,'yyy/MM/dd')} :自定义格式日期转换

${#dates.year(myDate)} :获取年份,还可以获取月份、日、时、分、秒

条件判断

th:if :单选择

性别:


th:switch :多选择(如果要实现 if else if else 判断表达式,在 Thymeleaf 要使用 th:switch 代替)

编号:
1 张三
2 李四
3 王五


对象




迭代遍历

th:each :迭代遍历

th:each :状态变量属性

  • ​ index:当前迭代器的索引 从 0 开始
  • ​ count:当前迭代对象的计数 从 1 开始
  • ​ size:被迭代对象的长度
  • ​ even/odd:布尔值,当前循环是否是偶数/奇数 从 0 开始
  • first:布尔值,当前循环的是否是第一条,如果是返回 true 否则返回 false
  • last:布尔值,当前循环的是否是最后一条,如果是则返回 true 否则返回 false

th:each :迭代 Map

Id Name Age
Id Name Age

域对象操作

${#httpServletRequest.getAttribute(key)} :HttpServletRequest

``

${session.key} :HttpSession

``

${application.key} :ServletContext

URL****表达式

基本语法

URL表达式的基本语法: @{}

th:href :绝对路径

绝对路径

th:href :相对路径,相对于当前项目的根路径

相对于当前项目的根路径

th:href :相对路径, 相对于服务器的根路径

相对于服务器的根路径

参数传递

   相对路径-普通传参
    相对路径-restful传参
    相对路径-restful传参


Spring Boot****整合持久层技术
1.MyBatis

创建项目

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第5张图片
image.png

创建 jar项目,编写pom.xml

 
    org.springframework.boot
    spring-boot-starter-parent
    2.1.7.RELEASE
  


  
    
    
      org.springframework.boot
      spring-boot-starter-web
    
    
    
      org.springframework.boot
      spring-boot-starter-thymeleaf
    
    
    
      org.mybatis.spring.boot
      mybatis-spring-boot-starter
      2.1.0
    
    
    
      mysql
      mysql-connector-java
    
    
    
      com.alibaba
      druid
      1.1.19
    
  

  
  
    
    
      
        src/main/resources
      
      
        src/main/java
        
          **/*.xml
          **/*.properties
          **/*.tld
        
        false
      
    
  

properties 配置文件

添加 application.properties 全局配置文件

# 配置数据库驱动
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=shsxt
# 配置数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 配置mybatis数据返回类型别名(默认别名是类名)
mybatis.type-aliases-package=com.springboot.pojo
# 配置mybatis.Maper映射文件
mybatis.mapper-locations=classpath:com/springboot/mapper/*.xml


SQL****文件

创建一个test表,字段id,name ,age;

    CREATE TABLE `user` (

`id` INT (11) NOT NULL AUTO_INCREMENT,

`name` VARCHAR (255) DEFAULT NULL,

`age` INT (11) DEFAULT NULL,

5PRIMARY KEY (`id`)

   ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;


1.1添加用户

实体类

User.java

public class User implements Serializable {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

Mapper 接口

UserMapper.java

public interface UserMapper {

    // 添加用户
    int insertUser(User user);

    // 查询用户
    List selectUserList();

    // 根据主键查询用户
    User selectUserById(Integer id);

    // 修改用户
    int updateUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

映射配置文件

UserMapper.xml






    
    
        insert into user (name, age) values (#{name}, #{age})
    

    
    

    
    

    
    
        update user set name = #{name}, age = #{age} where id = #{id};
    

    
    
        delete from user where id = #{id}
    



业务层

UserServiceI.java

public interface UserServiceI {

    int insertUser(User user);

    // 查询用户
    List selectUserList();

    // 根据主键查询用户
    User selectUserById(Integer id);

    // 修改用户
    int updateUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

UserServiceImpl.java

@Service
@Transactional
public class UserServiceImpl implements UserServiceI {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int insertUser(User user) {
        return userMapper.insertUser(user);
    }

    @Override
    public List selectUserList() {
        return userMapper.selectUserList();
    }

    @Override
    public User selectUserById(Integer id) {
        return userMapper.selectUserById(id);
    }

    @Override
    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    @Override
    public int deleteUser(Integer id) {
        return userMapper.deleteUser(id);
    }

}


控制层

UserController.java

/**
 * 操作持久层
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserServiceI userService;

    /**
     * 页面跳转
     */
    @RequestMapping("/{page}")
    public  String page(@PathVariable String page){
        return page;
    }
    /**
     * 添加用户
     */
    @PostMapping("/insertUser")
    public String insertUser(User user){
        int result =userService.insertUser(user);
        return "success";
    }

    /**
     * 查询用户列表
     */
    @GetMapping("/selectUserList")
    public String selectUserList(Model model) {
        model.addAttribute("userList", userService.selectUserList());
        return "user-list";
    }

    /**
     * 根据主键查询
     */
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable Integer id, Model model) {
        model.addAttribute("user", userService.selectUserById(id));
        return "updateUser";
    }
    /**
     * 修改用户保存
     * 修改之前需要先根据ID查询
     */
    @PostMapping("/updateUser")
    public String updateUser(User user) {
        userService.updateUser(user);
        return "success";
    }

    /**
     * 删除用户
     */
    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable Integer id) {
        userService.deleteUser(id);
        return "success";
    }

}


视图层

templates/register.html




    
    注册用户


    
姓名:
年龄:

templates/success.html




    
    提示


    成功



启动类

App.java

@SpringBootApplication
@MapperScan("com.springboot.mapper")
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

结果

页面请求

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第6张图片
image.png

数据库

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第7张图片
image.png

1.2查询用户

视图层

templates/user-list.html




    
    用户列表


    
ID NAME AGE 操作
修改 删除

结果

查询所有用户

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第8张图片
image.png

根据主键查询用户

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第9张图片
image.png

1.3修改用户

视图层

templates/updateUser.html




    
    修改用户


    
姓名:
年龄:

结果

查询用户,并填写修改信息

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第10张图片
image.png

数据库

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第11张图片
image.png

1.4删除用户

结果

查询用户列表

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第12张图片
image.png

数据库

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第13张图片
image.png

Spring Boot****服务端数据校验

项目中使用较多的是前端的校验,比如页面中js校验。对于安全较高的建议在服务端进行校验。

校验框架

Spring 使用 Hibernate 的校验框架 validator,页面提交的请求参数,请求到 controller 方法中,使用 validator 进行校验,如果校验不通过,将错误信息展示到页面。

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第14张图片
image.png

主要使用到以下相关 jar 包(蓝色部分)


Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第15张图片
image.png
1.数据校验

创建项目

使用 IntelliJ IDEA 2019.1 直接创建Spring Boot项目

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第16张图片
image.png

目前最新的稳定版 Spring Boot 是2.1.7,我们课程中使用的2.1.6,所以需要修改一下pom.xml的版本信息。在创建项目时勾选 Web 和 Themeleaf 组件。

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第17张图片
image.png
Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第18张图片
image.png

pom.xml


        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    com.springboot
    springboot-validator
    0.0.1-SNAPSHOT
    springboot-validator
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

编写添加用户功能

实体类

User.java

package com.springboot.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;

private String username;

private String password;

private Integer age;

private String email;
public Integer getId() {

return id;

}
public void setId(Integer id) {

this.id = id;

}



public String getUsername() {

return username;

    }



public void setUsername(String username) {

    this.username = username;

    }


public String getPassword() {

    return password;

    }



public void setPassword(String password) {

    this.password = password;

    }



    public Integer getAge() {

    return age;
 
    }

    

    public void setAge(Integer age) {

    this.age = age;

    }

    

    public String getEmail() {

    return email;

    }

    

    public void setEmail(String email) {

    this.email = email;

    }



    @Override

    public String toString() {

    return "User{" +

    "id=" + id +
    ", username='" + username + '\'' +
    ", password='" + password + '\'' +
    ", age=" + age +
    ", email='" + email + '\'' +
    '}';

    }   
}


控制层

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {
/**
* 页面跳转
* *
@param page
* @return
*/
@RequestMapping("/{page}")
public String page(@PathVariable String page) {
return page;
} /
**
* 添加用户
* *
@param user
* @param model
* @return
*/
@PostMapping("/insertUser")
public String insertUser(User user, Model model) {
model.addAttribute("user", user);
return "success";
}
}

视图层

templates/register.html

用戶注冊頁面





添加用户


姓名:
密码:
年龄:
邮箱:

templates/success.html

注册成功页面,返回user





提示






启动类

App.java

准备好项目后,启动项目测试无误,准备开始数据校验.

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第19张图片
image.png

2.数据校验步骤

实体类添加校验规则

User.java

public class User implements Serializable {

    private Integer id;
    @NotEmpty(message = "用户名不可以为空", groups = {ValidateGroupForName.class, ValidateGroupForAll.class})// 非空校验不会去除前后空格
    private String username;
    @NotBlank(message = "密码不可以为空", groups = {ValidateGroupForAll.class})// 非空校验会去除前后空格
    @Size(message = "且长度在6 ~ 10之间", min = 6, max = 10, groups = {ValidateGroupForAll.class})// 长度必须在6~10之间
    private String password;
    // 校验是否为数字,并且在规定的大小值内
    @Max(message = "年龄必须在1 ~ 150岁之间", value = 150, groups = {ValidateGroupForAll.class})// 必须小于等于指定的值
    @Min(message = "年龄必须在1 ~ 150岁之间", value = 1, groups = {ValidateGroupForAll.class})// 必须大于等于指定的值
    private Integer age;
    // 校验邮箱格式,默认正则匹配规则是 ".*"
    @Email(message = "请输入正确的邮箱格式:[email protected]", regexp = "[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\\.[a-za-z]{2,4}",
            groups = {ValidateGroupForAll.class})
    private String email;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
    
}

控制层开启校验

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {

    /**
     * 页面跳转
     *
     * @param page
     * @return
     */
    @RequestMapping("/{page}")
    public String page(@PathVariable String page, User user) {
        return page;
    }

    /**
     * 添加用户
     *
     * @param user  @Validated:表示对哪个参数进行校验
     *              BindingResult:接收校验提示信息
     *              @Validated 和 BindingResult 是配对出现,并且形参顺序是固定的
     * @param model
     * @return
     */
    @PostMapping("/insertUser")
    public String insertUser(@Validated(value = {ValidateGroupForAll.class}) User user, BindingResult bindingResult, Model model) {
        model.addAttribute("user", user);
        if (bindingResult.hasErrors()) {
            List errors = bindingResult.getAllErrors();
            for (ObjectError error: errors) {
                System.out.println(error.getDefaultMessage());// 错误信息
            }
        }
        return bindingResult.hasErrors() ? "register" : "success";
    }

    /**
     * 用户登录。只校验用户名
     * @param user
     * @param bindingResult
     * @return
     */
    @PostMapping("/login")
    public String login(@Validated(value = {ValidateGroupForName.class}) User user, BindingResult bindingResult) {
        return bindingResult.hasErrors() ? "login" : "success";
    }

}

视图层获取提示信息

templates/register.html




    
    添加用户


姓名:
密码:
年龄:
邮箱:

*运行发生异常

org.thymeleaf.exceptions.TemplateProcessingException: Error during
execution of processor
'org.thymeleaf.spring5.processor.SpringErrorsTagProcessor' (template:
"register" - line 10, col 27)
at
org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(Ab
stractAttributeTagProcessor.java:117) ~[thymeleaf-
3.0.11.RELEASE.jar:3.0.11.RELEASE]

解决数据校验异常

方法一

在跳转页面的方法中注入一个对象,要求对象参数的变量名必须是类名的全称且首字母小写(小驼峰)。

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {
/**
* 页面跳转
* *
@param page
* @return
*/
@RequestMapping("/{page}")
public String page(@PathVariable String page, User user) {
return page;
} /
**
* 添加用户
* *
@param user @Validated:表示对哪个参数进行校验
* BindingResult:接收校验提示信息
* @Validated 和 BindingResult 是配对出现,并且形参顺序是固定的
* @param model
* @return
*/
@PostMapping("/insertUser")
public String insertUser(@Validated User user, BindingResult
bindingResult, Model model) {
return bindingResult.hasErrors() ? "register" : "success";
}
}

然后页面使用该变量名获取校验提示信息

templates/register.html





添加用户


姓名:
密码:
年龄:
邮箱:

方法二

使用 @ModelAttribute 注解,并且可以改变页面获取校验信息参数名称。

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {
/**
* 页面跳转
* *
@param page
* @return
*/
@RequestMapping("/{page}")
public String page(@PathVariable String page, @ModelAttribute("u") User
user) {
return page;
} /
**
* 添加用户
* *
@param user @Validated:表示对哪个参数进行校验
* BindingResult:接收校验提示信息
* @Validated 和 BindingResult 是配对出现,并且形参顺序是固定的
* @param model
* @return
*/
@PostMapping("/insertUser")
public String insertUser(@ModelAttribute("u") @Validated User user,
BindingResult bindingResult, Model model) {
return bindingResult.hasErrors() ? "register" : "success";
}
}

页面使用 u 获取校验提示信息

templates/register.html





添加用户


姓名:
密码:
年龄:
邮箱:

运行结果

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第20张图片
image.png

自定义校验提示信息

我们可以通过 message 属性来自定义校验提示信息。

结果


Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第21张图片
image.png

3.分组校验

当需要不同的方法对同一个对象进行校验,但是每个方法需要不同的校验时,需要将校验规则分组。

定义校验分组

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第22张图片
image.png

ValidateGroupForName.java

package com.springboot.group;

public interface ValidateGroupForName {
    // 接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    // 此分组只校验姓名
}

ValidateGroupForAll.java

package com.springboot.group;

public interface ValidateGroupForAll {
    // 接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    // 此分组校验全部
}

User.java

通过注解配置添加分组

每个方法使用不同的校验分组

此时,添加用户方法根据 ValidateGroupForName 分组校验,只会校验用户名,结果如下。

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第23张图片
image.png
Spring Boot****异常处理

Spring Boot对于异常处理提供了五种处理方式。

创建Spring Boot项目,选择 Web 和 Thymeleaf 组件。

1.默认

[图片上传失败...(image-d5c852-1566671305409)]

Spring Boot默认的处理异常的机制是:一旦程序中出现了异常Spring Boot会向 /error 的 url 发送请求。在Spring Boot中提供了一个叫 BasicExceptionController 来处理 /error 请求,然后跳转到默认显示异常的页面来展示异常信息。

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第24张图片
image.png

如果我们需要将所有的异常统一跳转到错误页面显式,需要在 src/main/resources/templates 目录下创建error.html 页面,Spring Boot会自动找到该页面作为错误页面。注意:名称必须叫 error

Spring Boot错误视图提供了以下错误属性:

  • timestamp:错误发生时间;
  • status:HTTP状态码;
  • error:错误原因;
  • exception:异常的类名;
  • message:异常消息(如果这个错误是由异常引起的);
  • errors:BindingResult异常里的各种错误(如果这个错误是由异常引起的);
  • trace:异常跟踪信息(如果这个错误是由异常引起的);
  • path:错误发生时请求的URL路径。

Spring Boot使用的前端框架模板不同,页面的名称也有所不同:

实现Spring的View接口的Bean,其ID需要设置为error(由Spring的BeanNameViewResolver所解析);

  • 如果配置了Thymeleaf,则需命名为error.html的Thymeleaf模板;
  • 如果配置了FreeMarker,则需命名为error.ftl的FreeMarker模板;
  • 如果配置了Velocity,则需命名为error.vm的Velocity模板;
  • 如果是用JSP视图,则需命名为error.jsp的JSP模板。

Thymeleaf 案例如下:

HelloController.java

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        Integer.parseInt("d");
        return "hello";
    }

}


编写错误跳转页面error.html




    
    错误提示


    

error页面

亲,出错了,请稍后再试!

错误发生时间:

HTTP状态码:

错误原因:

异常的类名:

异常消息:

BindingResult异常里的各种错误:

异常跟踪信息:

错误发生时请求的URL路径:

结果

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第25张图片
image.png
1@ExceptionHandle****注解

@ExceptionHandle 注解可以根据 value 属性声明需要捕获哪些异常,然后声明一个自定义方法, Spring Boot会将产生的异常对象注入到方法中供我们使用,该方法需要返回 ModelAndView 封装异常信息,指定跳转视图。

案例如下:

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/show")
public String show() {
Integer.parseInt("D");
return "index";
} 
@RequestMapping("/info")
public String info() {
int i = 2 / 0;
return "index";
} /
**
* @ExceptionHandler(value = {}):捕获哪些异常
* ModelAndView:封装异常信息,指定跳转视图
* Exception ex:将产生的异常对象注入到方法中
* @param ex
* @return
*/
@ExceptionHandler(value = {NumberFormatException.class})
public ModelAndView numberFormatExceptionHandler(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("error", ex.toString());
mv.setViewName("numberFormatException");
return mv;
} /
**
* @ExceptionHandler(value = {}):捕获哪些异常
* ModelAndView:封装异常信息,指定跳转视图
* Exception ex:将产生的异常对象注入到方法中
* @param ex
* @return
*/
@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("error", ex.toString());
mv.setViewName("arithmeticException");
return mv;
}
}

numberFormatException.html

数字转换异常跳转页面




    
    类型转换异常


    



arithmeticException.html

运算异常跳转页面




    
    算数运算异常


    



结果:

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第26张图片
image.png
2.@ControllerAdvice****注解
Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第27张图片
image.png

@ExceptionHandle 注解单独使用时需要借助自定义方法实现,如果多个类中都会有相同的异常出现,那么就需要声明多次,造成代码冗余,此时我们可以借助 @ControllerAdvice 注解实现代码重复利用

通过 @ControllerAdvice 注解声明一个全局异常处理类,然后配合 @ExceptionHandle 注解实现异常处理。

[图片上传失败...(image-4151fd-1566671305409)]

案例如下:

GlobalException.java

/**
* 全局异常处理类
*/
@ControllerAdvice
public class GlobalException {
/**
* @ExceptionHandler(value = {}):捕获哪些异常
* ModelAndView:封装异常信息,指定跳转视图
* Exception ex:将产生的异常对象注入到方法中
* @param ex
* @return
*/
@ExceptionHandler(value = {NumberFormatException.class})
public ModelAndView numberFormatExceptionHandler(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("error", ex.toString());
mv.setViewName("numberFormatException");
return mv;
} /
**
* @ExceptionHandler(value = {}):捕获哪些异常
* ModelAndView:封装异常信息,指定跳转视图
* Exception ex:将产生的异常对象注入到方法中
* @param ex
* @return
*/
@ExceptionHandler(value = {ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("error", ex.toString());
mv.setViewName("arithmeticException");
return mv;
}
}

numberFormatException.html

arithmeticException.html

将UserController中的捕获异常声明删除

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/show")
    public String show() {
        Integer.parseInt("D");
        return "index";
    }

    @RequestMapping("/info")
    public String info() {
        int i = 2 / 0;
        return "index";
    }

}

结果:

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第28张图片
image.png
3.SimpleMappingExceptionResolver

我们可以在全局异常处理类中使用 @Bean 注解注入 SimpleMappingExceptionResolver 实现异常处理。

这种对异常的处理只是定义了异常与视图映射的信息,无法给页面返回太多异常信息。

案例如下:

GlobalException.java

/**
* 全局异常处理类
*/
@Configuration
public class GlobalException {
@Bean
public SimpleMappingExceptionResolver
getSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new
SimpleMappingExceptionResolver();
Properties mappings = new Properties();
/**
* 参数一:异常的类型,注意必须是异常类型的全名
* 参数二:视图名称
*/
mappings.put(ArithmeticException.class.getSimpleName(),
"arithmeticException");
mappings.put(NumberFormatException.class.getSimpleName(),
"numberFormatException");
// 设置异常与视图映射信息
resolver.setExceptionMappings(mappings);
return resolver;
}
}

numberFormatException.html

arithmeticException.html

结果:

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第29张图片
image.png
4.HandlerExceptionResolver

我们可以在全局异常处理类中实现 HandlerExceptionResolver 接口实现异常处理。

案例如下:

GlobalException.java

/**
 * 全局异常处理类
 */
@Configuration
public class GlobalException implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler, Exception ex) {
        ModelAndView mv = new ModelAndView();
        // 判断异常类型,做不同视图跳转
        if(ex instanceof ArithmeticException){
            mv.setViewName("arithmeticException");
        }
        if(ex instanceof NumberFormatException){
            mv.setViewName("numberFormatException");
        }
        mv.addObject("error", ex.toString());
        return mv;
    }


numberFormatException.html

arithmeticException.html

结果:

Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第30张图片
image.png
Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02_第31张图片
image.png

你可能感兴趣的:(Spring Boot整合视图层,持久层,服务校验数据,异常处理-----F02)