day05-mybatis配置文件和SQL映射文件

来源:https://www.cnblogs.com/liyuelian/archive/2023/02/26/17157746.html
-Advertisement-
Play Games

Mybatis配置文件&SQL映射文件 1.配置文件-mybatis-config.xml 1.1基本說明 mybatis的核心配置文件(mybatis-config.xml),它的作用如配置jdbc連接信息,註冊mapper等,我們需要對這個配置文件有詳細的瞭解。 文檔地址:mybatis – M ...


Mybatis配置文件&SQL映射文件

1.配置文件-mybatis-config.xml

1.1基本說明

mybatis的核心配置文件(mybatis-config.xml),它的作用如配置jdbc連接信息,註冊mapper等,我們需要對這個配置文件有詳細的瞭解。

文檔地址:mybatis – MyBatis 3 | 配置

配置文檔的頂層結構如下:

image-20230225193119860

1.2properties(屬性)

屬性可以在外部進行配置,並可以進行動態替換(使用${})。既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設置。

(1)直接在properties元素的子元素中配置

<dataSource type="POOLED">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?
        useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</dataSource>

(2)在外部配置,進行動態替換

jdbc.properties 屬性文件:

.properties 屬性文件需要統一放在 resource 目錄/類載入路徑

# The key value is arbitrary
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8
jdbc.user=root
jdbc.pwd=123456

mybatis 配置文件:

要先引入 .properties 文件

<configuration>
    <!--引入外部的jdbc.properties-->
    <properties resource="jdbc.properties"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.pwd}"/>
            </dataSource>
</configuration>

1.3settings(設置)

mybatis – MyBatis 3 | 配置

1.4typeAliases(別名處理器)

  1. 別名是Java命名一個短名稱,它只和XML配置有關,用來減少類名重覆的部分
  2. 如果指定了別名,我們的xxMapper.xml文件就可以做相應的簡化處理
  3. 註意指定別名後,還是可以使用全名的
  4. 如果一個包下有很多的類,我們可以直接引入包,這樣該包下麵的所有類名都可以直接使用。
<typeAliases>
    <!--如果一個包下有很多的類,可以直接使用包的方式引入,這樣包下的所有類名都可以直接使用-->
    <package name="com.li.entity"/>
</typeAliases>

1.5typeHandlers(類型處理器)

  1. 用於Java類型和jdbc類型映射
  2. Mybatis的映射基本已經滿足,不太需要重新定義
  3. 這個我們預設即可,也就是mybatis會自動地將java和jdbc類型進行轉換
  4. Java類型和jdbc類型映射關係一覽 mybatis – MyBatis 3 | 配置
image-20230225204211609

1.6environments(環境)

environments 元素定義瞭如何配置環境。

註意一些關鍵點:

  • 預設使用的環境 ID(比如:default="development")。
  • 每個 environment 元素定義的環境 ID(比如:id="development")。
  • 事務管理器的配置(比如:type="JDBC")。
  • 數據源的配置(比如:type="POOLED")。

預設環境和環境 ID 顧名思義。 環境可以隨意命名,但務必保證預設的環境 ID 要匹配其中一個環境 ID。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>

1.7mappers(映射器)

