一文教你如何在java中使用SpringMVC

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)一文教你如何在java中使用SpringMVC,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)公司專注于海州企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),商城網(wǎng)站制作。海州網(wǎng)站建設(shè)公司,為海州等地區(qū)提供建站服務(wù)。全流程按需求定制網(wǎng)站,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)

一、簡(jiǎn)介

SpringMVC 中,控制器Controller 負(fù)責(zé)處理由DispatcherServlet 分發(fā)的請(qǐng)求,它把用戶請(qǐng)求的數(shù)據(jù)經(jīng)過業(yè)務(wù)處理層處理之后封裝成一個(gè)Model ,然后再把該Model 返回給對(duì)應(yīng)的View 進(jìn)行展示。在SpringMVC 中提供了一個(gè)非常簡(jiǎn)便的定義Controller 的方法,你無需繼承特定的類或?qū)崿F(xiàn)特定的接口,只需使用@Controller 標(biāo)記一個(gè)類是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定義URL 請(qǐng)求和Controller 方法之間的映射,這樣的Controller 就能被外界訪問到。此外Controller 不會(huì)直接依賴于HttpServletRequestHttpServletResponse 等HttpServlet 對(duì)象,它們可以通過Controller 的方法參數(shù)靈活的獲取到。為了先對(duì)Controller 有一個(gè)初步的印象,以下先定義一個(gè)簡(jiǎn)單的Controller:

// *java代碼*

@Controller 
public class MyController {  
  @RequestMapping ( "/showView" ) 
  public ModelAndView showView() { 
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName( "viewName" ); 
    modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " ); 
    return modelAndView; 
  } 
 }

在上面的示例中,@Controller 是標(biāo)記在類MyController 上面的,所以類MyController 就是一個(gè)SpringMVC Controller 對(duì)象了,然后使用@RequestMapping(“/showView”) 標(biāo)記在Controller 方法上,表示當(dāng)請(qǐng)求/showView.do 的時(shí)候訪問的是MyController 的showView 方法,該方法返回了一個(gè)包括Model 和View 的ModelAndView 對(duì)象。這些在后續(xù)都將會(huì)詳細(xì)介紹。

二、使用@Controller 定義一個(gè)Controller控制器

@Controller 用于標(biāo)記在一個(gè)類上,使用它標(biāo)記的類就是一個(gè)SpringMVC Controller 對(duì)象。分發(fā)處理器將會(huì)掃描使用了該注解的類的方法,并檢測(cè)該方法是否使用了@RequestMapping 注解。@Controller 只是定義了一個(gè)控制器類,而使用@RequestMapping 注解的方法才是真正處理請(qǐng)求的處理器,這個(gè)接下來就會(huì)講到。

單單使用@Controller 標(biāo)記在一個(gè)類上還不能真正意義上的說它就是SpringMVC 的一個(gè)控制器類,因?yàn)檫@個(gè)時(shí)候Spring 還不認(rèn)識(shí)它。那么要如何做Spring 才能認(rèn)識(shí)它呢?這個(gè)時(shí)候就需要我們把這個(gè)控制器類交給Spring 來管理。拿MyController 來舉一個(gè)例子:

//java代碼
@Controller 
public class MyController { 
  @RequestMapping ( "/showView" ) 
  public ModelAndView showView() { 
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName( "viewName" ); 
    modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " ); 
    return modelAndView; 
  } 
 
}

這個(gè)時(shí)候有兩種方式可以把MyController 交給Spring 管理,好讓它能夠識(shí)別我們標(biāo)記的@Controller 。

第一種方式是在SpringMVC 的配置文件中定義MyController 的bean對(duì)象

<bean class="com.host.app.web.controller.MyController"></bean>

第二種方式是在SpringMVC 的配置文件中告訴Spring 該到哪里去找標(biāo)記為@Controller 的Controller 控制器。

<!-- html 代碼-->
< context:component-scan base-package = "com.host.app.web.controller" > 
  < context:exclude-filter type = "annotation" 
    expression = "org.springframework.stereotype.Service" /> 
</ context:component-scan >

三、使用 @RequestMapping 來映射 Request 請(qǐng)求與處理器

可以使用@RequestMapping 來映射URL 到控制器類,或者是到Controller 控制器的處理方法上。當(dāng)@RequestMapping 標(biāo)記在Controller 類上的時(shí)候,里面使用@RequestMapping 標(biāo)記的方法的請(qǐng)求地址都是相對(duì)于類上的@RequestMapping 而言的;當(dāng)Controller 類上沒有標(biāo)記@RequestMapping 注解時(shí),方法上的@RequestMapping 都是絕對(duì)路徑。這種絕對(duì)路徑和相對(duì)路徑所組合成的最終路徑都是相對(duì)于根路徑“/ ”而言的。

//java代碼
@Controller 
public class MyController { 
  @RequestMapping ( "/showView" ) 
  public ModelAndView showView() { 
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName( "viewName" ); 
    modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " ); 
    return modelAndView; 
  } 
 
}

在這個(gè)控制器中,因?yàn)镸yController 沒有被@RequestMapping 標(biāo)記,所以當(dāng)需要訪問到里面使用了@RequestMapping 標(biāo)記的showView 方法時(shí),就是使用的絕對(duì)路徑/showView.do 請(qǐng)求就可以了。

