• 概述
  • Spring MVC注解类型
    • Controller注解类型
    • RequestMapping注解类型
      • value属性
      • 其他属性
  • 编写请求处理方法
  • 应用基于注解的控制器
    • 目录结构
    • 配置文件
    • Controller类
    • View
    • 测试应用
  • 使用@Autowired和@Service进行依赖注入
  • 重定向和Flash属性
  • 请求参数和路径变量
    • 获取请求参数
    • 获取路径变量
    • 使用路径变量有可能出现的问题
  • @ModelAttribute
    • @ModelAttribute的第一个用途
    • @ModelAttribute的第二个用途
  • 总结

概述

Spring MVC-03循序渐进之Spring MVC中我们介绍了传统的开发方式,其弊端Controller接口实现类只能处理一个单一动作,本篇博文我们来介绍下基于注解的控制器。


Spring MVC注解类型

基于注解的控制器优点如下:

  1. 一个控制器可以处理多个请求动作,而一个实现了Controller接口的控制器只能处理一个动作

  2. 基于注解的控制器的请求映射不需要存储在配置文件中,使用RequestMapping注解类型,可以对一个方法进行请求处理。

Controller和RequestMapping注解类型是SpringMVC API最重要的两个注释类型,当然了我们这里也会介绍其他一些注解类型


Controller注解类型

org.springframework.stereotype.Controller注解类型用于指示Spring类的实例是一个控制器。

下面是一个带有@Controller注解的例子

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

Spring使用注解扫描的方式来找到应用中所有基于注解的控制器类,为了确保Spring能扫描到你的控制器,需要完成两件事情

  1. 在Spring MVC配置文件中声明spring-context及指定schema
  2. 然后配置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"/><!--......省略其他配置项---></beans>

确保所有控制器类都在基本包下,并且不要指定一个太宽泛的基本包,这样会使Spring扫描了无关的包。


RequestMapping注解类型

现在我们需要在控制器类内部为每一个动作开发相应的处理方法,要让Spring知道哪一种方法来处理它的动作,需要使用org.springframework.web.bind.annotation.RequestMapping注解类型映射的URL与方法。

RequestMapping注释类型的作用:映射一个请求和一种方法,可以使用@RequestMapping注释一种方法或者一个类

一个采用了@RequestMapping注解的方法将成为一个请求处理方法,并由调度程序在接收到对应的URL请求时调用

下面是一个@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注解的默认属性,如果只有唯一的属性,则可以省略属性名称。换句话说

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

效果是等同的,但是如果超过一个属性时,就必须要输入value属性名称。

请求映射的值可以是一个空字符,此时该方法被映射到如下网址 http://domain/context

其他属性

RequestMapping除了具有value属性,还有其他属性。比如method属性用来指示改方法仅处理哪些HTTP方法. 当method为多个值时,后面写为数组{method1, method2}

例如只有在HTTP POST或者PUT方法时才能访问到下面的方法

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

如果method属性仅有一个HTTP方法值,则不需要花括号

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

如果没有指定method属性值,则请求处理方法可以处理任意HTTP方法。


此外RequestMapping注释类型也可以用来注释一个控制器类

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

编写请求处理方法

每个请求处理方法可以有多个不同类型的参数,以及一个多钟类型的返回结果。

比如在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确传递给方法

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

或者,如果需要访问客户端环境和HttpServletRequest,则可以在方法签名上包括这样的参数

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

每个请求处理方法可以有多个不同类型的参数,下面时可以在请求处理方法中出现的参数类型:

  • 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类型不是一个Servlet API类型,而是一个包涵Map的Spring MVC类型。每次调用请求处理方法时,Spring MVC都创建Model对象将其Map注入到各种对象

请求处理方法可以返回如下类型的对象:

  • ModelAndView

  • Model

  • Map包含模型的属性

  • View

  • 代表逻辑视图名的String

  • void

  • 提供对Servlet的访问。以相应HTTP头部和内容HttpEntity或ResponseEntity对象

  • Callable

  • DeferredResult

  • 其他任意类型,Spring将其视作输出给View的对象模型


应用基于注解的控制器

该处的示例是对前面几篇博文的重写,区别于前几篇博文中的示例在于

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

目录结构

maven工程结构如上,在这里,只有一个控制器类,而不是之前示例中的两个。

