SpringMVC 教程 - Handler Method

来源:https://www.cnblogs.com/hitandrew/archive/2018/04/29/8971918.html
-Advertisement-
Play Games

原文鏈接:https://www.codemore.top/cates/Backend/post/2018-04-21/spring-mvc-handler-methods 由註解@RequestMapping註解修飾的處理請求的函數的簽名非常的靈活,可以使用controller函數支持的一系列參數 ...


原文鏈接:https://www.codemore.top/cates/Backend/post/2018-04-21/spring-mvc-handler-methods

由註解@RequestMapping註解修飾的處理請求的函數的簽名非常的靈活,可以使用controller函數支持的一系列參數和返回值。

函數參數

下列表格列出了controller方法可以接受的參數,稍後會對其進行詳細的解釋。 對於 JDK 8的java.util.Optional 可以在包含required屬性的註解中使用,例如:@RequestParam,@RequestHeader等,相當於required=false

函數參數解釋
WebRequest,NativeWebRequest 無需直接使用Servlet API來訪問請求參數,請求屬性和session的屬性。
javax.servlet.ServletRequest,javax.servlet.ServletResponse 可以是指定的請求和響應類型例如ServletRequestHttpServletRequest,也可以是Spring的MultipartRequest,MultipartHttpServletRequest
HttpSession 參數永不為null,訪問session非線程安全,如果多個請求訪問一個session,需要設置RequestMappingHandlerAdaptersynchronizeOnSession為true。
PushBuilder Servlet 4.0 支持HTTP/2 push的API,如果客戶端不支持則為null
Principal 當前授權用戶。
HttpMethod 請求的HTTP方法
Locale 當前請求的區域,由LocaleResolver解析
TimeZone,ZoneId LocaleContextResolver解析的當前請求的時區
InputStream,Reader 訪問由Servlet API暴露的請求體
OutputStream,Writer 訪問由Servlet API 暴露的響應體
@PathVairable 訪問URI變數
@MatrixVariable 訪問URI中的name-value值。例如 pets/42;q=11 @MatrixVariable int q
@Requestparam 訪問請求中參數
@RequestHeader 訪問請求頭
@CookieValue 訪問cookie值
@RequestBody 訪問請求體,將請求體轉換為相應類型
HttpEntity<B> 訪問請求頭和請求體
Map,Model,ModelMap 訪問會在渲染模板時使用的變數。
RedirectAttributes 重定向時使用的屬性
@ModelAttribute 訪問model中的屬性,同時進行數據綁定和校驗
Errors, BindingResult 訪問在數據綁定和校驗是出現的錯誤。

類級別的 @SessionAttributes,SessionStatus | 在不同的請求中存儲session UriComponentsBuilder | 相對於當前請求的host,port,scheme等 @SessionAttribute | 訪問session中的屬性 @RequestAttribute| 訪問請求的屬性。 其他類型 | 如果參數非上述類型,那麼將當成@RequestParam來處理

返回值

下列表格列出了支持的返回類型

返回值類型解釋
@ResponseBody 返回值由HttpMessageConverters轉換,直接寫到響應體
HttpEntity<B>ResponseEntity<B> 返回值包括,http header和body
HttpHeaders 只返回HTTP header
String ViewResolver解析出具體的模板渲染。
View 返回具體的視圖
Map,Model model包含的屬性,視圖由RequestToViewNameTranslator解析
@ModelAttribute 返回添加到Model的屬性,視圖由RequestToViewNameTranslator解析.
ModelAndView 返回具體視圖和添加的model
void 返回void,則Spring MVC會認為Controller內部已經處理好響應內容了。
DeferredResult<V> 非同步返回結果,可以由任意線程處理
Callback<V> 非同步返回,現成由Spring MVC管理
ListenableFuture<V>,CompletionStage<V>,CompletableFuture<V> DefferedResult
ResponseBodyEmitter,SseEmitter 使用HttpMessageConverter非同步將對象以流的方式發到響應。
StreamingResponseBody 非同步將響應發送的輸出流
Reactor, RxJava, 等Reactive類型 DeferredResult
其他類型 如果不返回以上類型,預設當作視圖名稱處理。
類型轉換

一些需要參數的註解,例如@RequestParam,@RequestHeader,@PathVariabl,@MatrixVariable@CookieValue,如果他麽的參數並非String,那麼久需要進行類型轉換。 類型轉換自動由Spring MVC中註冊的轉換器來進行轉換,預設情況下支持,int,long,Date等簡單類型。對於不支持的類型可以通過WebDataBinder或者由FormattingConversionService註冊的Formatter來進行轉換。

Matrix 變數

