1. 程式人生 > >Springmvc知識二細節[email protect

Springmvc知識二細節[email protect

舉例說明

對於@modelattribute註解比較吃力。現在我們先考慮一個問題,關於資料的修改。

假設我們需要修改一個User物件,但是我們規定某一個或者幾個欄位不能修改,我們會利用表單填寫相關資訊,然後提交給後臺,然後 在後臺會new出一個物件,並將表單提交的資料賦值到這個表單的屬性中,然後執行update操作,但是由於有些欄位不能被修改,所以我們在前臺傳遞的物件有些屬性為空,所以在更新的時候,那些不能被修改的欄位就會被預設為空值。
這裡寫圖片描述

解決:1、我們可以利用隱藏域,在使用者進行修改的時候,將對應的不能修改的欄位進行隱藏,這樣的話,可以解決,但是如果對應的欄位的敏感度比較高,例如密碼不適合利用隱藏域進行記錄,這種方法是不合適的。
2、我們可以在資料更新之前,先從資料庫中將使用者資訊給讀取出來,然後將不能修改的欄位重新進行賦值然後更新。

但是如果所不能修改的欄位比較多,我們就會對這個比較麻煩。重複程式碼較多。

引出:
對於上述兩種方式都有對應的缺點,但是對於更新資料比較小的可以使用,所以我們可以利用我們的這個ModelAttribute註解進行處理。
這裡寫圖片描述
注意 這裡的物件不是new出來的,而是從資料庫獲取出來的,這就是ModelAttribute的作用之一。
在沒有利用@ModelAttribute修飾前演示

<!-- POJO類ModelAttributes屬性  -->
     private int id;  
     private String name;
     private int age;
     private String email;
     private String password; // 不能被修改


<!--
            模擬修改操作  前臺頁面
            1.原始資料為 1 tom  12 
[email protected]
12345 2.密碼不能修改 3.表單回顯 ,模擬操作直接在表單填寫對應的屬性值 在使用者修改資料時,有些資料不能修改,所以在修改時我們把這些子段不給顯示, 我們應該是從資料庫中先獲取,然後 利用ModelAttribute註解進行 覆蓋, 會比我們自己手動利用覆蓋的效果高 --> <form action="TestModelArributes" method="post" > <input
type="hidden" name="id" value="1">
name:<input type="text" name="name" value="tom"> age:<input type="text" name="age" value="12" > email:<input type="text" name="eamil" value="[email protected]" > <input type="submit" value="submit"> </form> <!-- 後臺處理 --> @RequestMapping("/TestModelArributes") public String TestModelArributes(User user){ System.out.println("修改:"+user); // 執行更新操作 省略 return SUCCESS; } <!-- 控制檯列印結果 --> 修改:User[id=1, name=tom, age=13, [email protected], password=null]

注意:在這裡我們的原始資料 帶有密碼,但是從前臺到後臺處理的時候,這個密碼由於沒有在表單之中,所以傳過來的POJO 的密碼為空。即利用方法一所造成的。

然後我們在後臺處理中新增加一個方法,注意是被@ModelAttribute修飾的

    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
            Map<String, Object> maps){
        if(id != null){   // id不為空,說明是使用者執行了修改操作
            // 模擬從資料庫中獲取物件 我們是生成的
        User user =new User(1,"tom", 12,"[email protected]", "1234");
        System.out.println("從資料庫中獲取一個物件:"+user );
        maps.put("user", user);
        }   
    }

<!-- 控制檯列印結果 -->

從資料庫中獲取一個物件:User[id=1, name=tom, age=12, [email protected]163.com, password=1234]
修改:User[id=1, name=tom, age=13, [email protected]163.com, password=1234]

當被@ModelAttribute修飾一個方法之後,結果就變成了password有值了,而且也應該注意到,被@ModelAttribute修飾的方法給提前執行了,這就是@ModelAttribute的作用。這樣的話,再做修改操作的話,就能將原始密碼給帶進入修改操作了。為什麼被@ModelAttribute修飾一個方法之後就會有這樣的結果呢?

下面我們抽出主要程式碼進行分析

<!-- 第一種方式 -->
@ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
            Map<String, Object> maps){
        if(id != null){
        User user =new User(1,"tom", 12,"[email protected]", "1234");
        maps.put("user", user);
        }   
    }

    @RequestMapping("/TestModelArributes")
    public String TestModelArributes(User user){
        System.out.println("修改:"+user);
        return SUCCESS;
    }

=============================


    <!--第二種方式 -->
    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
            Map<String, Object> maps){
        if(id != null){
        User user=new User(1,"tom", 12, "1234");
        maps.put("change", user);
        }


        @RequestMapping("/TestModelArributes")
        public String TestModelArributes(@ModelAttribute( value="change") User user){
            System.out.println("修改:"+user);
            return SUCCESS;
        }

注意
1、@ModelAttribute修飾的方法會被Springmvc提前執行,執行在每個目標方法之前。
2、在@ModelAttribute修飾的方法中,【map存入的鍵需要和目標方法入參型別的第一個字母小寫的字串一致】方式一所示,否則的話,在目標的請求引數方法中不能匹配到從資料庫中提取出來的資料,或者就是你也將目標方法的引數用利用註解ModelAttribute修飾且設定value屬性值指向你的map中的鍵名,上述程式碼的第二種方式

分析流程

執行流程:
我們上述程式碼可以分為三個步驟:
1、 執行ModelArribute修飾的方法,從資料庫中取出物件,把物件放到Map 中,鍵為user
2、springmvc 從Map 中取出User 物件 ,並把表單的請求引數賦給該User物件的對應屬性。
3、springmvc 把上述物件傳入到目標方法的引數。

@ModelAttribute原始碼分析流程

原始碼分析流程:對應上面的執行流程。
1、呼叫@ModelAttribute 註解修飾的方法,實際上把@ModelAttribute方法中 Map中的資料放在了implicitModel中。
2、解析請求處理器的目標引數,實際上該目標引數來自於WebDataBinder物件的target屬性。
2.1、建立WebDataBinder物件。
a) 確定objectName屬性:若傳入的attrName屬性值為空”“,則objectName為類名第一個字母小寫。需要注意的是:attrName。如果目標方法的POJO引數屬性使用了@ModelAttribute來修飾,則attrName值即為@ModelAttribute的value屬性值(對應我們的第二種寫法)
b)確定target屬性:在implicitModel 中查詢attrName對應的屬性值,如果存在,進行利用。如果不存在,則驗證當前Handler是否使用了@SessionAttribute進行修飾類。如果使用了@SessionAttribute,則嘗試從HttpSession中獲取attrName所對應的值,若Session中沒有所對應的值,則會丟擲異常。【這也是SessionAttribute與ModelAttribute共同使用時造成的一個常見問題】,如果當前Handler沒有使用@SessionAttribute修飾類,且@SessionAttribute中沒有使用value值指定的key和attrName相匹配,則通過反射機制進行建立POJO 物件。
2.2、Springmvc把表單的請求引數賦值給WebDataBinder 的target對應的屬性。
2.3、Springmvc 會把WebDataBinder的attrName和target給到implicitModel,進而傳遞到request域物件中。
3、把WebDataBinder的target作為引數傳遞給目標方法

