SpringMVC(3)- 校驗框架、SSM整合

Huonly發表於2020-12-08

1 校驗框架

1.1 校驗框架入門

1.1.1 表單校驗的重要性

  • 表單校驗保障了資料有效性、安全性

在這裡插入圖片描述

資料可以隨意輸入,導致錯誤的結果。後端表單校驗的重要性。

1.1.2 表單校驗分類

  • 校驗位置:
    • 客戶端校驗
    • 服務端校驗
  • 校驗內容與對應方式:
    • 格式校驗
      • 客戶端:使用Js技術,利用正規表示式校驗
      • 服務端:使用校驗框架
    • 邏輯校驗
      • 客戶端:使用ajax傳送要校驗的資料,在服務端完成邏輯校驗,返回校驗結果
      • 服務端:接收到完整的請求後,在執行業務操作前,完成邏輯校驗

1.1.3 表單校驗規則

  • 長度:例如使用者名稱長度,評論字元數量
  • 非法字元:例如使用者名稱組成
  • 資料格式:例如Email格式、 IP地址格式
  • 邊界值:例如轉賬金額上限,年齡上下限
  • 重複性:例如使用者名稱是否重複

1.1.4 表單校驗框架

  • JSR(Java Specification Requests):Java 規範提案

    303:提供bean屬性相關校驗規則

  • JSR規範列表

    • 企業應用技術
       Contexts and Dependency Injection for Java (Web Beans 1.0) (JSR 299)
       Dependency Injection for Java 1.0 (JSR 330)@postConstruct, @PreDestroy
       Bean Validation 1.0 (JSR 303)
       Enterprise JavaBeans 3.1 (includes Interceptors 1.1) (JSR 318)
       Java EE Connector Architecture 1.6 (JSR 322)
       Java Persistence 2.0 (JSR 317)
       Common Annotations for the Java Platform 1.1 (JSR 250)
       Java Message Service API 1.1 (JSR 914)
       Java Transaction API (JTA) 1.1 (JSR 907)
       JavaMail 1.4 (JSR 919)
    • Web應用技術
       Java Servlet 3.0 (JSR 315)
       JavaServer Faces 2.0 (JSR 314)
       JavaServer Pages 2.2/Expression Language 2.2 (JSR 245)
       Standard Tag Library for JavaServer Pages (JSTL) 1.2 (JSR 52)
       Debugging Support for Other Languages 1.0 (JSR 45)
       模組化 (JSR 294)
       Swing應用框架 (JSR 296)
       JavaBeans Activation Framework (JAF) 1.1 (JSR 925)
       Streaming API for XML (StAX) 1.0 (JSR 173)
    • 管理與安全技術
       Java Authentication Service Provider Interface for Containers (JSR 196)
       Java Authorization Contract for Containers 1.3 (JSR 115)
       Java EE Application Deployment 1.2 (JSR 88)
       J2EE Management 1.1 (JSR 77)
       Java SE中與Java EE有關的規範
       JCache API (JSR 107)
       Java Memory Model (JSR 133)
       Concurrency Utilitie (JSR 166)
       Java API for XML Processing (JAXP) 1.3 (JSR 206)
       Java Database Connectivity 4.0 (JSR 221)
       Java Management Extensions (JMX) 2.0 (JSR 255)
       Java Portlet API (JSR 286)
  • Web Service技術
     Java Date與Time API (JSR 310)
     Java API for RESTful Web Services (JAX-RS) 1.1 (JSR 311)
     Implementing Enterprise Web Services 1.3 (JSR 109)
     Java API for XML-Based Web Services (JAX-WS) 2.2 (JSR 224)
     Java Architecture for XML Binding (JAXB) 2.2 (JSR 222)
     Web Services Metadata for the Java Platform (JSR 181)
     Java API for XML-Based RPC (JAX-RPC) 1.1 (JSR 101)
     Java APIs for XML Messaging 1.3 (JSR 67)
     Java API for XML Registries (JAXR) 1.0 (JSR 93)

  • JCP(Java Community Process):Java社群

  • Hibernate框架中包含一套獨立的校驗框架hibernate-validator

    匯入座標

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.0.Final</version>
</dependency>

注意:
tomcat7 :搭配hibernate-validator版本5...Final
tomcat8.5↑ :搭配hibernate-validator版本6...Final

1.2 快速使用