同时增加了一个名为index.html的静态文件,以便Spring MVC Servlet的URL模式设置为”/”时,依然可以访问静态资源


配置文件

两个配置文件,第一个为部署描述符(web.xml文件)中注册Spring MVC的DispatcherServlet ,第二个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设置为 / ,而不是之前实例中的action。 实际上映射动作不必一定是要用某种URL扩展。

当然,当URL设置为/,意味着所有的请求( 包括那些静态资源)都被映射到DispatcherServlet, 为了正确的处理静态资源,就必须要在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扫描目标包中的类。

接下来是一个mvc:annotation-driven和两个mvc:resources。

  • mvc:annotation-driven元素做的事情内包括注册用于支持基于注解的控制器的请求处理方法的bean对象

  • mvc:resources元素用于指示Spring MVC 哪些静态资源需要单独处理,即不通过Dispatcher Servlet

在这个示例中,第一个resources元素确保/css目录下的所有文件可见
第二个允许显示所有的.html文件

注意:如果没有annotation-driven,resources元素会阻止任意控制器被调用,如果不需要使用resources,则不需要annotation-driven元素


Controller类

使用Controller注释类型的一个优点在于:一个控制器类可以包含多个请求处理方法

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()方法的第二个入参

  public String saveProduct(ProductForm productForm, Model model) 

无论是否会使用,SpringMVC都会在每一个请求处理方法被调用时创建一个Model实例,用于增加需要显示在视图中的属性,例如通过调用model.addAttribute("product", product);来添加Product实例。这样Product实例就可以被添加到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>

测试应用

http://localhost:8080/chapter04a/product_input

输入对应的表格

提交后
http://localhost:8080/chapter04a/product_save
调用saveProduct方法


使用@Autowired和@Service进行依赖注入

使用Spring框架的一个好处是容易进行依赖注入,将依赖注入到Spring MVC控制器的最简单的方法是通过注解@Autowired到字段或者方法。Autowired注解类型属于org.springframework.beans.factory.annotation包

分两步

  1. 在配置文件中添加context:component-scan元素扫描依赖基本包

  2. 标注注解,如果是服务层,标注@Service

我们新建个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中的动态参数*/@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";}}

该ProductController类与上个例子中的ProductController类相比,做了一些调整

1. 首先自动注入了ProductService ,加了@AutoWired注解

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

或者

@Autowired
private ProductService productService;

productService是一个提供跟踪处理产品方法的接口,为productService字段或者set方法注入@Autowired会使ProductService的一个实例被注入到ProductController实例中。

为了使类能够被Spring扫描到,必须要标注@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* 标注了@Service的服务层**/
@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配置文件中有两个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: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属性

经常写Servlet/JSP的童鞋都知道转发和重定向的区别

转发比重定向要快,因为转发不经过客户端,而重定向会经过客户端。但是有时候采用重定向会更好,比如需要重定向到一个外部网站,则无法使用转发

另外一个使用重定向的场景是避免在用户重新加载页面的时候再次调用相同的动作 ,比如,这个示例中, 当提交产品表单时,saveProduct方法会被调用,并执行相应的动作。在真实应用中,这些所述产品会加入到数据库中。但是如果提交表单后重新加载页面,saveProduct会被再此调用,同样的产品可能被再此添加。为了避免这种情况,提交表单后,你可能更愿意将用户重定向到一个不同的页面。这个网页任意加载都没有副作用。我们这个示例中,提交表单后,将用户重定向到一个ViewProduct页面.

在这个示例中,ProductController#saveProduct方法 返回

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

这里使用重定向,而不是转发来防止当用户重新加载页面时,saveProduct被二次调用。


使用重定向有个不方便的地方:无法轻松的传值给目标页面,而转发则可以简单的将属性添加到Model中,使目标页面轻松访问。由于重定向经过客户端,所以Model中的一切都在重定向时丢失了。 幸运的是Spring3.1版本及更高的版本通过Flash属性提供了一种重定向传值的方法

要使用Flash属性,必须在Spring MVC的配置文件中有一个<mvc:annotation-driven/>元素,然后,还必须在方法上添加一个新的参数类型 org.springframework.web.servlet.mvc.support.RedirectAttributes

如下所示


请求参数和路径变量

获取请求参数

