日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring MVC-04循序渐进之基于注解的控制器

發(fā)布時(shí)間:2025/3/21 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring MVC-04循序渐进之基于注解的控制器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  • 概述
  • Spring MVC注解類型
    • Controller注解類型
    • RequestMapping注解類型
      • value屬性
      • 其他屬性
  • 編寫請求處理方法
  • 應(yīng)用基于注解的控制器
    • 目錄結(jié)構(gòu)
    • 配置文件
    • Controller類
    • View
    • 測試應(yīng)用
  • 使用@Autowired和@Service進(jìn)行依賴注入
  • 重定向和Flash屬性
  • 請求參數(shù)和路徑變量
    • 獲取請求參數(shù)
    • 獲取路徑變量
    • 使用路徑變量有可能出現(xiàn)的問題
  • @ModelAttribute
    • @ModelAttribute的第一個(gè)用途
    • @ModelAttribute的第二個(gè)用途
  • 總結(jié)

概述

Spring MVC-03循序漸進(jìn)之Spring MVC中我們介紹了傳統(tǒng)的開發(fā)方式,其弊端Controller接口實(shí)現(xiàn)類只能處理一個(gè)單一動(dòng)作,本篇博文我們來介紹下基于注解的控制器。


Spring MVC注解類型

基于注解的控制器優(yōu)點(diǎn)如下:

  • 一個(gè)控制器可以處理多個(gè)請求動(dòng)作,而一個(gè)實(shí)現(xiàn)了Controller接口的控制器只能處理一個(gè)動(dòng)作

  • 基于注解的控制器的請求映射不需要存儲在配置文件中,使用RequestMapping注解類型,可以對一個(gè)方法進(jìn)行請求處理。

  • Controller和RequestMapping注解類型是SpringMVC API最重要的兩個(gè)注釋類型,當(dāng)然了我們這里也會介紹其他一些注解類型


    Controller注解類型

    org.springframework.stereotype.Controller注解類型用于指示Spring類的實(shí)例是一個(gè)控制器。

    下面是一個(gè)帶有@Controller注解的例子

    import org.springframework.stereotype.Controller;@Controller public class ArtisanController {}

    Spring使用注解掃描的方式來找到應(yīng)用中所有基于注解的控制器類,為了確保Spring能掃描到你的控制器,需要完成兩件事情

  • 在Spring MVC配置文件中聲明spring-context及指定schema
  • 然后配置component-scan掃描路徑
  • <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.artisan.springmvc.controller"/><!--......省略其他配置項(xiàng)---></beans>

    確保所有控制器類都在基本包下,并且不要指定一個(gè)太寬泛的基本包,這樣會使Spring掃描了無關(guān)的包。


    RequestMapping注解類型

    現(xiàn)在我們需要在控制器類內(nèi)部為每一個(gè)動(dòng)作開發(fā)相應(yīng)的處理方法,要讓Spring知道哪一種方法來處理它的動(dòng)作,需要使用org.springframework.web.bind.annotation.RequestMapping注解類型映射的URL與方法。

    RequestMapping注釋類型的作用:映射一個(gè)請求和一種方法,可以使用@RequestMapping注釋一種方法或者一個(gè)類

    一個(gè)采用了@RequestMapping注解的方法將成為一個(gè)請求處理方法,并由調(diào)度程序在接收到對應(yīng)的URL請求時(shí)調(diào)用

    下面是一個(gè)@RequestMapping注解方法的控制器類

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;@Controller public class ArtisanController {@RequestMapping(value="/doSomething")public String doSomething() {// do some bussiness logic herereturn "custoomer";} }

    使用RequestMapping注解的value屬性將URI映射到方法。在上面的例子中,我們將doSomething映射到doSomething方法,這樣,就可以使用如下URL訪問doSomething方法

    http://domain/context/doSomething

    value屬性

    由于value屬性是RequestMapping注解的默認(rèn)屬性,如果只有唯一的屬性,則可以省略屬性名稱。換句話說

    @RequestMapping(value="/doSomething")@RequestMapping("/doSomething")

    效果是等同的,但是如果超過一個(gè)屬性時(shí),就必須要輸入value屬性名稱。

    請求映射的值可以是一個(gè)空字符,此時(shí)該方法被映射到如下網(wǎng)址 http://domain/context

    其他屬性

    RequestMapping除了具有value屬性,還有其他屬性。比如method屬性用來指示改方法僅處理哪些HTTP方法. 當(dāng)method為多個(gè)值時(shí),后面寫為數(shù)組{method1, method2}

    例如只有在HTTP POST或者PUT方法時(shí)才能訪問到下面的方法

    @Controller public class ArtisanController {@RequestMapping(value="/doSomething",method={RequestMethod.POST,RequestMethod.PUT})public String doSomething() {// do some bussiness logic herereturn "customer";} }

    如果method屬性僅有一個(gè)HTTP方法值,則不需要花括號

    @RequestMapping(value="/doSomething",method=RequestMethod.POST)

    如果沒有指定method屬性值,則請求處理方法可以處理任意HTTP方法。


    此外RequestMapping注釋類型也可以用來注釋一個(gè)控制器類

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;@Controller @RequestMapping("/artisan") public class ArtisanController {}

    這種情況下,所有的方法都將映射為相對于類級別的請求,比如下面的deleteArtisan方法

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;@Controller @RequestMapping("/artisan") public class ArtisanController {@RequestMapping(value="/delete",method={RequestMethod.POST,RequestMethod.PUT})public String deleteArtisan() {// do delete opertaionreturn "artisanList";} }

    由于控制器類的映射使用了“/artisan” ,而deleteArtisan方法映射為/delete,則如下的URL將映射到該方法上

    htpp://domain/context/artisan/delete

    編寫請求處理方法

    每個(gè)請求處理方法可以有多個(gè)不同類型的參數(shù),以及一個(gè)多鐘類型的返回結(jié)果。

    比如在請求處理方法中需要訪問HttpSession對象,則可以添加HttpSession作為參數(shù),Spring會將對象正確傳遞給方法

    @RequestMapping("/uri")public String method(HttpSession session){// do somethingsession.setAttribute(key, value);return ...;}

    或者,如果需要訪問客戶端環(huán)境和HttpServletRequest,則可以在方法簽名上包括這樣的參數(shù)

    @RequestMapping("/uri")public String method(HttpServletRequest request,Locale locale){// access HttpServletRequest or Locale here return ...;}

    每個(gè)請求處理方法可以有多個(gè)不同類型的參數(shù),下面時(shí)可以在請求處理方法中出現(xiàn)的參數(shù)類型:

    • javax.servlet.ServletRequest 或 javax.servlet.HttpServletRequest

    • javax.servlet.ServletResponse
      或 javax.servlet.httpHttpServletResponse

    • javax.servlet.http.HttpSession

    • org.springframework.web.context.request.WebRequest
      或 org.springframework.web.context.request.nativeWebRequest

    • java.util.Locale

    • java.io.InputStream 或 java.io.Reader

    • java.io.OutputStream 或 java.io.Writer

    • java.security.Principal

    • HttpEntity<?>

    • java.util.Map 或 org.springframework.ui.Model

    • org.springframework.ui.ModelMap

    • org.springframework.web.servlet.mvc.support.RedirectAttributes

    • org.springframework.validation.Errors

    • org.springframework.validation.BindingResult

    • 命令或表單對象

    • org.springframework.web.util.UriCompontsBuilder

    • org.springframework.web.util.UriComponentsBuilder

    • 帶@PathVariable, @MatrixVariable注釋的對象

    • @RequestParam, @RequestHeader, @RequestBody 或 @RequestPart

    特別重要的是org.springframework.ui.Model類型不是一個(gè)Servlet API類型,而是一個(gè)包涵Map的Spring MVC類型。每次調(diào)用請求處理方法時(shí),Spring MVC都創(chuàng)建Model對象將其Map注入到各種對象。

    請求處理方法可以返回如下類型的對象:

    • ModelAndView

    • Model

    • Map包含模型的屬性

    • View

    • 代表邏輯視圖名的String

    • void

    • 提供對Servlet的訪問。以相應(yīng)HTTP頭部和內(nèi)容HttpEntity或ResponseEntity對象

    • Callable

    • DeferredResult

    • 其他任意類型,Spring將其視作輸出給View的對象模型


    應(yīng)用基于注解的控制器

    該處的示例是對前面幾篇博文的重寫,區(qū)別于前幾篇博文中的示例在于

    • 控制器類中增加了@Controller注解
    • Spring配置文件增加了部分元素,下面詳解

    目錄結(jié)構(gòu)

    maven工程結(jié)構(gòu)如上,在這里,只有一個(gè)控制器類,而不是之前示例中的兩個(gè)。

    同時(shí)增加了一個(gè)名為index.html的靜態(tài)文件,以便Spring MVC Servlet的URL模式設(shè)置為”/”時(shí),依然可以訪問靜態(tài)資源


    配置文件

    兩個(gè)配置文件,第一個(gè)為部署描述符(web.xml文件)中注冊Spring MVC的DispatcherServlet ,第二個(gè)Spring MVC的配置文件 springmvc-config.xml

    web.xml

    <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/config/springmvc-config.xml</param-value></init-param><load-on-startup>1</load-on-startup> </servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping> </web-app>

    在部署描述符中servlet-mapping元素中url-pattern設(shè)置為 / ,而不是之前實(shí)例中的action。 實(shí)際上映射動(dòng)作不必一定是要用某種URL擴(kuò)展。

    當(dāng)然,當(dāng)URL設(shè)置為/,意味著所有的請求( 包括那些靜態(tài)資源)都被映射到DispatcherServlet, 為了正確的處理靜態(tài)資源,就必須要在Spring MVC的配置文件中添加一些 resouce元素。


    springmvc-config.xml

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.artisan.springmvc.controller"/><mvc:annotation-driven/><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/*.html" location="/"/><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean> </beans>

    Spring MVC配置文件中最重要的是context:component-scan元素,這是要告訴SpringMVC掃描目標(biāo)包中的類。

    接下來是一個(gè)mvc:annotation-driven和兩個(gè)mvc:resources。

    • mvc:annotation-driven元素做的事情內(nèi)包括注冊用于支持基于注解的控制器的請求處理方法的bean對象

    • mvc:resources元素用于指示Spring MVC 哪些靜態(tài)資源需要單獨(dú)處理,即不通過Dispatcher Servlet

    在這個(gè)示例中,第一個(gè)resources元素確保/css目錄下的所有文件可見
    第二個(gè)允許顯示所有的.html文件

    注意:如果沒有annotation-driven,resources元素會阻止任意控制器被調(diào)用,如果不需要使用resources,則不需要annotation-driven元素


    Controller類

    使用Controller注釋類型的一個(gè)優(yōu)點(diǎn)在于:一個(gè)控制器類可以包含多個(gè)請求處理方法

    package com.artisan.springmvc.controller;import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;import com.artisan.springmvc.domain.Product; import com.artisan.springmvc.form.ProductForm;@Controller public class ProductController {private static final Log logger = LogFactory.getLog(ProductController.class);@RequestMapping(value="/product_input")public String inputProduct() {logger.info("inputProduct called");return "ProductForm";}@RequestMapping(value="/product_save")public String saveProduct(ProductForm productForm, Model model) {logger.info("saveProduct called");// no need to create and instantiate a ProductForm// create ProductProduct product = new Product();product.setName(productForm.getName());product.setDescription(productForm.getDescription());try {product.setPrice(Float.parseFloat(productForm.getPrice()));} catch (NumberFormatException e) {}// add productmodel.addAttribute("product", product);return "ProductDetails";} }

    其中,ProductController#saveProduct()方法的第二個(gè)入?yún)?

    public String saveProduct(ProductForm productForm, Model model)

    無論是否會使用,SpringMVC都會在每一個(gè)請求處理方法被調(diào)用時(shí)創(chuàng)建一個(gè)Model實(shí)例,用于增加需要顯示在視圖中的屬性,例如通過調(diào)用model.addAttribute("product", product);來添加Product實(shí)例。這樣Product實(shí)例就可以被添加到HttpServletRequestt中那樣訪問了。


    View

    ProductForm.jsp

    <!DOCTYPE HTML> <html> <head> <title>Add Product Form</title> <style type="text/css">@import url(css/main.css);</style> </head> <body><div id="global"> <form action="product_save" method="post"><fieldset><legend>Add a product</legend><p><label for="name">Product Name: </label><input type="text" id="name" name="name" tabindex="1"></p><p><label for="description">Description: </label><input type="text" id="description" name="description" tabindex="2"></p><p><label for="price">Price: </label><input type="text" id="price" name="price" tabindex="3"></p><p id="buttons"><input id="reset" type="reset" tabindex="4"><input id="submit" type="submit" tabindex="5" value="Add Product"></p></fieldset> </form> </div> </body> </html>

    ProductDetails.jsp

    <!DOCTYPE HTML> <html> <head> <title>Save Product</title> <style type="text/css">@import url(css/main.css);</style> </head> <body> <div id="global"><h4>The product has been saved.</h4><p><h5>Details:</h5>Product Name: ${product.name}<br/>Description: ${product.description}<br/>Price: $${product.price}</p> </div> </body> </html>

    測試應(yīng)用

    http://localhost:8080/chapter04a/product_input

    輸入對應(yīng)的表格

    提交后
    http://localhost:8080/chapter04a/product_save
    調(diào)用saveProduct方法


    使用@Autowired和@Service進(jìn)行依賴注入

    使用Spring框架的一個(gè)好處是容易進(jìn)行依賴注入,將依賴注入到Spring MVC控制器的最簡單的方法是通過注解@Autowired到字段或者方法。Autowired注解類型屬于org.springframework.beans.factory.annotation包

    分兩步

  • 在配置文件中添加context:component-scan元素掃描依賴基本包

  • 標(biāo)注注解,如果是服務(wù)層,標(biāo)注@Service

  • 我們新建個(gè)maven工程來演示該功能

    首先我們先看下Controller類

    package com.artisan.springmvc.controller;import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.artisan.springmvc.domain.Product; import com.artisan.springmvc.form.ProductForm; import com.artisan.springmvc.service.ProductService;@Controller public class ProductController {private static final Logger logger = Logger.getLogger(ProductController.class);@Autowiredprivate ProductService productService;@RequestMapping(value = "/product_input")public String inputProduct() {logger.info("inputProduct called ....");return "ProductForm";}@RequestMapping(value = "/product_save", method = RequestMethod.POST)public String saveProduct(ProductForm productForm, RedirectAttributes attributes) {logger.info("saveProduct called ....");// no need to create and instantiate a ProductForm// create ProductProduct product = new Product();product.setName(productForm.getName());product.setDescription(productForm.getDescription());try {product.setPrice(Float.parseFloat(productForm.getPrice()));} catch (NumberFormatException e) {}// add productProduct savedProduct = productService.add(product);attributes.addFlashAttribute("message", "The product has been saved successfully");return "redirect:/product_view/" + savedProduct.getId();}/*** * @param id* @param model* @return* @PathVariable用來獲得請求url中的動(dòng)態(tài)參數(shù)*/@RequestMapping(value = "/product_view/{id}")public String getProductById(@PathVariable Long id, Model model) {logger.info("getProductById called ....");Product product = productService.get(id);model.addAttribute("product", product);return "ProductView";}}

    該P(yáng)roductController類與上個(gè)例子中的ProductController類相比,做了一些調(diào)整

    1. 首先自動(dòng)注入了ProductService ,加了@AutoWired注解

    private ProductService productService;public ProductService getProductService() {return productService;}@Autowiredpublic void setProductService(ProductService productService) {this.productService = productService;}

    或者

    @Autowired private ProductService productService;

    productService是一個(gè)提供跟蹤處理產(chǎn)品方法的接口,為productService字段或者set方法注入@Autowired會使ProductService的一個(gè)實(shí)例被注入到ProductController實(shí)例中。

    為了使類能夠被Spring掃描到,必須要標(biāo)注@Service

    ProductService接口

    package com.artisan.springmvc.service;import com.artisan.springmvc.domain.Product;public interface ProductService {Product add(Product product);Product get(long id); }

    ProductServiceImpl類

    package com.artisan.springmvc.service;import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong;import org.springframework.stereotype.Service;import com.artisan.springmvc.domain.Product; /*** * @author Mr.Yang* 標(biāo)注了@Service的服務(wù)層**/ @Service public class ProductServiceImpl implements ProductService {private Map<Long, Product> products = new HashMap<Long, Product>();// 使用AtomicLong能讓long的操作在多線程下保持原子型private AtomicLong generator = new AtomicLong();public ProductServiceImpl() {Product product = new Product();add(product);}@Overridepublic Product add(Product product) {long newId = generator.incrementAndGet();product.setId(newId);products.put(newId, product);return product;}@Overridepublic Product get(long id) {return products.get(id);} }

    2. 然后在SpringMVC配置文件中有兩個(gè)component-scan元素,一個(gè)是用于掃描控制器類,另一個(gè)新增加的為掃描服務(wù)類

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.artisan.springmvc.controller"/><context:component-scan base-package="com.artisan.springmvc.service"/><mvc:annotation-driven/><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/*.html" location="/"/><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/></bean> </beans>

    重定向和Flash屬性

    經(jīng)常寫Servlet/JSP的童鞋都知道轉(zhuǎn)發(fā)和重定向的區(qū)別

    轉(zhuǎn)發(fā)比重定向要快,因?yàn)檗D(zhuǎn)發(fā)不經(jīng)過客戶端,而重定向會經(jīng)過客戶端。但是有時(shí)候采用重定向會更好,比如需要重定向到一個(gè)外部網(wǎng)站,則無法使用轉(zhuǎn)發(fā)

    另外一個(gè)使用重定向的場景是避免在用戶重新加載頁面的時(shí)候再次調(diào)用相同的動(dòng)作 ,比如,這個(gè)示例中, 當(dāng)提交產(chǎn)品表單時(shí),saveProduct方法會被調(diào)用,并執(zhí)行相應(yīng)的動(dòng)作。在真實(shí)應(yīng)用中,這些所述產(chǎn)品會加入到數(shù)據(jù)庫中。但是如果提交表單后重新加載頁面,saveProduct會被再此調(diào)用,同樣的產(chǎn)品可能被再此添加。為了避免這種情況,提交表單后,你可能更愿意將用戶重定向到一個(gè)不同的頁面。這個(gè)網(wǎng)頁任意加載都沒有副作用。我們這個(gè)示例中,提交表單后,將用戶重定向到一個(gè)ViewProduct頁面.

    在這個(gè)示例中,ProductController#saveProduct方法 返回

    return "redirect:/product_view/" + savedProduct.getId();

    這里使用重定向,而不是轉(zhuǎn)發(fā)來防止當(dāng)用戶重新加載頁面時(shí),saveProduct被二次調(diào)用。


    使用重定向有個(gè)不方便的地方:無法輕松的傳值給目標(biāo)頁面,而轉(zhuǎn)發(fā)則可以簡單的將屬性添加到Model中,使目標(biāo)頁面輕松訪問。由于重定向經(jīng)過客戶端,所以Model中的一切都在重定向時(shí)丟失了。 幸運(yùn)的是Spring3.1版本及更高的版本通過Flash屬性提供了一種重定向傳值的方法

    要使用Flash屬性,必須在Spring MVC的配置文件中有一個(gè)<mvc:annotation-driven/>元素,然后,還必須在方法上添加一個(gè)新的參數(shù)類型 org.springframework.web.servlet.mvc.support.RedirectAttributes

    如下所示


    請求參數(shù)和路徑變量

    獲取請求參數(shù)

    請求參數(shù)和路徑變量都可以用于發(fā)送值給服務(wù)器,二者都是URL的一部分。 請求參數(shù)采用key=value形式,并用&分割。

    比如

    http://localhost:8080/chapter04b/productRetrive?productId=5

    在傳統(tǒng)的Servlet編程中,可以使用HttpServletRequest的getParameter方法來獲取一個(gè)請求參數(shù)值

    String productId=httpServletRequest.getParameter("productId");

    Spring MVC則提供了一個(gè)更簡單的方法來獲取請求參數(shù)的值:org.springframework.web.bind.annotation.RequestParam注釋類型來獲取注釋方法參數(shù),比如

    public void sendProduct(@RequestParam int productId)

    正如所示,@RequestParam注解的參數(shù)類型不一定是字符串。


    獲取路徑變量

    路徑變量類似請求參數(shù),但是沒有key部分,只有一個(gè)值, 比如我們這個(gè)示例中 product_view動(dòng)作映射到如下URL

    /product_view/productId

    其中productId表示產(chǎn)品標(biāo)識符的整數(shù)。在SpringMVC中,productId被稱作路徑變量,用來發(fā)送一個(gè)值到服務(wù)器

    接下來我們看下viewProduct方法演示了一個(gè)路徑變量的使用

    /*** * @param id* @param model* @return* @PathVariable用來獲得請求url中的動(dòng)態(tài)參數(shù)*/@RequestMapping(value = "/product_view/{id}")public String viewProduct(@PathVariable Long id, Model model) {logger.info("getProductById called ....");Product product = productService.get(id);model.addAttribute("product", product);return "ProductView";}

    為了使用路徑變量,首先需要在RequestMapping注解的值屬性中添加一個(gè)變量,該變量必須放在花括號之間,例如下面的RequestMapping注解定義一個(gè)名為id的路徑變量

    @RequestMapping(value = "/product_view/{id}")

    然后在方法簽名中添加一個(gè)同名變量,并添加上@PathVariable注解。 當(dāng)viewProduct方法別調(diào)用時(shí),請求URL的id值將被復(fù)制到路徑變量中,并可以在方法中使用。 路徑變量的類型可以不是字符串,Spring MVC將盡量轉(zhuǎn)換為非字符串類型,這個(gè)強(qiáng)大的功能,后續(xù)在數(shù)據(jù)綁定和表單參數(shù)中詳解。

    可以在請求映射中使用多個(gè)路徑變量,比如userId和orderId兩個(gè)路徑變量

    @RequestMapping(value="/produtc_view/{userId}/{orderId}")

    直接在瀏覽器中輸入U(xiǎn)RL,來測試viewProduct方法的路徑變量

    http://localhost:8080/chapter04b/product_view/5

    使用路徑變量有可能出現(xiàn)的問題

    有時(shí)候,使用路徑變量會遇到一個(gè)小問題:在某些情況下,瀏覽器可能會誤解路徑變量。 考慮下面的URL

    http://example.com/context/abc

    瀏覽器會(正確)認(rèn)為abc是一個(gè)動(dòng)作。 任何靜態(tài)文件路徑的解析,比如css文件,將使用http://example.com/context作為基本路徑。

    這就是說,若服務(wù)器發(fā)送的網(wǎng)頁包含如下img元素 <img src='logo.png'/>,改瀏覽器將試圖通過http://example.com/context/logo.png來加載logo.png

    然而,若一個(gè)應(yīng)用程序被部署為默認(rèn)上線文(默認(rèn)上下文是一個(gè)空字符串),則對于同一個(gè)目標(biāo)的URL,會是這樣

    http://example.com/abc

    下面是帶有路徑變量的URL

    http://example.com/abc/1

    這種情況下,瀏覽器會認(rèn)為abc是上下文,沒有動(dòng)作。 如果在頁面中使用<img src='logo.png'/>,瀏覽器將試圖通過http://example.com/abc/logo.png來尋找圖片,并且它將找不到圖片。

    幸運(yùn)的是,我們有個(gè)簡單的解決方法,即通過JSTL標(biāo)記的URL。 標(biāo)簽會通過正確解析URL來修復(fù)該問題。

    比如我們該案例中的css加載

    <style type="text/css">@import url(css/main.css);</style>

    改為

    <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style>

    若程序部署為默認(rèn)的上下文,鏈接標(biāo)簽會將改URL轉(zhuǎn)換成如下形式

    <style type="text/css">@import url(css/main.css);</style>

    若程序不在默認(rèn)上下文中,則會被轉(zhuǎn)換為

    <style type="text/css">@import url("<c:url value="/chapter04b/css/main.css"/>");</style>

    我們這個(gè)示例中的上下文為chapter04b , 通過f12查看如下方式加載css
    http://localhost:8080/chapter04b/css/main.css

    如果寫成@import url(css/main.css);將加載不到css的樣式。


    @ModelAttribute

    前面講到Spring MVC在每次調(diào)用請求處理方法時(shí),都會創(chuàng)建Model類型的一個(gè)實(shí)例。若打算使用該實(shí)例,則可以在方法中添加一個(gè)Model類型的參數(shù)。事實(shí)上還可以使用在方法中添加ModelAttribute注釋類型來訪問Model實(shí)例。 該注釋類型也是org.springframework.web.bind.annotation包的成員。


    @ModelAttribute的第一個(gè)用途

    可以用@ModelAttribute來注釋方法參數(shù)或者方法。

    帶@ModelAttribute注解的方法會將其輸入的或創(chuàng)建的參數(shù)對象添加到Model對象中(若方法中沒有顯式添加)。

    比如,Spring MVC將在每次調(diào)用submitOrder方法時(shí)創(chuàng)建一個(gè)Order實(shí)例

    @RequestMapping(value="/submitOrder",method=RequestMethod.Post) public String submitOrder(@ModelAttribute("newOrder") Order order,Model model){... }

    輸入或者創(chuàng)建的Order實(shí)例將用newOrder鍵值添加到Model對象中,如果未定義鍵值名,則使用該對象類型的名稱。

    比如,每次調(diào)用如下方法,會使用鍵值order將Order實(shí)例添加到Model對象中

    @RequestMapping(value="/submitOrder",method=RequestMethod.Post) public String submitOrder(@ModelAttribute Order order,Model model){... }

    @ModelAttribute的第二個(gè)用途

    @ModelAttribute的第二個(gè)用途是標(biāo)注一個(gè)非請求的處理方法。 被@ModelAttribute注釋的方法會在每次調(diào)用該控制器類的請求處理方法時(shí)被調(diào)用。

    這就意味著,如果一個(gè)控制器類有兩個(gè)請求處理方法,以及一個(gè)帶有@ModelAttribute注解的方法,該方法的調(diào)用次數(shù)就會比每個(gè)處理請求方法更加頻繁。

    Spring MVC會在調(diào)用請求處理方法之前調(diào)用帶有@ModelAttribute注解的方法,帶@ModelAttribute注解的方法可以返回一個(gè)對象或者一個(gè)void類型,

    如果返回一個(gè)對象,則返回對象會自動(dòng)添加到Model中

    @ModelAttribute public Product addProduct(@RequestParam String productId){return productService.get(produtId) }

    若返回的是void,這還必須添加一個(gè)Model類型的參數(shù),并自行將實(shí)例添加到Model中

    @ModelAttribute public void populateModel(@RequestParam String id,Model model){model.addAttribute(new Account(id)); }

    總結(jié)

    這里介紹了如何編寫基于注解的控制器的Spring MVC應(yīng)用,也講解了各種注解類、方法或者方法的參數(shù)的注釋類型

    總結(jié)

    以上是生活随笔為你收集整理的Spring MVC-04循序渐进之基于注解的控制器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。