RFC 3986規定了在路徑中添加name-value對。在Spring MVC中,將其定義為matrix變數。 Matrix變數可以出現在任意的路徑中,每個變數由分號隔開,多個值由逗號隔開,例如:/cars;color=red,green;year=2012。多個值同樣可也可是通過分離名字來指定,例如:color=red;color=green。 如果想要在路徑中添加Matrix變數,那麼就必須保證相應的controller方法包含接收matrix變數,並且請求映射不收到Matrix變數的影響。例如:

// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

    // petId == 42
    // q == 11
}

因為所有的路徑都有可能包辦Matrix變數,可以通過指定路徑的形式分辨某個Matrix變數屬於哪個路徑例如:

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
        @MatrixVariable(name="q", pathVar="ownerId") int q1,
        @MatrixVariable(name="q", pathVar="petId") int q2) {

    // q1 == 11
    // q2 == 22
}

Matrix變數可以是可選的,指定預設值.例如:

// GET /pets/42

@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

    // q == 1
}

可以使用MultiValueMap獲取所有的Matrix變數,例如:

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
        @MatrixVariable MultiValueMap<String, String> matrixVars,
        @MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {

    // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
    // petMatrixVars: ["q" : 22, "s" : 23]
}

預設情況下Spring MVC是不啟用Matrix變數的,如果是用Java配置,可以通過配置UrlPathHelperremoveSemicolonContent=false啟用,如果是使用XML配置,可以使用<mvc:annotation-driven enable-matrix=variable="true"/>啟用。

@RequestParam

@RequestParam可以將Servlet請求參數綁定到controller函數中的變數.例如:

@Controller
@RequestMapping("/pets")
public class EditPetForm {

    // ...

    @GetMapping
    public String setupForm(@RequestParam("petId") int petId, Model model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    // ...

}

@RequestParam的變數required 預設情況下是true,如果不希望必須指定某個參數可以設置required=false或者如果使用Java 8 可以使用java.util.Optional。 如果函數的參數非String類型,那麼將會進行自動類型轉換。 如果@RequsetParam修飾的是Map<String,String>或者MultiValueMap<String,String>那麼就會獲取所有的請求參數。

@RequestHeader

@RequestHeader將header的值綁定到controller的方法參數中。 例如一下作為請求header:

Host                    localhost:8080
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language         fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding         gzip,deflate
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive              300

下列代碼就可以獲取Accept-EncodingKeep-Aliveheader

@GetMapping("/demo")
public void handle(
        @RequestHeader("Accept-Encoding") String encoding,
        @RequestHeader("Keep-Alive") long keepAlive) {
    //...
}

同樣,如果參數非String類型,也會自動進行類型轉換,如果修飾的是Map<String,String>,MultiValueMap<String,String>或者HttpHeaders,也是獲取所有的header值

@CookieValue

使用@CookieValue將cookie值綁定到controller的方法參數中 例如以下cookie:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下列代碼即可獲取:

@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
    //...
}

同樣的,如果參數類型非String,會自動進行類型轉換。

@ModelAttribute

使用@ModelAttribute修飾的函數參數可以訪問Model中的屬性,或者其未初始化是初始化。方法參數名和請求參數名相同,model 屬性同樣也可以覆蓋其請求參數,這樣就不需要自己再從請求參數中解析了。例如:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { }

Pet 示例的獲取:

  • 如果Model中存在,則從Model中解析
  • 通過@SessionAttributes獲取
  • 從URI的路徑變數中獲取
  • 通過預設的構造函數獲取
  • 通過和Servlet請求參數相匹配的帶參數的構造函數獲取。參數名由@ConstructorProperties獲取或者位元組碼獲取。

當然一般都是使用Model來填充其值的,另一個選擇使用URI的路徑變數,其值通過註冊的Converter<String,T>轉換。下麵這個例子就是@ModelAttribute修飾的值和路徑匹配,通過Converter<String,Account>進行類型轉換。

@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) {
    // ...
}

獲取了屬性值的實例後就可以開始進行數據綁定了。WebDataBinder類通過匹配Servlet 的請求參數名(查詢參數和form欄位)來將欄位名對應到對象中。當類型轉換完之後填充匹配的欄位。DataBinderValidation將在後面章節詳細描述。 數據綁定是會產生錯誤的,預設情況下會拋出BindException異常,為了在controller的方法中捕獲這個異常,可以在方法參數中加入BindingResult獲取異常。例如:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}

某些情況下只想要訪問屬性之而不需要數據綁定。這種情況下可以將設置@ModelAttribute(binding=false)。例如:

@ModelAttribute
public AccountForm setUpForm() {
    return new AccountForm();
}