请求参数和路径变量都可以用于发送值给服务器,二者都是URL的一部分。 请求参数采用key=value形式,并用&分割。

比如

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

在传统的Servlet编程中,可以使用HttpServletRequest的getParameter方法来获取一个请求参数值

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

Spring MVC则提供了一个更简单的方法来获取请求参数的值:org.springframework.web.bind.annotation.RequestParam注释类型来获取注释方法参数,比如

public void sendProduct(@RequestParam int productId)

正如所示,@RequestParam注解的参数类型不一定是字符串。


获取路径变量

路径变量类似请求参数,但是没有key部分,只有一个值, 比如我们这个示例中 product_view动作映射到如下URL

/product_view/productId

其中productId表示产品标识符的整数。在SpringMVC中,productId被称作路径变量,用来发送一个值到服务器

接下来我们看下viewProduct方法演示了一个路径变量的使用

/*** * @param id* @param model* @return* @PathVariable用来获得请求url中的动态参数*/@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注解的值属性中添加一个变量,该变量必须放在花括号之间,例如下面的RequestMapping注解定义一个名为id的路径变量

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

然后在方法签名中添加一个同名变量,并添加上@PathVariable注解。 当viewProduct方法别调用时,请求URL的id值将被复制到路径变量中,并可以在方法中使用。 路径变量的类型可以不是字符串,Spring MVC将尽量转换为非字符串类型,这个强大的功能,后续在数据绑定和表单参数中详解。

可以在请求映射中使用多个路径变量,比如userId和orderId两个路径变量

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

直接在浏览器中输入URL,来测试viewProduct方法的路径变量

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

使用路径变量有可能出现的问题

有时候,使用路径变量会遇到一个小问题:在某些情况下,浏览器可能会误解路径变量。 考虑下面的URL

http://example.com/context/abc

浏览器会(正确)认为abc是一个动作。 任何静态文件路径的解析,比如css文件,将使用http://example.com/context作为基本路径。

这就是说,若服务器发送的网页包含如下img元素 <img src='logo.png'/>,改浏览器将试图通过http://example.com/context/logo.png来加载logo.png

然而,若一个应用程序被部署为默认上线文(默认上下文是一个空字符串),则对于同一个目标的URL,会是这样

http://example.com/abc

下面是带有路径变量的URL

http://example.com/abc/1

这种情况下,浏览器会认为abc是上下文,没有动作。 如果在页面中使用<img src='logo.png'/>,浏览器将试图通过http://example.com/abc/logo.png来寻找图片,并且它将找不到图片。

幸运的是,我们有个简单的解决方法,即通过JSTL标记的URL。 标签会通过正确解析URL来修复该问题。

比如我们该案例中的css加载

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

改为

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

若程序部署为默认的上下文,链接标签会将改URL转换成如下形式

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

若程序不在默认上下文中,则会被转换为

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

我们这个示例中的上下文为chapter04b , 通过f12查看如下方式加载css
http://localhost:8080/chapter04b/css/main.css

如果写成@import url(css/main.css);将加载不到css的样式。


@ModelAttribute

前面讲到Spring MVC在每次调用请求处理方法时,都会创建Model类型的一个实例。若打算使用该实例,则可以在方法中添加一个Model类型的参数。事实上还可以使用在方法中添加ModelAttribute注释类型来访问Model实例。 该注释类型也是org.springframework.web.bind.annotation包的成员。


@ModelAttribute的第一个用途

可以用@ModelAttribute来注释方法参数或者方法。

带@ModelAttribute注解的方法会将其输入的或创建的参数对象添加到Model对象中(若方法中没有显式添加)。

比如,Spring MVC将在每次调用submitOrder方法时创建一个Order实例

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

输入或者创建的Order实例将用newOrder键值添加到Model对象中,如果未定义键值名,则使用该对象类型的名称。

比如,每次调用如下方法,会使用键值order将Order实例添加到Model对象中

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

@ModelAttribute的第二个用途

@ModelAttribute的第二个用途是标注一个非请求的处理方法。 被@ModelAttribute注释的方法会在每次调用该控制器类的请求处理方法时被调用。

这就意味着,如果一个控制器类有两个请求处理方法,以及一个带有@ModelAttribute注解的方法,该方法的调用次数就会比每个处理请求方法更加频繁。