//java代碼
@Controller 
@RequestMapping ( "/test" ) 
public class MyController { 
  @RequestMapping ( "/showView" ) 
  public ModelAndView showView() { 
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName( "viewName" ); 
    modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " ); 
    return modelAndView; 
  } 
 
}

這種情況是在控制器上加了@RequestMapping 注解,所以當(dāng)需要訪問到里面使用了@RequestMapping 標(biāo)記的方法showView() 的時(shí)候就需要使用showView 方法上@RequestMapping 相對(duì)于控制器MyController 上@RequestMapping 的地址,即/test/showView.do 。

(一)使用URI模板

URI 模板就是在URI 中給定一個(gè)變量,然后在映射的時(shí)候動(dòng)態(tài)的給該變量賦值。在SpringMVC 中,這種取代模板中定義的變量的值也可以給處理器方法使用,這樣我們就可以非常方便的實(shí)現(xiàn)URL 的RestFul 風(fēng)格。這個(gè)變量在SpringMVC 中是使用@PathVariable 來標(biāo)記的。

在SpringMVC 中,我們可以使用@PathVariable 來標(biāo)記一個(gè)Controller 的處理方法參數(shù),表示該參數(shù)的值將使用URI 模板中對(duì)應(yīng)的變量的值來賦值。

//java代碼
@Controller 
@RequestMapping ( "/test/{variable1}" ) 
public class MyController { 
 
  @RequestMapping ( "/showView/{variable2}" ) 
  public ModelAndView showView( @PathVariable String variable1, @PathVariable ( "variable2" ) int variable2) { 
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName( "viewName" ); 
    modelAndView.addObject( " 需要放到 model 中的屬性名稱 " , " 對(duì)應(yīng)的屬性值,它是一個(gè)對(duì)象 " ); 
    return modelAndView; 
  } 
}

在上面的代碼中我們定義了兩個(gè)URI 變量,一個(gè)是控制器類上的variable1 ,一個(gè)是showView 方法上的variable2 ,然后在showView 方法的參數(shù)里面使用@PathVariable 標(biāo)記使用了這兩個(gè)變量。所以當(dāng)我們使用/test/hello/showView/2.do 來請(qǐng)求的時(shí)候就可以訪問到MyController 的showView 方法,這個(gè)時(shí)候variable1 就被賦予值hello ,variable2 就被賦予值2 ,然后我們?cè)趕howView 方法參數(shù)里面標(biāo)注了參數(shù)variable1 和variable2 是來自訪問路徑的path 變量,這樣方法參數(shù)variable1 和variable2 就被分別賦予hello 和2 。方法參數(shù)variable1 是定義為String 類型,variable2 是定義為int 類型,像這種簡(jiǎn)單類型在進(jìn)行賦值的時(shí)候Spring 是會(huì)幫我們自動(dòng)轉(zhuǎn)換的,關(guān)于復(fù)雜類型該如何來轉(zhuǎn)換在后續(xù)內(nèi)容中將會(huì)講到。

在上面的代碼中我們可以看到在標(biāo)記variable1 為path 變量的時(shí)候我們使用的是@PathVariable ,而在標(biāo)記variable2 的時(shí)候使用的是@PathVariable(“variable2”) 。這兩者有什么區(qū)別呢?第一種情況就默認(rèn)去URI 模板中找跟參數(shù)名相同的變量,但是這種情況只有在使用debug 模式進(jìn)行編譯的時(shí)候才可以,而第二種情況是明確規(guī)定使用的就是URI 模板中的variable2 變量。當(dāng)不是使用debug 模式進(jìn)行編譯,或者是所需要使用的變量名跟參數(shù)名不相同的時(shí)候,就要使用第二種方式明確指出使用的是URI 模板中的哪個(gè)變量。

除了在請(qǐng)求路徑中使用URI 模板,定義變量之外,@RequestMapping 中還支持通配符“* ”。如下面的代碼我就可以使用/myTest/whatever/wildcard.do 訪問到Controller 的testWildcard 方法。

@Controller 
@RequestMapping ( "/myTest" ) 
public class MyController { 
  @RequestMapping ( "*/wildcard" ) 
  public String testWildcard() { 
    System. out .println( "wildcard------------" ); 
    return "wildcard" ; 
  }  
}

(二)使用 @RequestParam 綁定 HttpServletRequest 請(qǐng)求參數(shù)到控制器方法參數(shù)

//Java代碼
@RequestMapping ( "requestParam" ) 
ublic String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) { 
  return "requestParam" ; 
}

在上面代碼中利用@RequestParam 從HttpServletRequest 中綁定了參數(shù)name 到控制器方法參數(shù)name ,綁定了參數(shù)age 到控制器方法參數(shù)age 。值得注意的是和@PathVariable 一樣,當(dāng)你沒有明確指定從request 中取哪個(gè)參數(shù)時(shí),Spring 在代碼是debug 編譯的情況下會(huì)默認(rèn)取更方法參數(shù)同名的參數(shù),如果不是debug 編譯的就會(huì)報(bào)錯(cuò)。此外,當(dāng)需要從request 中綁定的參數(shù)和方法的參數(shù)名不相同的時(shí)候,也需要在@RequestParam 中明確指出是要綁定哪個(gè)參數(shù)。在上面的代碼中如果我訪問/requestParam.do&#63;name=hello&age=1 則Spring 將會(huì)把request 請(qǐng)求參數(shù)name 的值hello 賦給對(duì)應(yīng)的處理方法參數(shù)name ,把參數(shù)age 的值1 賦給對(duì)應(yīng)的處理方法參數(shù)age 。