1. 開啟校驗

 名稱:@Valid 、 @Validated
 型別:形參註解
 位置:處理器類中的實體類型別的方法形參前方
 作用:設定對當前實體類型別引數進行校驗
 範例:

@RequestMapping(value = "/addemployee")
public String addEmployee(@Valid Employee employee) {
    System.out.println(employee);
}

2.設定校驗規則

 名稱:@NotNull
 型別:屬性註解 等
 位置:實體類屬性上方
 作用:設定當前屬性校驗規則
 範例:
每個校驗規則所攜帶的引數不同,根據校驗規則進行相應的調整
具體的校驗規則檢視對應的校驗框架進行獲取

public class Employee{
    @NotNull(message = "姓名不能為空")
    private String name;//員工姓名
}  

3.獲取錯誤資訊

@RequestMapping(value = "/addemployee")
public String addEmployee(@Valid Employee employee, Errors errors, Model model){
    System.out.println(employee);
    if(errors.hasErrors()){
        for(FieldError error : errors.getFieldErrors()){
            model.addAttribute(error.getField(),error.getDefaultMessage());
        }
        return "addemployee.jsp";
    }
    return "success.jsp";
}  

通過形參Errors獲取校驗結果資料,通過Model介面將資料封裝後傳遞到頁面顯示

<form action="/addemployee" method="post">
    員工姓名:<input type="text" name="name"><span style="color:red">${name}</span><br/>
    員工年齡:<input type="text" name="age"><span style="color:red">${age}</span><br/>
    <input type="submit" value="提交">
</form>

通過形參Errors獲取校驗結果資料,通過Model介面將資料封裝後傳遞到頁面顯示
頁面獲取後臺封裝的校驗結果資訊

1.3 多規則校驗

  • 同一個屬性可以新增多個校驗器
@NotNull(message = "請輸入您的年齡")
@Max(value = 60,message = "年齡最大值不允許超過60歲")
@Min(value = 18,message = "年齡最小值不允許低於18歲")
private Integer age;//員工年齡
  • 3種判定空校驗器的區別
    在這裡插入圖片描述

1.4 巢狀校驗

 名稱:@Valid
 型別:屬性註解
 位置:實體類中的引用型別屬性上方
 作用:設定當前應用型別屬性中的屬性開啟校驗
 範例:

public class Employee {
    //實體類中的引用型別通過標註@Valid註解,設定開啟當前引用型別欄位中的屬性參與校驗
    @Valid
    private Address address;
}

 注意:開啟巢狀校驗後,被校驗物件內部需要新增對應的校驗規則

1.5 分組校驗

  • 同一個模組,根據執行的業務不同,需要校驗的屬性會有不同
    • 新增使用者
    • 修改使用者
  • 對不同種類的屬性進行分組,在校驗時可以指定參與校驗的欄位所屬的組類別
    • 定義組(通用)
    • 為屬性設定所屬組,可以設定多個
    • 開啟組校驗
public interface GroupOne {
}
public String addEmployee(@Validated({GroupOne.class}) Employee employee){
}  
@NotEmpty(message = "姓名不能為空",groups = {GroupOne.class})
private String name;//員工姓名

2 ssm整合

2.1 整合流程簡介

整合步驟分析

SSM(Spring+SpringMVC+MyBatis)

  • Spring

    • 框架基礎
  • MyBatis

    • mysql+druid+pagehelper
  • Spring整合MyBatis

  • junit測試業務層介面

  • SpringMVC

    • rest風格(postman測試請求結果)
    • 資料封裝json(jackson)
  • Spring整合SpringMVC

    • Controller呼叫Service
  • 其他

    • 表現層資料封裝

    • 自定義異常

表結構

在這裡插入圖片描述

​ 最重要的5個步驟

  1. Spring

  2. MyBatis

  3. Spring整合MyBatis

  4. SpringMVC

  5. Spring整合SpringMVC

2.2 專案結構搭建

Part0: 專案基礎結構搭建

  • 建立專案,組織專案結構,建立包

  • 建立表與實體類

  • 建立三層架構對應的模組、介面與實體類,建立關聯關係

  • 資料層介面(代理自動建立實現類)

    • 業務層介面+業務層實現類
    • 表現層類

在這裡插入圖片描述

public interface UserDao {
    public boolean save(User user);  public boolean update(User user);  
    public boolean delete(Integer uuid);  public User get(Integer uuid);
    public List<User> getAll(int page,int size);