POJO入參流程

從而我們也可以得出Springmvc進行傳遞POJO型別作為引數的流程:
1、確定一個key:
1.1、若目標方法的POJO型別的引數沒有使用@ModelAttribute 作為修飾,則key為POJO類名第一個字母的小寫。
1.2、如果使用了@ModelAttribute 來修飾,則key為@ModelAttribute 註解的value屬性值。
2、在implicitModel中查詢key對應的物件,如果存在則作為入參傳入。
2.1、如在@ModelAttribute標記的方法中儲存過,且key值與上述1中key一致,也可以進行獲取(這就是上述程式碼為什麼可以獲取@ModelAttribute修飾的方法中map中的值)
3、若implicitModel 中不存在key對應的物件,則檢查當前Handler是否使用了@SessionAttribute進行修飾類,如果使用了@SessionAttribute,且@SessionAttribute註解的value屬性值中包含了key,則會從HttpSession中來獲取key所對應的value值,若不存在則會丟擲異常。
4、如果當前Handler沒有使用@SessionAttribute修飾類,且@SessionAttribute中value屬性值中不包含key,則通過反射機制進行建立POJO 物件。作為目標的方法引數物件。
5、Springmvc會把key和pojo型別的物件報錯到implicitModel 中,進而儲存到Request中。