@RequestParam 中除了指定綁定哪個(gè)參數(shù)的屬性value 之外,還有一個(gè)屬性required ,它表示所指定的參數(shù)是否必須在request 屬性中存在,默認(rèn)是true ,表示必須存在,當(dāng)不存在時(shí)就會(huì)報(bào)錯(cuò)。在上面代碼中我們指定了參數(shù)name 的required 的屬性為false ,而沒有指定age 的required 屬性,這時(shí)候如果我們?cè)L問/requestParam.do 而沒有傳遞參數(shù)的時(shí)候,系統(tǒng)就會(huì)拋出異常,因?yàn)閍ge 參數(shù)是必須存在的,而我們沒有指定。而如果我們?cè)L問/requestParam.do&#63;age=1 的時(shí)候就可以正常訪問,因?yàn)槲覀儌鬟f了必須的參數(shù)age ,而參數(shù)name 是非必須的,不傳遞也可以。

(三)使用 @CookieValue 綁定 cookie 的值到 Controller 方法參數(shù)

//java代碼
@RequestMapping ( "cookieValue" ) 
public String testCookieValue( @CookieValue ( "hello" ) String cookieValue, @CookieValue String hello) { 
  System. out .println(cookieValue + "-----------" + hello); 
  return "cookieValue" ; 
}

在上面的代碼中我們使用@CookieValue 綁定了cookie 的值到方法參數(shù)上。上面一共綁定了兩個(gè)參數(shù),一個(gè)是明確指定要綁定的是名稱為hello 的cookie 的值,一個(gè)是沒有指定。使用沒有指定的形式的規(guī)則和@PathVariable 、@RequestParam 的規(guī)則是一樣的,即在debug 編譯模式下將自動(dòng)獲取跟方法參數(shù)名同名的cookie 值。

(四)使用 @RequestHeader 注解綁定 HttpServletRequest 頭信息到 Controller 方法參數(shù)

//java代碼
@RequestMapping ( "testRequestHeader" ) 
public String testRequestHeader( @RequestHeader ( "Host" ) String hostAddr, @RequestHeader String Host, @RequestHeader String host ) { 
  System. out .println(hostAddr + "-----" + Host + "-----" + host ); 
  return "requestHeader" ; 
}

在上面的代碼中我們使用了 @RequestHeader 綁定了 HttpServletRequest 請(qǐng)求頭 host 到 Controller 的方法參數(shù)。上面方法的三個(gè)參數(shù)都將會(huì)賦予同一個(gè)值,由此我們可以知道在綁定請(qǐng)求頭參數(shù)到方法參數(shù)的時(shí)候規(guī)則和 @PathVariable 、 @RequestParam 以及 @CookieValue 是一樣的,即沒有指定綁定哪個(gè)參數(shù)到方法參數(shù)的時(shí)候,在 debug 編譯模式下將使用方法參數(shù)名作為需要綁定的參數(shù)。但是有一點(diǎn) @RequestHeader 跟另外三種綁定方式是不一樣的,那就是在使用 @RequestHeader 的時(shí)候是大小寫不敏感的,即 @RequestHeader(“Host”) 和 @RequestHeader(“host”) 綁定的都是 Host 頭信息。記住在 @PathVariable 、 @RequestParam 和 @CookieValue 中都是大小寫敏感的。

(五) @RequestMapping 的一些高級(jí)應(yīng)用

在RequestMapping 中除了指定請(qǐng)求路徑value 屬性外,還有其他的屬性可以指定,如params 、method 和headers 。這樣屬性都可以用于縮小請(qǐng)求的映射范圍。

params屬性

params 屬性用于指定請(qǐng)求參數(shù)的,先看以下代碼。

//java代碼
@RequestMapping (value= "testParams" , params={ "param1=value1" , "param2" , "!param3" }) 
public String testParams() { 
  System. out .println( "test Params..........." ); 
  return "testParams" ; 
}

在上面的代碼中我們用@RequestMapping 的params 屬性指定了三個(gè)參數(shù),這些參數(shù)都是針對(duì)請(qǐng)求參數(shù)而言的,它們分別表示參數(shù)param1 的值必須等于value1 ,參數(shù)param2 必須存在,值無所謂,參數(shù)param3 必須不存在,只有當(dāng)請(qǐng)求/testParams.do 并且滿足指定的三個(gè)參數(shù)條件的時(shí)候才能訪問到該方法。所以當(dāng)請(qǐng)求/testParams.do&#63;param1=value1&para;m2=value2 的時(shí)候能夠正確訪問到該testParams 方法,當(dāng)請(qǐng)求/testParams.do&#63;param1=value1&para;m2=value2&para;m3=value3 的時(shí)候就不能夠正常的訪問到該方法,因?yàn)樵贎RequestMapping 的params 參數(shù)里面指定了參數(shù)param3 是不能存在的。

2. method屬性

method 屬性主要是用于限制能夠訪問的方法類型的。

//java代碼
@RequestMapping (value= "testMethod" , method={RequestMethod. GET , RequestMethod. DELETE }) 
public String testMethod() { 
  return "method" ; 
}