@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
    return accountRepository.findOne(accountId);
}

@PostMapping("update")
public String update(@Valid AccountUpdateForm form, BindingResult result,
        @ModelAttribute(binding=false) Account account) {
    // ...
}

添加javax.util.validation.Valid或者Spring的@Validated註解,在數據綁定完成後會自動校驗。例如:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}
@SessionAttributes

@SessionAttributes用於在不同的請求間存儲Servlet session的屬性值。主要是列出需要在接下來的請求訪問的session的值自動的保存到session中。例如:

@Controller
@SessionAttributes("pet")
public class EditPetForm {
    // ...
}

第一次請求後這個帶有pet名字的屬性值將會自動的存到session中。直到另外一個帶有SessionStatus參數的方法將其清除。例如:

@Controller
@SessionAttributes("pet")
public class EditPetForm {

    // ...

    @PostMapping("/pets/{id}")
    public String handle(Pet pet, BindingResult errors, SessionStatus status) {
        if (errors.hasErrors) {
            // ...
        }
            status.setComplete();
            // ...
        }
    }
}
@SessionAttribute

如果想要訪問一個之前存在的session的屬性,可以使用@SessionAttribute訪問。例如:

@RequestMapping("/")
public String handle(@SessionAttribute User user) {
    // ...
}

請他情況下,需要添加或者刪除session的時候,可以通過註入org.springframework.web.context.request.WebRequest或者javax.servlet.http.HttpSession實現Session的管理。

@RequestAttribute

@SessionAttribute相似,@RequestAttribute可以訪問請求之前(例如,Filter,HandlerInterceptor)創建的請求屬性。例如:

@GetMapping("/")
public String handle(@RequestAttribute Client client) {
    // ...
}
重定向屬性值

預設情況下,在重定向url中所有的屬性值都通過URI的模版變數暴露。 例如:

@PostMapping("/files/{path}")
public String upload(...) {
    // ...
    return "redirect:files/{path}";
}
Flash屬性值

Flash屬性值可以保存一個請求的數據使得另一個請求可以使用他的數據。最常用的場景就是重定向,例如:Post/Redirect/Get模式。在重定向之前臨時將Flash屬性保存(一般保存在session中)。這樣在另一個請求中就可以獲取保存值,之後就會被立即刪除。 Spring MVC 通過FlashMapFlashMapManager支持Flash屬性。FlashMap保存值,FlashMapManager用來保存,查詢,管理FlashMap實例。 Flash屬性預設開啟,如果不使用則不會創建HTTP session。對於每個請求來說都有一個input的FlashMap,包含了上一個請求傳遞的屬性和一個output的FlashMap包含需要傳遞的屬性。這兩個FlashMap都可以通過RequestContextUtils中的靜態方法來獲取。 一般來講controller不會直接使用FlashMap。其方法參數RedirectAttributes預設情況下使用flash map存儲需要重定向的數據,保存到output的FlashMap中,重定向後,自動從input的FlashMap中獲取數據添加到Model中。

Multipart

啟用MultipartResolver後,如果POST請求包含了multipart/form-data,則其將會解析請求參數,獲取Multipart。下麵是上次文件的示例:

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name,
            @RequestParam("file") MultipartFile file) {

        if (!file.isEmpty()) {
            byte[] bytes = file.getBytes();
            // store the bytes somewhere
            return "redirect:uploadSuccess";
        }

        return "redirect:uploadFailure";
    }

}

如果使用Servlet 3.0 則可以用javax.servlet.http.Part代替Spring的MultipartFile。 Multipart 的內容同樣可以作為數據綁定的一部分,例如:

class MyForm {

    private String name;

    private MultipartFile file;

    // ...

}

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(MyForm form, BindingResult errors) {

        if (!form.getFile().isEmpty()) {
            byte[] bytes = form.getFile().getBytes();
            // store the bytes somewhere
            return "redirect:uploadSuccess";
        }

        return "redirect:uploadFailure";
    }

}

Multipart請求同樣可以通過非瀏覽器提交,例如:下麵是一個JSON的示例:

POST /someUrl
Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit

{
    "name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...

可以通過@RequestParam來獲取元信息,但是更好的做法是使用@RequestPart來獲取其元信息。例如:

@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
        @RequestPart("file-data") MultipartFile file) {
    // ...
}

@RequestPart可以和javax.validation.Valid或者Spring的@Validated註解一同使用,通過標準的bean驗證來校驗數據的準確性。預設情況下校驗錯誤拋出MethodArgumentNotValidException的異常,會直接返回404的錯誤。同樣可以通過BindingResult來自己處理異常情況。

@RequestBody