Spring MVC会在调用请求处理方法之前调用带有@ModelAttribute注解的方法,带@ModelAttribute注解的方法可以返回一个对象或者一个void类型,

如果返回一个对象,则返回对象会自动添加到Model中

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

若返回的是void,这还必须添加一个Model类型的参数,并自行将实例添加到Model中

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

总结

这里介绍了如何编写基于注解的控制器的Spring MVC应用,也讲解了各种注解类、方法或者方法的参数的注释类型

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

  1. spring 基于注解的控制器配置

    http://ttaale.iteye.com/blog/787586 spring 基于注解的控制器配置 博客分类: spring SpringBeanServletMVCWeb 13.12. 基于 ...

  2. Spring MVC中@Controller和@RequestMapping注解详解

    在<第一个Spring MVC应用>教程中创建了两个传统风格的控制器,它们是实现 Controller 接口的类.传统风格的控制器不仅需要在配置文件中部署映映射,而且只能编写一个处理方法, ...

  3. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  4. spring IOC容器 Bean 管理——基于注解方式

    IOC 操作 Bean 管理(基于注解方式) 1.什么是注解 ​ (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值-) ​ (2)使用注解,注解作用在类上面,方法上面, ...

  5. java spring多数据源配置文件_基于注解实现SpringBoot多数据源配置

    1.功能介绍 在实际的开发中,同一个项目中使用多个数据源是很常见的场景.最近在学习的过程中使用注解的方式实现了一个Springboot项目多数据源的功能.具体实现方式如下. 2.在applicatio ...

  6. Spring MCV基于注解的控制器

    一 Controller类的实现 package org.fkit.controller; import org.springframework.stereotype.Controller; impo ...

  7. Spring MVC零配置(全注解)(版本5.0.7)

    // 核心配置类 package spittr.config;import org.springframework.web.servlet.support.AbstractAnnotationConf ...

  8. java mvc 绑定_关于Java:Spring MVC:将请求属性绑定到控制器方法参数

    在Spring MVC中,很容易将请求参数绑定到处理请求的方法参数. 我只是使用@RequestParameter("name"). 但是我可以对request属性做同样的事情吗? ...

  9. spring mvc DispatcherServlet详解之前传---前端控制器架构

    前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现 ...

最新文章

  1. 腾腾流氓,云云更流氓(问微信怎样接入支付宝支付),手贱的赶紧点,你会感谢我的...
  2. 【转】一句话的设计模式
  3. spi总线 上层调用_spi总线设备驱动分析
  4. .net 反编译_向.net/Unity 程序员推荐一个十分因吹斯听的网站:sharplab.io
  5. 设计一个安全对外的API接口,需要考虑哪些方面?
  6. Linux下redis基本安装配置(CentOS7)
  7. java程序设计比赛心得体会_对Java程序设计的感想.doc
  8. JS9 -- switch
  9. Matlab实现光栅实验
  10. 蓝桥杯和noip都考C语言么,为什么NOIP信息学奥赛C++普及组师资匮乏
  11. win10系统显示打印机未连接到服务器,win10系统连接打印机提示“打印处理器不存在”如何解决...
  12. 创新工场和海豚浏览器宣讲会启示
  13. 算法竞赛入门经典 每日一题(郊区春游)
  14. selenium+python爬取简书文章
  15. Unit 2: Linux/Unix Acquisition 2.1 Linux/Unix Acquistion Memory Acquisition
  16. 大数据技术之Ranger
  17. 语音基础知识和处理流程(TTS小白入门)
  18. 这个PDF转换成Word的技巧,100%让你相见恨晚
  19. 永磁同步电机滞环电流控制
  20. 北京大学计算机专业考研试题,2017年北京大学计算机辅助翻译考研专业课真题(回忆版)...

热门文章

  1. 选择排序的基本原理及实现
  2. jquery~ajax()学习
  3. 什么是pretext tasks?
  4. python笔记:深拷贝与浅拷贝
  5. SPSS实战应用案例50篇(一):从SPSS的角度讲清楚卡方检验
  6. 还在埋头写论文?知网检索的这些小技巧让你有如神助!
  7. tableau必知必会之妙用 Lookup 函数同时跨行跨列取数
  8. BI工具和数据中台有什么区别?数据中台初探
  9. SVM在R语言中的使用
  10. 主成分分析 PCA算法