使用總結

1、註解在沒有返回值的方法上面
就如上面的例子註解在沒有返回值的方法上面,用在POJO入參上面或者我們可以在這裡設定一些Request域中的物件,在前臺可以直接使用。

@ModelAttribute
    public void getUser(){
            maps.put("name", "zhangsan");
        }

2、註解在有返回值的方法上面,
這裡要用value屬性進行資料儲存,會將返回值儲存在value屬性的值中,可以在前臺直接獲取。

    @ModelAttribute(value="user00")
    public User testModelAttribute(){
        User user =new User(1,"tom00", 12,"[email protected]", "123400");
        return user;
    }

3、在方法引數上使用@ModelAttribute
在方法的引數中使用必須是修飾POJO類,這樣的話,才能從相應的域中獲取資料

@RequestMapping("/TestModelArributes")
        public String TestModelArributes(@ModelAttribute( value="change") User user){
            System.out.println("列印"+user);
            return SUCCESS;
        }

這樣的話,會從implicitModel 隱藏域中查詢此型別物件,就猶如上面分析的傳遞POJO流程,其實這裡的作用只是可以使用change標記我們的user物件。

4、尤其要注意ModelAttribute與SessionAttribute同時使用會產生的異常丟擲,以及原因。

5、一定要理解POJO傳遞引數的流程

對於原始碼分析不理解的建議去看尚矽谷的佟剛的Springmvc教程,本例項就是根據他的視訊寫的筆記。

相關推薦

Springmvc知識細節<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7a57575757573a37151e1f163b0e0e0813180f0e1f">[email&#160;protect

舉例說明 對於@modelattribute註解比較吃力。現在我們先考慮一個問題,關於資料的修改。 假設我們需要修改一個User物件,但是我們規定某一個或者幾個欄位不能修改,我們會利用表單填寫相關資訊,然後提交給後臺,然後 在後臺會new出一個物件,並將表單

springMVC @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9eddf1f3eef1f0fbf0eab3deccfbedf1ebecfdfbb3">[email&#160;protected]

作用: @Component------------------------泛指元件,當元件不好歸類的時候,我們可以使用這個註解進行標註。(Component-------成分; 組分; 零件) @Resource------------------------(資源) @Autowired------

springMVC原始碼分析<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35181875665046465c5a5b744141475c57404150">[email&#160;protected

@SessionAttribute作用於處理器類上,用於在多個請求之間傳遞引數,類似於Session的Attribute,但不完全一樣,一般來說@SessionAttribute設定的引數只用於暫時的傳遞,而不是長期的儲存,長期儲存的資料還是要放到Session中。通過@Se

SpringMVC基礎<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b39ef3e1d6c2c6d6c0c7fbd6d2d7d6c1">[email&#160;protected]a>

1.概述  從Http請求頭中提取指定的某個請求頭.等價於HttpServletRequest.getHeader(String) 2.配置 (1)value(default ""):引數名例如: Accept (2)required(default true):是否請求

SpringMVC基礎<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ad80ede0c2c9c8c1ecd9d9dfc4cfd8d9c8">[email&#160;protected]a>註解&P

在總結@ModelAttribute註解功能配合PUT請求方式使用之前,先來總結一下POJO類作為入參接收form表單POST提交方式提交資料。 POJO類接收引數 總的來說POJO類還是與普通的Java Bean類還是特別的相似的,私有的屬性,需要

SpringMVC(1)<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7954545454392b1c080c1c0a0d29180b1814">[email&#160;protected]a>和

1、@RequestParam 使用@RequestParam接收前段引數比較方便,前端傳參的URL: url = “${ctx}/main/mm/am/edit?Id=${Id}&name=${name}” 後端使用集合來接受引數,靈活性較好,如