在上面的代碼中就使用method 參數(shù)限制了以GET 或DELETE 方法請(qǐng)求/testMethod.do 的時(shí)候才能訪問到該Controller 的testMethod 方法。

3. headers屬性

使用headers 屬性可以通過請(qǐng)求頭信息來縮小@RequestMapping 的映射范圍。

//java 代碼
@RequestMapping (value= "testHeaders" , headers={ "host=localhost" , "Accept" }) 
public String testHeaders() { 
  return "headers" ; 
}

headers 屬性的用法和功能與params 屬性相似。在上面的代碼中當(dāng)請(qǐng)求/testHeaders.do 的時(shí)候只有當(dāng)請(qǐng)求頭包含Accept 信息,且請(qǐng)求的host 為localhost 的時(shí)候才能正確的訪問到testHeaders 方法。

(六)以 @RequestMapping 標(biāo)記的處理器方法支持的方法參數(shù)和返回類型

1.支持的方法參數(shù)類型

(1 )HttpServlet 對(duì)象,主要包括HttpServletRequest 、HttpServletResponse 和HttpSession 對(duì)象。 這些參數(shù)Spring 在調(diào)用處理器方法的時(shí)候會(huì)自動(dòng)給它們賦值,所以當(dāng)在處理器方法中需要使用到這些對(duì)象的時(shí)候,可以直接在方法上給定一個(gè)方法參數(shù)的申明,然后在方法體里面直接用就可以了。但是有一點(diǎn)需要注意的是在使用HttpSession 對(duì)象的時(shí)候,如果此時(shí)HttpSession 對(duì)象還沒有建立起來的話就會(huì)有問題。

(2 )Spring 自己的WebRequest 對(duì)象。 使用該對(duì)象可以訪問到存放在HttpServletRequest 和HttpSession 中的屬性值。

(3 )InputStream 、OutputStream 、Reader 和Writer 。 InputStream 和Reader 是針對(duì)HttpServletRequest 而言的,可以從里面取數(shù)據(jù);OutputStream 和Writer 是針對(duì)HttpServletResponse 而言的,可以往里面寫數(shù)據(jù)。

(4 )使用@PathVariable 、@RequestParam 、@CookieValue 和@RequestHeader 標(biāo)記的參數(shù)。

(5 )使用@ModelAttribute 標(biāo)記的參數(shù)。

(6 )java.util.Map 、Spring 封裝的Model 和ModelMap 。 這些都可以用來封裝模型數(shù)據(jù),用來給視圖做展示。

(7 )實(shí)體類。 可以用來接收上傳的參數(shù)。

(8 )Spring 封裝的MultipartFile 。 用來接收上傳文件的。

(9 )Spring 封裝的Errors 和BindingResult 對(duì)象。 這兩個(gè)對(duì)象參數(shù)必須緊接在需要驗(yàn)證的實(shí)體對(duì)象參數(shù)之后,它里面包含了實(shí)體對(duì)象的驗(yàn)證結(jié)果。

2. 支持的返回類型

(1 )一個(gè)包含模型和視圖的ModelAndView 對(duì)象。

(2 )一個(gè)模型對(duì)象,這主要包括Spring 封裝好的Model 和ModelMap ,以及java.util.Map ,當(dāng)沒有視圖返回的時(shí)候視圖名稱將由RequestToViewNameTranslator 來決定。

(3 )一個(gè)View 對(duì)象。這個(gè)時(shí)候如果在渲染視圖的過程中模型的話就可以給處理器方法定義一個(gè)模型參數(shù),然后在方法體里面往模型中添加值。

(4 )一個(gè)String 字符串。這往往代表的是一個(gè)視圖名稱。這個(gè)時(shí)候如果需要在渲染視圖的過程中需要模型的話就可以給處理器方法一個(gè)模型參數(shù),然后在方法體里面往模型中添加值就可以了。

(5 )返回值是void 。這種情況一般是我們直接把返回結(jié)果寫到HttpServletResponse 中了,如果沒有寫的話,那么Spring 將會(huì)利用RequestToViewNameTranslator 來返回一個(gè)對(duì)應(yīng)的視圖名稱。如果視圖中需要模型的話,處理方法與返回字符串的情況相同。

(6 )如果處理器方法被注解@ResponseBody 標(biāo)記的話,那么處理器方法的任何返回類型都會(huì)通過HttpMessageConverters 轉(zhuǎn)換之后寫到HttpServletResponse 中,而不會(huì)像上面的那些情況一樣當(dāng)做視圖或者模型來處理。

(7 )除以上幾種情況之外的其他任何返回類型都會(huì)被當(dāng)做模型中的一個(gè)屬性來處理,而返回的視圖還是由RequestToViewNameTranslator 來決定,添加到模型中的屬性名稱可以在該方法上用@ModelAttribute(“attributeName”) 來定義,否則將使用返回類型的類名稱的首字母小寫形式來表示。使用@ModelAttribute 標(biāo)記的方法會(huì)在@RequestMapping 標(biāo)記的方法執(zhí)行之前執(zhí)行。

(七)使用 @ModelAttribute 和 @SessionAttributes 傳遞和保存數(shù)據(jù)

SpringMVC 支持使用 @ModelAttribute 和 @SessionAttributes 在不同的模型和控制器之間共享數(shù)據(jù)。 @ModelAttribute 主要有兩種使用方式,一種是標(biāo)注在方法上,一種是標(biāo)注在 Controller 方法參數(shù)上。