    public interface UserService {  
        public boolean save(User user);  public boolean update(User user);
        public boolean delete(Integer uuid);
        public User get(Integer uuid);
        public List<User> getAll(int page, int size);
        /**
        使用者登入
        @param userName 使用者名稱
        @param password 密碼資訊
        @return
        */
        public User login(String userName,String password);
    }

2.3 Spring整合Mybatis(複習)

Part1 : Spring環境配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:context="http://www.springframework.org/schema/context"  xmlns:tx="http://www.springframework.org/schema/tx"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd  http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd  http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--開啟bean註解掃描-->
    <context:component-scan base-package="com.itheima"/>

</beans>

Part1 : Mybatis配置事務

  • MyBatis對映

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.itheima.dao.UserDao">
    
        <!--新增-->
        <insert id="save" parameterType="user">
            insert into user(userName,password,realName,gender,birthday)values(#{userName},#{password},#{realName},#{gender},#{birthday})
        </insert>
    
        <!--刪除-->
        <delete id="delete" parameterType="int">
            delete from user where uuid = #{uuid}
        </delete>
    
        <!--修改-->
        <update id="update" parameterType="user">
            update user set userName=#{userName},password=#{password},realName=#{realName},gender=#{gender},birthday=#{birthday} where uuid=#{uuid}
        </update>
    
        <!--查詢單個-->
        <select id="get" resultType="user" parameterType="int">
            select * from user where uuid = #{uuid}
        </select>
    
        <!--分頁查詢-->
        <select id="getAll" resultType="user">
            select * from user
        </select>
    
        <!--登入-->
        <select id="getByUserNameAndPassword" resultType="user" >
            select * from user where userName=#{userName} and password=#{password}
        </select>
    
    </mapper>
    
  • Mybatis核心配置

    <!--開啟註解式事務-->
    <tx:annotation-driven transaction-manager="txManager"/>
    
    <!--載入properties檔案-->
    <context:property-placeholder location="classpath*:jdbc.properties"/>
    
    <!--資料來源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!--整合mybatis到spring中-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.itheima.domain"/>
        <!--分頁外掛-->
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <prop key="helperDialect">mysql</prop>
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </array>
        </property>
    </bean>
    
    <!--對映掃描-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.itheima.dao"/>
    </bean>
    
    <!--事務管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    

2.4 整合junit

**Part2:**單元測試整合junit

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = "classpath:applicationContext.xml")  
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testDelete(){  
        User user = new User();  userService.delete(3);
    }
}

2.5 Spring整合SpringMVC

**Part3:**SpringMVC

  • web.xml配置

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring-mvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
  • spring-mvc.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <mvc:annotation-driven/>
    
        <context:component-scan base-package="com.itheima.controller"/>
    
    </beans>
    
  • controller層

    @RestController  
    @RequestMapping("/user")  public class UserController {
        @PostMapping
        public boolean save(User user) {  
            System.out.println("save ..." + user);  return true;
        }
        @PostMapping("/login")
        public User login(String userName,String password){  
            System.out.println("login ..." + userName + " ," +password);
            return null;
        }
    }
    

**Part4:**Spring整合SpringMVC

  • web.xml載入Spring環境

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext.xml</param-value>
    </context-param>
    
    <!--啟動伺服器時,通過監聽器載入spring執行環境-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
  • Controller呼叫Service

    @RestController
    @RequestMapping("/user")
    public class UserController {
        @Autowired
        private UserService userService;
    
    
        @PostMapping
        public boolean save(User user){
            return userService.save(user);
        }
    }
    

2.6 表現層資料封裝

**Part5-1:**表現層資料封裝

  • 前端接收表現層返回的資料種類
u操作是否成功true/false格式A
u單個資料1,100,true格式B
u物件資料json物件格式C
u集合資料json陣列格式D

在這裡插入圖片描述

  • 返回資料格式設計