現在就要來定義 SQL 映射語句了。 首先,我們需要告訴 MyBatis 到哪裡去找到這些語句。你可以使用相對於類路徑的資源引用,或完全限定資源定位符(包括 file:/// 形式的 URL),或類名和包名等。

(1)使用相對於類路基的資源引用

<!-- 使用相對於類路徑的資源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

(2)使用完全限定資源定位符(URL),不推薦使用

<!-- 使用完全限定資源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

(3)使用映射器介面實現類的完全限定類名

<!-- 使用映射器介面實現類的完全限定類名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

(4)將包內的映射器介面全部註冊為映射器

<!-- 將包內的映射器介面全部註冊為映射器
   1.當一個包下有很多的xxMapper.xml文件和基於註解實現的介面時,為了方便,可以用包方式進行引用
   2.將下麵的所有xml文件和註解介面都進行註冊-->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

2.SQL映射文件-xxMapper.xml

2.1基本介紹

mybatis – MyBatis 3 | XML 映射器

  1. Mybatis 的真正強大之處在於它的語句映射(在XxxMapper.xml中配置),如果拿它和具有相同功能的 JDBC代碼進行對比,你會發現立即省掉了將近 95% 的代碼。MyBatis 致力於減少使用成本,讓用戶能更專註於SQL 代碼。

  2. SQL映射文件常用的頂級元素(按照應被定義的順序列出):

    • cache - 該命名空間的緩存配置

    • cache-ref - 引用其他命名空間的緩存配置

    • resultMap - 描述如何從資料庫的結果集 中載入對象,是最複雜也是最強大的元素

    • parameterType - 將會傳入這條語句的參數的類全限定名或別名

    • sql - 可被其他語句引用的可重用語句塊

    • insert - 映射插入語句

    • update - 映射更新語句

    • delete - 映射刪除語句

    • select - 映射查詢語句

2.2映射文件詳細說明

2.2.1基本使用

  1. insert,delete,update,select 這些在之前講過,分別對應增刪查改的方法和SQL語句的映射

  2. 如果獲取到剛剛添加的Monster對象的id主鍵(獲取自增長)也講過了

    <insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `monster`
        (`age`,`birthday`,`email`,`gender`,`name`,`salary`)
        VALUES (#{age},#{birthday},#{email},#{gender},#{name},#{salary})
    </insert>
    

2.2.2傳入類型-POJO或String

  1. 當有多個條件時,傳入的參數設為POJO/Entity類型的 Java對象,這樣可以通過 POJO/Entity 對象的屬性來接收傳入的參數
  2. 傳入 POJO/Entity 類型時,如果查詢時需要有多個篩選條件,怎麼在映射文件中處理?一般是使用#{}的方式來獲取入參的多個值(註意#{}內部的名稱對應的是POJO對象的屬性名,和表欄位無關)
  3. 當傳入的參數類型為String時,則使用${}的方式來接收傳入的參數

應用案例

(1)MonsterMapper.java 介面

package com.li.mapper;

import com.li.entity.Monster;

import java.util.List;

/**
 * @author 李
 * @version 1.0
 */
public interface MonsterMapper {
    //通過id或者名字查詢
    public List<Monster> findMonsterByNameOrId(Monster monster);

    //查詢名字中含有‘精’的妖怪
    public List<Monster> findMonsterByName(String name);

}

(2)映射文件MonsterMapper.xml 實現介面方法

<mapper namespace="com.li.mapper.MonsterMapper">
    <!--這裡 #{}的值是從傳入的參數的屬性中獲取的,`id`表示表的欄位名,
		這裡的parameterType可以直接使用類名,是因為在mybatis的配置文件中配置了別名-->
    <select id="findMonsterByNameOrId" parameterType="Monster" resultType="Monster">
        SELECT * FROM `monster` WHERE `id` = #{id} OR `name` = #{name}
    </select>

    <!--當傳入的參數類型為String時,使用${}的方式來接收參數-->
    <select id="findMonsterByName" parameterType="String" resultType="Monster">
        SELECT * FROM `monster` WHERE `name` LIKE '%${name}%'
    </select>
</mapper>

(3)測試

package com.li.mapper;

import com.li.entity.Monster;
import com.li.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

/**
 * @author 李
 * @version 1.0
 */
public class MonsterMapperTest {
    //屬性
    private SqlSession sqlSession;
    private MonsterMapper monsterMapper;

    //初始化
    @Before
    public void init() {
        sqlSession = MybatisUtils.getSqlSession();
        monsterMapper = sqlSession.getMapper(MonsterMapper.class);
        System.out.println("monsterMapper=" + monsterMapper.getClass());
    }

    @Test
    public void findMonsterByNameOrId() {
        Monster monster = new Monster();
        monster.setId(1);
        monster.setName("狐狸精");
        List<Monster> monsters =
                monsterMapper.findMonsterByNameOrId(monster);
        for (Monster m : monsters) {
            System.out.println("m=" + m);
        }
        if (sqlSession != null) {
            sqlSession.close();
        }
        System.out.println("findMonsterByNameOrId() 查詢成功!");
    }

    @Test
    public void findMonsterByName() {
        List<Monster> monsters = monsterMapper.findMonsterByName("精");
        for (Monster monster : monsters) {
            System.out.println("monster=" + monster);
        }
        if (sqlSession != null) {
            sqlSession.close();
        }
        System.out.println("findMonsterByName() 查詢成功!");
    }

}
image-20230226192643013 image-20230226192547388

2.2.3傳入類型-Map

HashMap傳入參數更加靈活,比如可以靈活地增加查詢的屬性,而不受POJO/Entity 類型本身屬性的限制(因為POJO/Entity 類型的屬性數量有限而且#{}中的名稱必須為屬性名)

例子-演示如何遍歷一個List<Map<String,Object>> 的數據類型

(1)修改MonsterMapper.java,增加方法介面

//聲明一個方法,傳入參數是HashMap,查詢 id>10 並且 salary>40 的所有妖怪
public List<Monster> findMonsterByIdAndSalary(Map<String, Object> map);

(2)修改MonsterMapper.xml映射文件,實現該方法

<!--聲明一個方法,傳入參數是HashMap,查詢 id>5 並且 salary>40 的所有妖怪
這裡使用 #{id}和 #{salary} 來獲取入參 map的值時,意味著你的map需要有key為id和salary的鍵值對
事實上,map的 key 只要和 #{}中的 key一樣即可,和表欄位無關-->
<select id="findMonsterByIdAndSalary" parameterType="map" resultType="Monster">
    SELECT * FROM `monster` WHERE `id`>#{id} AND `salary` > #{salary}
</select>

(3)測試

@Test
public void findMonsterByIdAndSalary() {
    Map<String, Object> map = new HashMap<>();
    map.put("id", 5);//這裡設置的key只要和#{key}的key值一樣即可,和表欄位無關
    map.put("salary", 40);
    List<Monster> monsters = monsterMapper.findMonsterByIdAndSalary(map);
    for (Monster monster : monsters) {
        System.out.println("monster=" + monster);
    }
    if (sqlSession != null) {
        sqlSession.close();
    }
    System.out.println("findMonsterByIdAndSalary() 查詢成功!");
}
image-20230226195136351

2.2.4傳入&返回的類型都是Map

(1)修改MonsterMapper.java,增加方法介面

//傳入和返回的類型都是Map
public List<Map<String, Object>> findMonsterByIdAndSalary2(Map<String, Object> map);

(2)修改MonsterMapper.xml映射文件,實現該方法

<!--查詢 id>5 並且 salary>40 的所有妖怪,要求傳入和返回的參數都是Map類型-->
<select id="findMonsterByIdAndSalary2" parameterType="map" resultType="map">
    SELECT * FROM `monster` WHERE `id`>#{id} AND `salary` > #{salary}
</select>

(3)測試

@Test
public void findMonsterByIdAndSalary2() {
    Map<String, Object> map = new HashMap<>();
    map.put("id", 5);
    map.put("salary", 40);
    List<Map<String, Object>> monstersList = monsterMapper.findMonsterByIdAndSalary2(map);
    //取出返回的結果-以map的形式
    for (Map<String, Object> monsterMap : monstersList) {
        System.out.println("monsterMap=" + monsterMap);
        //遍歷monsterMap,取出屬性和對應的值
        for (Map.Entry<String, Object> entry : monsterMap.entrySet()) {
            System.out.println("key=" + entry.getKey() + "=>value=" + entry.getValue());
        }
    }
    if (sqlSession != null) {
        sqlSession.close();
    }
    System.out.println("findMonsterByIdAndSalary2() 查詢成功!");
}
image-20230226201418806

2.2.5resultMap結果集映射

當實體類屬性和表的欄位名字不一樣時,我們可以通過resultMap進行映射,從而屏蔽實體類屬性名和表的欄位不一致可能出現的問題。

例子

(1)表user

-- 創建user表
CREATE TABLE `user`(
  `user_id` INT NOT NULL AUTO_INCREMENT,
  `user_email` VARCHAR(255) DEFAULT '',
  `user_name` VARCHAR(255) DEFAULT '',
  PRIMARY KEY(`user_id`)
)CHARSET=utf8

(2)創建實體類和表映射,這裡故意設置和表欄位不一樣的屬性名

package com.li.entity;

/**
 * @author 李
 * @version 1.0
 */
public class User {
    private Integer userId;
    private String userName;
    private String userEmail;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userEmail='" + userEmail + '\'' +
                '}';
    }
}

(3)創建介面 UserMapper.java

package com.li.mapper;

import com.li.entity.User;

import java.util.List;

/**
 * @author 李
 * @version 1.0
 */
public interface UserMapper {
    //添加
    public void addUser(User user);

    //查詢所有的User
    public List<User> findAllUsers();
}

(4)創建映射文件 UserMapper.xm

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace指定該xml文件和哪個介面對應-->
<mapper namespace="com.li.mapper.UserMapper">
    <!--完成添加用戶的任務,註意這裡的user屬性和表的欄位名不一致
    這裡的parameterType可以直接使用類名,是因為在mybatis的配置文件中配置了別名-->
    <insert id="addUser" parameterType="User">
        INSERT INTO `user`(`user_email`,`user_name`)
        VALUE(#{userEmail},#{userName});
    </insert>

    <!--因為表欄位的名稱和實體類型的名稱不一致
    1.如果對象屬性名和表欄位不一樣是,那麼返回的數據就保存不進去,就會是對象的屬性就是預設值
    2.要解決這個問題,可以使用resultMap來解決這個問題
    3.定義一個resultMap,它的id由你指定id,通過id可以引用這個resultMap
    4.type 為返回的數據類型(可以使用別名)
    5.column為表的欄位,property為對象的屬性名-->
    <resultMap id="findAllUserMap" type="User">
        <!--指定映射關係-->
        <result column="user_email" property="userEmail"/>
        <result column="user_name" property="userName"/>
    </resultMap>
    <select id="findAllUsers" resultMap="findAllUserMap">
        SELECT * FROM `user`
    </select>
</mapper>

(5)測試

package com.li.mapper;

import com.li.entity.User;
import com.li.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

/**
 * @author 李
 * @version 1.0
 */
public class UserMapperTest {
    //屬性
    private SqlSession sqlSession;
    private UserMapper userMapper;

    //初始化
    @Before
    public void init() {
        sqlSession = MybatisUtils.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void addUser(){
        User user = new User();
        user.setUserName("marry");
        user.setUserEmail("[email protected]");
        userMapper.addUser(user);
        if (sqlSession != null) {
            //需要手動提交事務,因為mybatis事務預設為false
            sqlSession.commit();
            sqlSession.close();
        }
        System.out.println("插入成功!");
    }

    @Test
    public void findAllUsers(){
        List<User> allUsers = userMapper.findAllUsers();
        for (User user : allUsers) {
            System.out.println("user="+user);
        }
        if (sqlSession != null) {
            sqlSession.close();
        }
        System.out.println("查詢成功!");
    }
}
image-20230226204123634 image-20230226205647442

resultMap註意事項和細節

  1. 除了使用resultMap,也可以使用欄位別名解決表欄位和對象屬性不一致的問題,但是它的復用性不好,因此不推薦使用欄位別名

    image-20230226210804693
  2. 如果是MyBatis-Plus處理就比較簡單,可以使用@TableField來解決實體欄位名和表欄位名不一致的問題,還可以使用@TableName來解決實體類名和表名不一致的問題。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 需求:我們現在需要寫一個 foo 函數,這個函數返迴首次調用時的 Date 對象,註意是首次。 使用場景:當我們每次都需要進行條件判斷,其實只需要判斷一次,接下來的使用方式都不會發生改變的時候,想想是否可以考慮使用惰性函數。 惰性函數:顧名思義,有點懶惰,懶到事件只處理一次,當然不是值整個函數 ...
  • 本章將繼續和大家分享Vue的一些基礎知識。話不多說,下麵我們直接上代碼: 本文內容大部分摘自Vue的官網:https://v2.cn.vuejs.org/v2/guide/ 首先我們先來看一下Demo的目錄結構,如下所示: 一、偵聽器 <!DOCTYPE html> <html lang="en"> ...
  • 在ES6中新增了一個很重要的特性: class(類)。作為一個在2015年就出了的特性, 相信很多小伙伴對class並不陌生。但是在日常開發中使用class的頻率感覺並不高(可能僅限於作者),感覺對class總有種一知半解的感覺。今天就帶著小伙伴們一起,好好剖析剖析這個特性。 1.什麼是class ...
  • ———————————————— 版權聲明:本文為CSDN博主「LW0512」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/LW0512/article/details/120287699 ...
  • 常用API API概述 API全稱是應用程式編程介面,是Java寫好的程式,程式員可以直接調用。 Object類:toString方法 Object是祖宗類,它裡面的方法,一切子類對象都可以使用。 public String toString() 預設是返回當前對象的地址信息。 Student s ...
  • 跨平臺開發框架是客戶端領域的經典課題,幾乎從操作系統誕生開始就是我們軟體從業者們的思考命題。為了促進 Flutter 在 4 個端的成熟,企業微信研發團隊也和 Google 團隊針對電腦端 Flutter 穩定版的落地做了多輪技術溝通。終於在近期的版本實現同一個功能跨平臺 4 端同步上線。企業微信每... ...
  • 1. 緩衝I/O 1.1. 對於文件和套接字,壓縮和字元串編碼的操作,必須適當地對I/O進行緩衝 1.1.1. 兩個流操作的是位元組塊(來自緩衝流)而不是一系列的單位元組(來自ObjectOutputStream),它們會運行得更好 1.2. InputStream.read() 1.3. Output ...
  • 前言 ​ 經常在網上看到一些博客,介紹高併發。由於我們在實際開發過程遇到高併發的場景非常少,一直覺得很高大上, 那我們通過CPU,操作系統,和JDK 等方面揭開高併發的''神秘面紗''。 1: 什麼時候發生併發 ​ 在電腦中,CPU執行程式指令的。那我們看下下麵這個圖 思考: 當兩個程式在不同的C ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...