當(dāng) @ModelAttribute 標(biāo)記在方法上的時(shí)候,該方法將在處理器方法執(zhí)行之前執(zhí)行,然后把返回的對(duì)象存放在 session 或模型屬性中,屬性名稱可以使用 @ModelAttribute(“attributeName”) 在標(biāo)記方法的時(shí)候指定,若未指定,則使用返回類型的類名稱(首字母小寫)作為屬性名稱。關(guān)于 @ModelAttribute 標(biāo)記在方法上時(shí)對(duì)應(yīng)的屬性是存放在 session 中還是存放在模型中,我們來做一個(gè)實(shí)驗(yàn),看下面一段代碼。

//java代碼
@Controller
@RequestMapping ( "/myTest" )
public class MyController {
  @ModelAttribute ( "hello" )
  public String getModel() {
    System. out .println( "-------------Hello---------" );
    return "world" ;
  } 
  @ModelAttribute ( "intValue" )
  public int getInteger() {
    System. out .println( "-------------intValue---------------" );
    return 10;
  }
  @RequestMapping ( "sayHello" )
  public void sayHello( @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpSession session) throws IOException {
    writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
    writer.write( "\r" );
    Enumeration enume = session.getAttributeNames();
    while (enume.hasMoreElements())
      writer.write(enume.nextElement() + "\r" );
  }
  @ModelAttribute ( "user2" )
  public User getUser() {
    System. out .println( "---------getUser-------------" );
    return new User(3, "user2" );
  }
}

當(dāng)我們請(qǐng)求 /myTest/sayHello.do 的時(shí)候使用 @ModelAttribute 標(biāo)記的方法會(huì)先執(zhí)行,然后把它們返回的對(duì)象存放到模型中。最終訪問到 sayHello 方法的時(shí)候,使用 @ModelAttribute 標(biāo)記的方法參數(shù)都能被正確的注入值。執(zhí)行結(jié)果如下圖所示:

Hello world,Hello user210

由執(zhí)行結(jié)果我們可以看出來,此時(shí) session 中沒有包含任何屬性,也就是說上面的那些對(duì)象都是存放在模型屬性中,而不是存放在 session 屬性中。那要如何才能存放在 session 屬性中呢?這個(gè)時(shí)候我們先引入一個(gè)新的概念 @SessionAttributes ,它的用法會(huì)在講完 @ModelAttribute 之后介紹,這里我們就先拿來用一下。我們?cè)?MyController 類上加上 @SessionAttributes 屬性標(biāo)記哪些是需要存放到 session 中的??聪旅娴拇a:

//java代碼
@Controller
@RequestMapping ( "/myTest" )
@SessionAttributes (value={ "intValue" , "stringValue" }, types={User. class })
public class MyController {
  @ModelAttribute ( "hello" )
  public String getModel() {
    System. out .println( "-------------Hello---------" );
    return "world" ;
  }
  @ModelAttribute ( "intValue" )
  public int getInteger() {
    System. out .println( "-------------intValue---------------" );
    return 10;
  }
  @RequestMapping ( "sayHello" )
  public void sayHello(Map<string, object=""> map, @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" ) int num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpServletRequest request) throws IOException {
    map.put( "stringValue" , "String" );
    writer.write( "Hello " + hello + " , Hello " + user.getUsername() + num);
    writer.write( "\r" );
    HttpSession session = request.getSession();
    Enumeration enume = session.getAttributeNames();
    while (enume.hasMoreElements())
      writer.write(enume.nextElement() + "\r" );
    System. out .println(session);
  }
  @ModelAttribute ( "user2" )
  public User getUser() {
    System. out .println( "---------getUser-------------" );
    return new User(3, "user2" );
  }
}

在上面代碼中我們指定了屬性為 intValue 或 stringValue 或者類型為 User 的都會(huì)放到 Session 中,利用上面的代碼當(dāng)我們?cè)L問 /myTest/sayHello.do 的時(shí)候,結(jié)果如下:

Hello world,Hello user210

仍然沒有打印出任何 session 屬性,這是怎么回事呢?怎么定義了把模型中屬性名為 intValue 的對(duì)象和類型為 User 的對(duì)象存到 session 中,而實(shí)際上沒有加進(jìn)去呢?難道我們錯(cuò)啦?我們當(dāng)然沒有錯(cuò),只是在第一次訪問 /myTest/sayHello.do 的時(shí)候 @SessionAttributes 定義了需要存放到 session 中的屬性,而且這個(gè)模型中也有對(duì)應(yīng)的屬性,但是這個(gè)時(shí)候還沒有加到 session 中,所以 session 中不會(huì)有任何屬性,等處理器方法執(zhí)行完成后 Spring 才會(huì)把模型中對(duì)應(yīng)的屬性添加到 session 中。所以當(dāng)請(qǐng)求第二次的時(shí)候就會(huì)出現(xiàn)如下結(jié)果:

Hello world,Hello user210

user2

intValue

stringValue

當(dāng) @ModelAttribute 標(biāo)記在處理器方法參數(shù)上的時(shí)候,表示該參數(shù)的值將從模型或者 Session 中取對(duì)應(yīng)名稱的屬性值,該名稱可以通過 @ModelAttribute(“attributeName”) 來指定,若未指定,則使用參數(shù)類型的類名稱(首字母小寫)作為屬性名稱。