使用了@RequestBody的參數通過HttpMessageConverter來將請求體反序列化成一個對象。下麵是使用@RequestBody的示例:

@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
    // ...
}

@RequestBody同樣可以和javax.validation.Valid或者Spring的@Validated註解一同使用。預設拋出的異常是MethodArgumentNotValidException處理方法同@RequestPart

@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
    // ...
}
HttpEntity

HttpEntity的使用和@RequestBody相似,不過他可以同時包含header和body。使用方法如下:

@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
    // ...
}
@ReponseBody

在方法中使用@ResponseBody修飾,則會自動的將返回值通過HttpMessageConverter的轉換寫入到響應體中。 使用方法如下:

@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
    // ...
}

@ResponseBody同樣支持類級別,如果修飾controller類,那麼所有的方法都會繼承這個註解。這個和@RestController一樣,@RestController就是@Controller@RequestBody的組合。

ResponseEntity

ResponseEntity@ResponseBody相似,只是其同時包含了響應的header和body。使用如下:

@PostMapping("/something")
public ResponseEntity<String> handle() {
    // ...
    URI location = ... ;
    return ResponseEntity.created(location).build();
}
Jackson JSON

Spring MVC 內監了對Jackson序列化視圖的支持。在使用ResponseEntity@ResponseBody的時候可以使用@JsonView來啟動序列化的視圖類。使用如下:

public class UserController {

    @GetMapping("/user")
    @JsonView(User.WithoutPasswordView.class)
    public User getUser() {
        return new User("eric", "7!jd#h23");
    }
}

public class User {

    public interface WithoutPasswordView {};
    public interface WithPasswordView extends WithoutPasswordView {};

    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @JsonView(WithoutPasswordView.class)
    public String getUsername() {
        return this.username;
    }

    @JsonView(WithPasswordView.class)
    public String getPassword() {
        return this.password;
    }
}

如果controller的方法返回的是一個字元串的視圖,可以將其放到model中啟用:

@Controller
public class UserController extends AbstractController {

    @GetMapping("/user")
    public String getUser(Model model) {
        model.addAttribute("user", new User("eric", "7!jd#h23"));
        model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
        return "userView";
    }
}
Jackson JSONP

為了開啟@ResponseBodyResonseEntity的JSONP的支持,可以通過定義一個@ControllerAdvice的bean繼承AbstractJsonpResponseBodyAdvice,其預設構造參數就是JSONP的查詢參數,使用如下:

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        super("callback");
    }
}

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

-Advertisement-
Play Games
更多相關文章
  • 在微服務中,我們將系統拆分為很多個服務單元,各單元之間通過服務註冊和訂閱消費的方式進行相互依賴。但是如果有一些服務出現問題了會怎麼樣? 比如說有三個服務(ABC),A調用B,B調用C。由於網路延遲或C本身代碼有問題導致B遲遲得不到回應,這樣B調用C的請求就會被掛起,等待。 在高併發的訪問的情況下,這 ...
  • 重覆提交原因 從提交頁面到成功頁面的跳轉一般採用視圖定位,由於視圖定位是在服務端跳轉的,如果用戶在點擊提交之後再次刷新頁面,會導致重覆提交,資料庫的數據會有重覆。 採用令牌措施 1、在轉賬展示頁面生成一個隨機的令牌號碼,然後放入session和傳參中。 2、跳轉到轉賬的trans.jsp文件,註意傳 ...
  • 簡介 __setitem__:當屬性被以索引方式賦值的時候會調用該方法 __getitem__:一般如果想使用索引訪問元素時,就可以在類中定義這個方法 __delitem__:當使用索引刪除屬性時調用該方法 實例 ~~~~ __Author__ = "Lance " coding = utf 8 c ...
  • 會話跟蹤是一種靈活的機制,雖然HTTP是一種無狀態協議,但會話跟蹤技術使Web上的狀態編程成為可能,目前普遍存在四種會話跟蹤技術:URL重寫、隱藏表單域、Cookie、Session。 1 隱藏表單域 特點 (參數存放)參數是存放在請求實體里的,因此沒有長度限制,但是不支持 GET 請求方法,因為 ...
  • ArrayList 實現原理:由數組實現的。元素有序,允許重覆。 //其中增長長度的方法,可以看到是創建一個新數組,傳入舊數組和新的數組長度。 private void grow(int minCapacity) { // overflow-conscious code int oldCapacit ...
  • At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door ...
  • Given a non negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English. Input Specificat ...
  • 傳遞多個參數的四種方式: 順序傳參:public User selectUser(String name,int deptId); <select id="selectUser" resultType="user">select * from user where user_name=#{0} an ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...