Spring @ModelAttribute注解用法

之前項(xiàng)目中并自己并沒有怎么使用到過@ModelAttribute這個(gè)注解,接手一個(gè)老項(xiàng)目的時(shí)候發(fā)現(xiàn)項(xiàng)目中大量使用@ModelAttribute這個(gè)注解,在這里就整理下這個(gè)注解常用的方式,也為自己做個(gè)記錄,以免久了不用又忘記了
@ModelAttribute使用大致有有兩種,一種是是直接標(biāo)記在方法上,一種是標(biāo)記在方法的參數(shù)中,兩種標(biāo)記方法產(chǎn)生的效果也各不相同,這里就列舉下兩種標(biāo)記所產(chǎn)生的效果

首先先做點(diǎn)簡單的準(zhǔn)備工作,寫一個(gè)只包含一個(gè)button的jsp頁面,這里可以看見,只是寫了個(gè)簡單按鈕事件,跳轉(zhuǎn)的modelTest.do這個(gè)路徑

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
    <script type="text/javascript" src="<%=basePath%>static/js/jquery.min.js"></script>
  </head>
  <script type="text/javascript">
        $(function(){
            $("#modelTest").on("click",function(){
                
                window.location.href="<%=basePath%>model/modelTest.do";
            })
        });
  </script>
  <body>
  
    <input type="button" id="modelTest" value="測(cè)試">
 
    
  </body>
</html>

注解標(biāo)記在方法上

下面,再讓我們寫一個(gè)controller控制器,這里我們?cè)倏刂破髦袑憙蓚€(gè)方法,其中一個(gè)使用@RequestMapping方法路徑標(biāo)記為modelTest.do,另外一個(gè)方法不標(biāo)記路徑,使用@ModelAttribute標(biāo)記

package com.lovo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @ModelAttribute
    public void init()
    {
        System.out.println("最先執(zhí)行的方法");
    }
    
    @ModelAttribute
    public void init02()
    {
        System.out.println("最先執(zhí)行的方法02");
    }
    
    @RequestMapping(value="modelTest.do")
    public String modelTest()
    {
        System.out.println("然后執(zhí)行的方法");
        return "modelTest";
    }
    
    @ModelAttribute
    public void init03()
    {
        System.out.println("最先執(zhí)行的方法03");
    }
}


部署后運(yùn)行,點(diǎn)擊頁面測(cè)試按鈕,查看控制臺(tái)輸出,這個(gè)時(shí)候你會(huì)發(fā)現(xiàn),后臺(tái)控制器并沒有直接進(jìn)入modelTest.do的路徑,而是先執(zhí)行了被@ModelAttribute標(biāo)記的init方法。應(yīng)該這么理解,當(dāng)同一個(gè)controller中有任意一個(gè)方法被@ModelAttribute注解標(biāo)記,頁面請(qǐng)求只要進(jìn)入這個(gè)控制器,不管請(qǐng)求那個(gè)方法,均會(huì)先執(zhí)行被@ModelAttribute標(biāo)記的方法,所以我們可以用@ModelAttribute注解的方法做一些初始化操作。當(dāng)同一個(gè)controller中有多個(gè)方法被@ModelAttribute注解標(biāo)記,所有被@ModelAttribute標(biāo)記的方法均會(huì)被執(zhí)行,按先后順序執(zhí)行,然后再進(jìn)入請(qǐng)求的方法。

image.png

下面方法做一些變形,變形為帶有參數(shù)的返回,這樣也是實(shí)際開發(fā)中經(jīng)常會(huì)操作的
首先像創(chuàng)建個(gè)pojo對(duì)象,對(duì)象包含userName,sex兩個(gè)屬性。并對(duì)JSP及控制器代碼做一些修改

頁面使用EL表達(dá)式接受返回參數(shù)

 <script type="text/javascript">
        $(function(){
            $("#modelTest").on("click",function(){
                
                window.location.href="<%=basePath%>model/modelTest.do";
            })
        });
  </script>
  <body>
  
    <input type="button" id="modelTest" value="測(cè)試">
 
    <input type="text" value="${pojo.userName }">
    <input type="text" value="${pojo.sex }">
    
  </body>

@ModelAtterbute方法無返回值情況

@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @ModelAttribute
    public void init(Model mode)
    {
        PojoTest pojo=new PojoTest(null, "小明", "男");
        mode.addAttribute("pojo", pojo);
    }

    @RequestMapping(value="modelTest.do")
    public String modelTest()
    {
        return "modelTest";
    }

}

訪問ModelTest.jsp頁面并點(diǎn)擊測(cè)試

image.png

出現(xiàn)如下結(jié)果

image.png

從執(zhí)行結(jié)果看出,當(dāng)訪問請(qǐng)求時(shí),會(huì)首先訪問init方法,然后再對(duì)test方法進(jìn)行訪問,并且是同一個(gè)請(qǐng)求,因?yàn)閙odel模型數(shù)據(jù)的作用域與request相同,所以可以用此標(biāo)記直接標(biāo)記在方法上對(duì)實(shí)際要訪問的方法進(jìn)行一些初始化操作

@ModelAttribute標(biāo)記方法有返回值