springMVC原始碼分析<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="65484825280a010009241111170c07101100">[email&#160;protected]a

這一篇部落格我們簡單的介紹一下ModelAttribute的使用和執行原理。1、首先@ModelAttribute是使用在方法或者上的,當使用在方法上時其作用於本身所在的Controller,在訪問Controller中的所有請求時都會執行到@ModelAttribute所註

shell腳本中的$# $0 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f8dcb8">[email&#160;protected]a> $* $$ $! $?的意義

腳本 $* width 上一個 pre shell int .cn height 轉載自:http://www.cnblogs.com/davygeek/p/5670212.html 今天學寫腳本遇到一些變量不認識,在此做下記錄。 變量 含義 $0 當前腳本的文件

shell中$*與<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b296f2">[email&#160;protected]a>的區別

劃分 位置 一個 這也 差異 獨立 [email protected] 情況 雙引號 $*所有的位置參數,被作為一個單詞 註意:"$*"必須被""引用 [email protected] 與$*同義,但是每個參數都是一個獨立的""引用字串,這就意味著參數

Spring4.0系列<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aa9f87eae9c5c4cec3dec3c5c4cbc6">[email&#160;protected]a>

one window 標識 cto ace ted ada bsp 布爾 這篇文章介紹Spring 4的@Conditional註解。在Spring的早期版本你可以通過以下方法來處理條件問題: 3.1之前的版本,使用Spring Expression Langua

Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email&#160;protected]a>***註解的工作原理

sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="297a595b40474e69685c5d465e405b4c4d">[email&#160;protected]a>註解與自動裝配(轉發)

配置 調用方法 support autowired 信息 ann over 反射機制 test 1 配置文件的方法我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中註入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 se

linux bash Shell特殊變數:Shell $0, $#, $*, <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8aaeca">[email&#160;protected]a>, $?

在linux下配置shell引數說明 前面已經講到,變數名只能包含數字、字母和下劃線,因為某些包含其他字元的變數有特殊含義,這樣的變數被稱為特殊變數。  例如,$ 表示當前Shell程序的ID,即pid,看下面的程式碼: [[email protected] /]$ ec

spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="62000d0d16222103010a0703000e07">[email&#160;protected]a>中value的理解

先看原始碼 /** * Names of the caches in which method invocation results are stored. * <p>Names may be used to determine the target cache (or cac

{<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="733e3c3f3f2a342136363d203323213c273c3d3e323a3f5d303c3e">[email&#160;protecte

近日,復旦解密安全團隊發現GandCrab4.0活躍度提升,跟蹤到多起GandCrab4.0變種勒索事件,現釋出安全預警,提醒廣大使用者預防GandCrab4.0勒索。 目前復旦解密已經可以成功解密GandCrab4.0變種採用RSA+AES加密演算法 mg中毒檔案可以在一個小時解決.電話151691214

Springboot註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="260b0b666549485254494a4a4354">[email&#160;protected]a>和@RestCon

1.使用@Controller 註解,在對應的方法上,檢視解析器可以解析return 的jsp,html頁面,並且跳轉到相應頁面;若返回json等內容到頁面,則需要加@ResponseBody註解 [email protected]註解,相當於@[email protected

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b2c3e391b33">[email&#160;protected]a>,c小總結

問題0:元素內聯元素,行內元素,行內塊元素.         內聯: 寬高M,P都有效         行內元素:無寬高,內容撐開,M,P左右有效  

SQL Server資料庫mdf檔案中了勒索病毒<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc9f8e858c889998a39d8f9d9293bc9f939f97">[email&#160;p

SQL,資料庫,勒索病毒,mdf檔案中毒,[email protected]_email *SQL Server資料庫mdf檔案中了勒索病毒[email protected]_email。副檔名變為[email protected]_email SQL Serv

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5400313a273b2632383b2379142032">[email&#160;protected]a>_export詳解

Tensorflow經常看到定義的函式前面加了“@tf_export”。例如,tensorflow/python/platform/app.py中有: @tf_export('app.run') def run(main=None, argv=None): """Runs the progr

手把手教你搭建React Native 開發環境 - ios篇 (React <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="eda38c99849b88adddc3d8d8c3d9">[email&#

由於之前我是h5的,沒接觸過ios和安卓, 也不瞭解xcode配置,所以 建議學reace-native之前還是先去了解一下ios和安卓開發環境搭建等問題。 環境下載及配置 nodejs:https://nodejs.org/en/download/ 設定淘寶映象 $ npm con