//java代碼
@Controller
@RequestMapping ( "/myTest" )
public class MyController {
 
  @ModelAttribute ( "hello" )
  public String getModel() {
    return "world" ;
  }
  @RequestMapping ( "sayHello" )
  public void sayHello( @ModelAttribute ( "hello" ) String hello, Writer writer) throws IOException {
    writer.write( "Hello " + hello);
  }  
}

在上面代碼中,當(dāng)我們請(qǐng)求/myTest/sayHello.do 的時(shí)候,由于MyController 中的方法getModel 使用了注解@ModelAttribute 進(jìn)行標(biāo)記,所以在執(zhí)行請(qǐng)求方法sayHello 之前會(huì)先執(zhí)行g(shù)etModel 方法,這個(gè)時(shí)候getModel 方法返回一個(gè)字符串world 并把它以屬性名hello 保存在模型中,接下來訪問請(qǐng)求方法sayHello 的時(shí)候,該方法的hello 參數(shù)使用@ModelAttribute(“hello”) 進(jìn)行標(biāo)記,這意味著將從session 或者模型中取屬性名稱為hello 的屬性值賦給hello 參數(shù),所以這里hello 參數(shù)將被賦予值world ,所以請(qǐng)求完成后將會(huì)在頁(yè)面上看到Hello world 字符串。

@SessionAttributes 用于標(biāo)記需要在Session 中使用到的數(shù)據(jù),包括從Session 中取數(shù)據(jù)和存數(shù)據(jù)。@SessionAttributes 一般是標(biāo)記在Controller 類上的,可以通過名稱、類型或者名稱加類型的形式來指定哪些屬性是需要存放在session 中的。

//java代碼
@Controller
@RequestMapping ( "/myTest" )
@SessionAttributes (value={ "user1" , "blog1" }, types={User. class , Blog. class })
public class MyController {
 
  @RequestMapping ( "setSessionAttribute" )
  public void setSessionAttribute(Map<string, object=""> map, Writer writer) throws IOException {
    User user = new User(1, "user" );
    User user1 = new User(2, "user1" );
    Blog blog = new Blog(1, "blog" );
    Blog blog1 = new Blog(2, "blog1" );
    map.put( "user" , user);
    map.put( "user1" , user1);
    map.put( "blog" , blog);
    map.put( "blog1" , blog1);
    writer.write( "over." );
  }
  @RequestMapping ( "useSessionAttribute" )
  public void useSessionAttribute(Writer writer, @ModelAttribute ( "user1" ) User user1, @ModelAttribute ( "blog1" ) Blog blog1) throws IOException {
    writer.write(user1.getId() + "--------" + user1.getUsername());
    writer.write( "\r" );
    writer.write(blog1.getId() + "--------" + blog1.getTitle());
  }
  @RequestMapping ( "useSessionAttribute2" )
  public void useSessionAttribute(Writer writer, @ModelAttribute ( "user1" ) User user1, @ModelAttribute ( "blog1" ) Blog blog1, @ModelAttribute User user, HttpSession session) throws IOException {
    writer.write(user1.getId() + "--------" + user1.getUsername());
    writer.write( "\r" );
    writer.write(blog1.getId() + "--------" + blog1.getTitle());
    writer.write( "\r" );
    writer.write(user.getId() + "---------" + user.getUsername());
    writer.write( "\r" );
    Enumeration enume = session.getAttributeNames();
    while (enume.hasMoreElements())
      writer.write(enume.nextElement() + " \r" );
  }
  @RequestMapping ( "useSessionAttribute3" )
  public void useSessionAttribute( @ModelAttribute ( "user2" ) User user) {
 
  }
}

在上面代碼中我們可以看到在MyController 上面使用了@SessionAttributes 標(biāo)記了需要使用到的Session 屬性。

可以通過名稱和類型指定需要存放到Session 中的屬性,對(duì)應(yīng)@SessionAttributes 注解的value 和types 屬性。當(dāng)使用的是types 屬性的時(shí)候,那么使用的Session 屬性名稱將會(huì)是對(duì)應(yīng)類型的名稱(首字母小寫)。

當(dāng)value 和types 兩個(gè)屬性都使用到了的時(shí)候,這時(shí)候取的是它們的并集,而不是交集,所以上面代碼中指定要存放在Session 中的屬性有名稱為user1 或blog1 的對(duì)象,或類型為User 或Blog 的對(duì)象。

在上面代碼中我們首先訪問/myTest/setSessionAttribute.do ,該請(qǐng)求將會(huì)請(qǐng)求到MyController 的setSessionAttribute 方法,在該方法中,我們往模型里面添加了user 、user1 、blog 和blog1 四個(gè)屬性,因?yàn)樗鼈兓蚋惿系腀SessionAttributes 定義的需要存到session 中的屬性名稱相同或類型相同,所以在請(qǐng)求完成后這四個(gè)屬性都將添加到session 屬性中。

接下來訪問/myTest/useSessionAttribute.do ,該請(qǐng)求將會(huì)請(qǐng)求MyController 的useSessionAttribute(Writer writer, @ModelAttribute(“user1”) User user1, @ModelAttribute(“blog1”) Blog blog) 方法,該方法參數(shù)中用@ModelAttribute 指定了參數(shù)user1 和參數(shù)blog1 是需要從session 或模型中綁定的,恰好這個(gè)時(shí)候session 中已經(jīng)有了這兩個(gè)屬性,所以這個(gè)時(shí)候在方法執(zhí)行之前會(huì)先綁定這兩個(gè)參數(shù)。執(zhí)行結(jié)果如下圖所示:

2————-user1

2————-blog1

接下來訪問/myTest/useSessionAttribute2.do ,這個(gè)時(shí)候請(qǐng)求的是上面代碼中對(duì)應(yīng)的第二個(gè)useSessionAttribute 方法,方法參數(shù)user 、user1 和blog1 用@ModelAttribute 聲明了需要session 或模型屬性注入,我們知道在請(qǐng)求/myTest/setSessionAttribute.do 的時(shí)候這些屬性都已經(jīng)添加到了session 中,所以該請(qǐng)求的結(jié)果會(huì)如下圖所示:

2————-user1

2————-blog1

1————-user

blog

user

user1

blog1

接下來訪問/myTest/useSessionAttribute3.do ,這個(gè)時(shí)候請(qǐng)求的是上面代碼中對(duì)應(yīng)的第三個(gè)useSessionAttribute 方法,我們可以看到該方法的方法參數(shù)user 使用了@ModelAttribute(“user2”) 進(jìn)行標(biāo)記,表示user 需要session 中的user2 屬性來注入,但是這個(gè)時(shí)候我們知道session 中是不存在user2 屬性的,所以這個(gè)時(shí)候就會(huì)報(bào)錯(cuò)了。執(zhí)行結(jié)果如圖所示:

一文教你如何在java中使用SpringMVC

(八)定制自己的類型轉(zhuǎn)換器

在通過處理器方法參數(shù)接收 request 請(qǐng)求參數(shù)綁定數(shù)據(jù)的時(shí)候,對(duì)于一些簡(jiǎn)單的數(shù)據(jù)類型 Spring 會(huì)幫我們自動(dòng)進(jìn)行類型轉(zhuǎn)換,而對(duì)于一些復(fù)雜的類型由于 Spring 沒法識(shí)別,所以也就不能幫助我們進(jìn)行自動(dòng)轉(zhuǎn)換了,這個(gè)時(shí)候如果我們需要 Spring 來幫我們自動(dòng)轉(zhuǎn)換的話就需要我們給 Spring 注冊(cè)一個(gè)對(duì)特定類型的識(shí)別轉(zhuǎn)換器。

Spring 允許我們提供兩種類型的識(shí)別轉(zhuǎn)換器,一種是注冊(cè)在 Controller 中的,一種是注冊(cè)在 SpringMVC 的配置文件中。聰明的讀者看到這里應(yīng)該可以想到它們的區(qū)別了,定義在 Controller 中的是局部的,只在當(dāng)前 Controller 中有效,而放在 SpringMVC 配置文件中的是全局的,所有 Controller 都可以拿來使用。

在 @InitBinder 標(biāo)記的方法中定義局部的類型轉(zhuǎn)換器

我們可以使用 @InitBinder 注解標(biāo)注在 Controller 方法上,然后在方法體里面注冊(cè)數(shù)據(jù)綁定的轉(zhuǎn)換器,這主要是通過 WebDataBinder 進(jìn)行的。

我們可以給需要注冊(cè)數(shù)據(jù)綁定的轉(zhuǎn)換器的方法一個(gè) WebDataBinder 參數(shù),然后給該方法加上 @InitBinder 注解,這樣當(dāng)該 Controller 中在處理請(qǐng)求方法時(shí)如果發(fā)現(xiàn)有不能解析的對(duì)象的時(shí)候,就會(huì)看該類中是否有使用 @InitBinder 標(biāo)記的方法,如果有就會(huì)執(zhí)行該方法,然后看里面定義的類型轉(zhuǎn)換器是否與當(dāng)前需要的類型匹配。

//java代碼
@Controller 
@RequestMapping ( "/myTest" ) 
public class MyController { 
 
  @InitBinder 
  public void dataBinder(WebDataBinder binder) { 
    DateFormat dateFormat = new SimpleDateFormat( "yyyyMMdd" ); 
    PropertyEditor propertyEditor = new CustomDateEditor(dateFormat, true ); // 第二個(gè)參數(shù)表示是否允許為空 
    binder.registerCustomEditor(Date. class , propertyEditor); 
  } 
  @RequestMapping ( "dataBinder/{date}" ) 
  public void testDate( @PathVariable Date date, Writer writer) throws IOException { 
    writer.write(String.valueOf (date.getTime())); 
  } 
}


在上面的代碼中當(dāng)我們請(qǐng)求 /myTest/dataBinder/20121212.do 的時(shí)候, Spring 就會(huì)利用 @InitBinder 標(biāo)記的方法里面定義的類型轉(zhuǎn)換器把字符串 20121212 轉(zhuǎn)換為一個(gè) Date 對(duì)象。

這樣定義的類型轉(zhuǎn)換器是局部的類型轉(zhuǎn)換器,一旦出了這個(gè) Controller 就不會(huì)再起作用。類型轉(zhuǎn)換器是通過 WebDataBinder 對(duì)象的 registerCustomEditor 方法來注冊(cè)的,要實(shí)現(xiàn)自己的類型轉(zhuǎn)換器就要實(shí)現(xiàn)自己的 PropertyEditor 對(duì)象。 Spring 已經(jīng)給我們提供了一些常用的屬性編輯器,如 CustomDateEditor 、 CustomBooleanEditor 等。