在這裡插入圖片描述

  • 程式碼

    public class Result {
        // 操作結果編碼
        private Integer code;
        // 運算元據結果
        private Object data;
        // 訊息
        private String message;
        public Result(Integer code) {
            this.code = code;
        }
        public Result(Integer code, Object data) {
            this.code = code;
            this.data = data;
        }
    }
    

    狀態碼常量可以根據自己的業務需求設定

    public class Code {
        public static final Integer SAVE_OK = 20011;
        public static final Integer SAVE_ERROR = 20010;
        //其他編碼
    }
    

    controller 呼叫

    @RestController
    public class UserController {
        @Autowired
        private UserService userService;
        @PostMapping
        public Result save(User user){
            boolean flag = userService.save(user);
            return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERROR);
        }
        @GetMapping("/{uuid}")
        public Result get(@PathVariable Integer uuid){
            User user = userService.get(uuid);
            return new Result(null != user ?Code.GET_OK: Code.GET_ERROR,user);
        }
    }
    

2.7 自定義異常

**Part5-2:**自定義異常

  • 設定自定義異常,封裝程式執行過程中出現的問題,便於表現層進行統一的異常攔截並進行處理

    • BusinessException
    • SystemException
  • 自定義異常訊息返回時需要與業務正常執行的訊息按照統一的格式進行處理

定義BusinessException

public class BusinessException extends RuntimeException {
    //自定義異常中封裝對應的錯誤編碼,用於異常處理時獲取對應的操作編碼
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code) {
        this.code = code;
    }

    public BusinessException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause,Integer code) {
        super(message, cause);
        this.code = code;
    }

    public BusinessException(Throwable cause,Integer code) {
        super(cause);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }
}

@GetMapping("/{uuid}")
public Result get(@PathVariable Integer uuid){
    User user = userService.get(uuid);
    //模擬出現異常,使用條件控制,便於測試結果
    if (uuid == 10 ) throw new BusinessException("查詢出錯啦,請重試!",Code.GET_ERROR);
    return new Result(null != user ?Code.GET_OK: Code.GET_ERROR,user);
}

2.8 返回訊息相容異常資訊

@Component
@ControllerAdvice
public class ProjectExceptionAdivce {
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    //對出現異常的情況進行攔截,並將其處理成統一的頁面資料結果格式
    public Result doBusinessException(BusinessException e){
        return new Result(e.getCode(),e.getMessage());
    }
}

3 純註解開發SSM

3.1 用註解替代applicationContext.xml

同前期設定,新增事務註解驅動
@Configuration

//掃描元件,排除SpringMVC對應的bean,等同於<context:component-scan />
@ComponentScan(value = "com.itheima",excludeFilters = {
    @ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Controller.class})})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MyBatisConfig.class})
//等同於<tx:annotation-driven transaction-manager="txManager"/>,匯入的預設名稱為transactionManager
@EnableTransactionManagement
public class SpringConfig {
    //等同於<bean   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    @Bean("transactionManager")
    public DataSourceTransactionManager getDataSourceTxManager(@Autowired DataSource dataSource){
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        //等同於<property name="dataSource" ref="dataSource"/>
        dtm.setDataSource(dataSource);
        return dtm;
    }
}  

3.2 用註解替代spring-mvc.xml

  • 同前期設定,新增@EnableWebMvc註解
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
}
  • EnableWebMvc
  1. 支援ConversionService的配置,可以方便配置自定義型別轉換器
  2. 支援@NumberFormat註解格式化數字型別
  3. 支援@DateTimeFormat註解格式化日期資料,日期包括Date,Calendar,JodaTime(JodaTime要導包)
  4. 支援@Valid的引數校驗(需要匯入JSR-303規範)
    public DataSourceTransactionManager getDataSourceTxManager(@Autowired DataSource dataSource){
    DataSourceTransactionManager dtm = new DataSourceTransactionManager();
    //等同於
    dtm.setDataSource(dataSource);
    return dtm;
    }
    }

## 3.2 用註解替代spring-mvc.xml  

*   同前期設定,新增@EnableWebMvc註解  

  ```java
  @Configuration
  @ComponentScan("com.itheima.controller")
  @EnableWebMvc
  public class SpringMvcConfig implements WebMvcConfigurer {
  }
  • EnableWebMvc
  1. 支援ConversionService的配置,可以方便配置自定義型別轉換器
  2. 支援@NumberFormat註解格式化數字型別
  3. 支援@DateTimeFormat註解格式化日期資料,日期包括Date,Calendar,JodaTime(JodaTime要導包)
  4. 支援@Valid的引數校驗(需要匯入JSR-303規範)
  5. 配合第三方jar包和SpringMVC提供的註解讀寫XML和JSON格式資料

相關文章