@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @ModelAttribute
    public String init(Model mode)
    {
        System.out.println("進(jìn)入init方法");
        PojoTest pojo=new PojoTest(null, "小明", "男");
        mode.addAttribute("pojo", pojo);
        return "model/befor.do";
    }
    
    @RequestMapping(value="befor.do")
    public String befor(){
        
        System.out.println("進(jìn)入befor方法");
        return "index";
        
    }

    @RequestMapping(value="modelTest.do")
    public String modelTest()
    {
        System.out.println("進(jìn)入modelTest方法");
        return "modelTest";
    }

}

這里稍微做了點(diǎn)變形,可以看到在被@ModelAttribute方法中設(shè)值了返回路徑為befor方法,但是在在代碼運(yùn)行的過程中并不會(huì)跳轉(zhuǎn)befor方法,而是在代碼執(zhí)行完成return之前直接跳轉(zhuǎn)了實(shí)際請(qǐng)求的方法。

image.png

當(dāng)@RequestMapping標(biāo)記和@ModelAttribute同時(shí)標(biāo)記在一個(gè)方法上

@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @RequestMapping(value="modelTest.do")
    @ModelAttribute(value="pojo")
    public String modelTest()
    {
        System.out.println("進(jìn)入modelTest方法");
        
        return "modelTest";
    }

}

點(diǎn)擊測(cè)試頁面發(fā)現(xiàn)進(jìn)入控制器后返回,頁面報(bào)404,這是因?yàn)楫?dāng)兩個(gè)注解標(biāo)記到同一個(gè)方法上時(shí),邏輯視圖名并不是返回值,而是返回請(qǐng)求的路徑,根據(jù)model/modelTest.do生成邏輯視圖。在這里我們修改下代碼,把controller上的@RequestMapping標(biāo)記去掉,并修改下頁面的請(qǐng)求路徑,讓生成的視圖路徑和訪問的頁面路徑相同

@Controller
public class ModelAttributeTest {
    
    @RequestMapping(value="modelTest.do")
    @ModelAttribute(value="pojo")
    public String modelTest()
    {
        System.out.println("進(jìn)入modelTest方法");
        
        return "modelTest";
    }

}
  <script type="text/javascript">
        $(function(){
            $("#modelTest").on("click",function(){
                
                window.location.href="<%=basePath%>modelTest.do";
            })
        });
  </script>
  <body>
  
    <input type="button" id="modelTest" value="測(cè)試">
    
    <input type="text" value="${pojo }">
    
  </body>

點(diǎn)擊測(cè)試頁面,會(huì)發(fā)現(xiàn)當(dāng)兩個(gè)注解同時(shí)注解到一個(gè)方法上時(shí),方法的返回值會(huì)變成model模型的返回值,key是標(biāo)記的名

image.png

@ModelAttribute標(biāo)記在參數(shù)前

從from表單或url地址中取值,這里就以u(píng)rl地址為例,為了避免url地址中文亂碼問題,這里調(diào)用了encodeURL函數(shù)

<script type="text/javascript">
        $(function(){
            $("#modelTest").on("click",function(){
                
                window.location.href="<%=basePath%>model/modelTest.do?userName="+encodeURI('小明')+"&sex="+encodeURI('男');
            })
        });
  </script>
  <body>
  
    <input type="button" id="modelTest" value="測(cè)試">
    <input type="text" value="${pojo.userName }">
    <input type="text" value="${pojo.sex }">
    
  </body>
@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @RequestMapping(value="modelTest.do")
    public String modelTest(@ModelAttribute("pojo") PojoTest pojo) 
    {
        try {
            pojo.setUserName(new String(pojo.getUserName().getBytes("iso-8859-1"),"utf-8"));
            pojo.setSex(new String(pojo.getSex().getBytes("iso-8859-1"),"utf-8"));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(pojo);
        return "modelTest";
    }

}

點(diǎn)擊頁面測(cè)試,頁面文本框會(huì)顯示URL地址傳遞過來的參數(shù),因?yàn)镾pringMVC會(huì)自動(dòng)匹匹配頁面?zhèn)鬟f過來的參數(shù)的name屬性和后臺(tái)控制器中的方法中的參數(shù)名,如果參數(shù)名相同,會(huì)自動(dòng)匹配,如果控制器中方法是封裝的bean,會(huì)自動(dòng)匹配bean中的屬性,其實(shí)這種取值方式不需要用@ModelAttribute注解,只要滿足匹配要求,也能拿得到值

image.png

從model對(duì)象中取值

@Controller
@RequestMapping(value="model")
public class ModelAttributeTest {
    
    @ModelAttribute("pojo")
    public PojoTest init( PojoTest pojo)
    {
        pojo.setSex("男");
        return pojo;
        
    }
    
    @RequestMapping(value="modelTest.do")
    public String modelTest(@ModelAttribute("pojo") PojoTest pojo) 
    {
        pojo.setUserName("小明");
        return "modelTest";
    }

}

點(diǎn)擊測(cè)試發(fā)現(xiàn),modelTest拿到inint方法中的pojo對(duì)象,合并兩次set的參數(shù)后返回頁面

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容