PropertyEditor 是一個(gè)接口,要實(shí)現(xiàn)自己的 PropertyEditor 類我們可以實(shí)現(xiàn)這個(gè)接口,然后實(shí)現(xiàn)里面的方法。

但是 PropertyEditor 里面定義的方法太多了,這樣做比較麻煩。在 java 中有一個(gè)封裝類是實(shí)現(xiàn)了 PropertyEditor 接口的,它是 PropertyEditorSupport 類。所以如果需要實(shí)現(xiàn)自己的 PropertyEditor 的時(shí)候只需要繼承 PropertyEditorSupport 類,然后重寫其中的一些方法。

一般就是重寫 setAsText 和 getAsText 方法就可以了, setAsText 方法是用于把字符串類型的值轉(zhuǎn)換為對(duì)應(yīng)的對(duì)象的,而 getAsText 方法是用于把對(duì)象當(dāng)做字符串來返回的。在 setAsText 中我們一般先把字符串類型的對(duì)象轉(zhuǎn)為特定的對(duì)象,然后利用 PropertyEditor 的 setValue 方法設(shè)定轉(zhuǎn)換后的值。在 getAsText 方法中一般先使用 getValue 方法取代當(dāng)前的對(duì)象,然后把它轉(zhuǎn)換為字符串后再返回給 getAsText 方法。下面是一個(gè)示例:

//java代碼
@InitBinder 
public void dataBinder(WebDataBinder binder) { 
  // 定義一個(gè) User 屬性編輯器 
  PropertyEditor userEditor = new PropertyEditorSupport() { 
    @Override 
    public String getAsText() { 
     // TODO Auto-generated method stub 
     User user = (User) getValue(); 
     return user.getUsername(); 
    } 
    @Override 
    public void setAsText(String userStr) throws IllegalArgumentException { 
     // TODO Auto-generated method stub 
     User user = new User(1, userStr); 
     setValue(user); 
    } 
  }; 
  // 使用 WebDataBinder 注冊(cè) User 類型的屬性編輯器 
  binder.registerCustomEditor(User. class , userEditor); 
}

實(shí)現(xiàn) WebBindingInitializer 接口定義全局的類型轉(zhuǎn)換器

如果需要定義全局的類型轉(zhuǎn)換器就需要實(shí)現(xiàn)自己的 WebBindingInitializer 對(duì)象,然后把該對(duì)象注入到

AnnotationMethodHandlerAdapter 中,這樣 Spring 在遇到自己不能解析的對(duì)象的時(shí)候就會(huì)到全局的 WebBindingInitializer 的 initBinder 方法中去找,每次遇到不認(rèn)識(shí)的對(duì)象時(shí), initBinder 方法都會(huì)被執(zhí)行一遍。

//java代碼
public class MyWebBindingInitializer implements WebBindingInitializer { 
 
  @Override 
  public void initBinder(WebDataBinder binder, WebRequest request) { 
    // TODO Auto-generated method stub 
    DateFormat dateFormat = new SimpleDateFormat( "yyyyMMdd" ); 
    PropertyEditor propertyEditor = new CustomDateEditor(dateFormat, true ); 
    binder.registerCustomEditor(Date. class , propertyEditor); 
  } 
}

定義了這么一個(gè) WebBindingInitializer 對(duì)象之后 Spring 還是不能識(shí)別其中指定的對(duì)象,這是因?yàn)槲覀冎皇嵌x了 WebBindingInitializer 對(duì)象,還沒有把它交給 Spring , Spring 不知道該去哪里找解析器。要讓 Spring 能夠識(shí)別還需要我們?cè)?SpringMVC 的配置文件中定義一個(gè) AnnotationMethodHandlerAdapter 類型的 bean 對(duì)象,然后利用自己定義的 WebBindingInitializer 覆蓋它的默認(rèn)屬性 webBindingInitializer 。

<!--html代碼-->
< bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" > 
  < property name = "webBindingInitializer" > 
    < bean class = "com.host.app.web.util.MyWebBindingInitializer" /> 
  </ property > 
</ bean >

觸發(fā)數(shù)據(jù)綁定方法的時(shí)間

當(dāng)Controller處理器方法參數(shù)使用@RequestParam、@PathVariable、@RequestHeader、@CookieValue和@ModelAttribute標(biāo)記的時(shí)候都會(huì)觸發(fā)initBinder方法的執(zhí)行,這包括使用WebBindingInitializer定義的全局方法和在Controller中使用@InitBinder標(biāo)記的局部方法。而且每個(gè)使用了這幾個(gè)注解標(biāo)記的參數(shù)都會(huì)觸發(fā)一次initBinder方法的執(zhí)行,這也意味著有幾個(gè)參數(shù)使用了上述注解就會(huì)觸發(fā)幾次initBinder方法的執(zhí)行。

上述就是小編為大家分享的一文教你如何在java中使用SpringMVC了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

新聞名稱:一文教你如何在java中使用SpringMVC
URL地址:http://muchs.cn/article30/joghpo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、移動(dòng)網(wǎng)站建設(shè)、面包屑導(dǎo)航網(wǎng)站設(shè)計(jì)、App設(shè)計(jì)、網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司