Spring:注解驱动MVC

来源:互联网 发布:软件的需求报告 编辑:程序博客网 时间:2024/04/28 11:24

1、web.xml 启动spring容器和spring MVC

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_2_5.xsd" version="2.5">
  <display-name>Spring Annotation MVC Sample</display-name>
  <!-- Spring 服务层的配置文件 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!-- Spring 容器启动监听器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
  <!-- Spring MVC 的Servlet,它将加载WEB-INF/annomvc-servlet.xml 的 
  配置文件,以启动Spring MVC模块-->
  <servlet>
    <servlet-name>annomvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet 
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>annomvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

 

 

web.xml 中定义了一个名为 annomvc 的 Spring MVC 模块,如果没有特别指定,需要在 WEB-INF目录下创建一个与servlet名字相同的配置文件annomvc-servlet.xml。 配置文件中定义 Spring MVC 模块的具体配置

<?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:context="http://www.springframework.org/schema/context" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  <!-- ①:对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
  
<context:component-scan base-package="com.baobaotao.web"/>
  <!-- ②:启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
  <mvc:annotation-driven/>   

   <!-- ③:对模型视图名称的解析,即在模型视图名称添加前后缀 -->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
    p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
</beans>

 

2、@RequestMapping专题

映射url请求

对于处理多个 URL 请求的 Controller 来说,我们倾向于通过一个 URL 参数指定 Controller 处理方法的名称(如 method=listAllBoard),而非直接通过不同的 URL 指定 Controller 的处理方法。

 

@Controller
@RequestMapping("/bbtForum.do") // <—— ① 指定控制器对应URL请求 
public class BbtForumController {
  @Autowired
  private BbtForumService bbtForumService;
  // <—— ② 如果URL请求中包括"method=listAllBoard"的参数,由本方法进行处理 
  
@RequestMapping(params = "method=listAllBoard")
  public String listAllBoard() {
    bbtForumService.getAllBoard();
    System.out.println("call listAllBoard method.");
    return "listBoard";
  }
  // <—— ③ 如果URL请求中包括"method=listBoardTopic"的参数,由本方法进行处理 
  
@RequestMapping(params = "method=listBoardTopic")
  public String listBoardTopic(int topicId) {
    bbtForumService.getBoardTopics(topicId);
    System.out.println("call listBoardTopic method.");
    return "listTopic";
  }
}

 

@RequestMapping 注解中除了 params 属性外,还有一个常用的属性是 method,它可以让 Controller 方法处理特定 HTTP 请求方式的请求

@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController {
  @RequestMapping(params = "method=createTopic",method = RequestMethod.POST)
  public String createTopic(){
    System.out.println("call createTopic method.");
    return "createTopic";
  }
}

 

处理方法入参如何绑定 URL 参数

Spring 在如何给处理方法入参自动赋值以及如何将处理方法返回值转化为 ModelAndView 中的过程中存在一套潜在的规则,不熟悉这个规则就不可能很好地开发基于注解的请求处理方法,因此了解这个潜在规则无疑成为理解 Spring MVC 框架基于注解功能的核心问题。

 

A、按契约绑定

 

请求处理方法入参的类型可以是 Java 基本数据类型或 String 类型,这时方法入参按参数名匹配的原则绑定到 URL 请求参数,同时还自动完成 String 类型的 URL 请求参数到请求处理方法参数类型的转换。如果入参是基本数据类型(如 int、long、float 等),URL 请求参数中一定要有对应的参数,否则将抛出 TypeMismatchException 异常,提示无法将 null 转换为基本数据类型。

example:

 

listBoardTopic(int topicId):和 topicId URL 请求参数绑定;

listBoardTopic(int topicId,String boardName):分别和 topicId、boardName URL 请求参数绑定;

 

请求处理方法的入参也可以一个 JavaBean,如:

  @RequestMapping(params = "method=listBoardTopic")
  public String listBoardTopic(int topicId,User user) {

                 。。。

    }

如果我们使用以下的 URL 请求:http://localhost/bbtForum.do?method=listBoardTopic&topicId=1&userId=10&userName=tom

topicId URL 参数将绑定到 topicId 入参上,而 userId 和 userName URL 参数将绑定到 user 对象的 userId 和 userName 属性中。和 URL 请求中不允许没有 topicId 参数不同,虽然 User 的 userId 属性的类型是基本数据类型,但如果 URL 中不存在 userId 参数,Spring 也不会报错,此时 user.userId 值为 0

 

B、通过注解指定绑定的 URL 参数

如果我们想改变这种默认的按名称匹配的策略,比如让 listBoardTopic(int topicId,User user) 中的 topicId 绑定到 id 这个 URL 参数,那么可以通过对入参使用 @RequestParam 注解来达到目的:

@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController {
  @RequestMapping(params = "method=listBoardTopic")
  public String listBoardTopic(@RequestParam("id") int topicId,User user) {
    bbtForumService.getBoardTopics(topicId);
    return "listTopic";
  }

}

 

C、绑定模型对象中某个属性

ModelMap 类,它作为通用的模型数据承载对象,传递数据供视图所用。

@RequestMapping(params = "method=listBoardTopic")
 public String listBoardTopic(@RequestParam("id")int topicId,
 User user,ModelMap model) {
   bbtForumService.getBoardTopics(topicId);
   System.out.println("topicId:" + topicId);
   System.out.println("user:" + user);
   //① 将user对象以currUser为键放入到model中 
   
model.addAttribute("currUser",user);
   return "listTopic";
 }

对于当次请求所对应的模型对象来说,其所有属性都将存放到 request 的属性列表中。JSP 视图页面中通过 request.getAttribute(“currUser”) 或者通过 ${currUser} EL 表达式访问模型对象中的对象。

在默认情况下,ModelMap 中的属性作用域是 request 级别是,也就是说,当本次请求结束后,ModelMap 中的属性将销毁。如果希望在多个请求中共享 ModelMap 中的属性,必须将其属性转存到 session 中,这样 ModelMap 的属性才可以被跨请求访问。

Spring 允许我们有选择地指定 ModelMap 中的哪些属性需要转存到 session 中,以便下一个请求属对应的 ModelMap 的属性列表中还能访问到这些属性。这一功能是通过类定义处标注 @SessionAttributes 注解来实现的。

Example:

@Controller
@RequestMapping("/bbtForum.do")
@SessionAttributes("currUser") //①将ModelMap中属性名为currUser的属性
//放到Session属性列表中,以便这个属性可以跨请求访问 
public class BbtForumController {

  @RequestMapping(params = "method=listBoardTopic")
  public String listBoardTopic(@RequestParam("id")int topicId, User user,
ModelMap model) {
    bbtForumService.getBoardTopics(topicId);
    System.out.println("topicId:" + topicId);
    System.out.println("user:" + user);
    model.addAttribute("currUser",user); //②向ModelMap中添加一个属性
    return "listTopic";
  }
}

不但可以在 listBoardTopic() 请求所对应的 JSP 视图页面中通过 request.getAttribute(“currUser”) 和 session.getAttribute(“currUser”) 获取 user 对象,还可以在下一个请求所对应的 JSP 视图页面中通过 session.getAttribute(“currUser”) 或 ModelMap#get(“currUser”) 访问到这个属性。

 

除了在JSP视图页面中通过传统的方法访问 ModelMap中的属性外,是否可以将ModelMap中的属性绑定到请求处理方法的入参中呢?答案是肯定的。Spring为此提供了一个@ModelAttribute的注解。

 

请求处理方法的签名规约

方法入参

请求处理方法入参的可选类型说明Java 基本数据类型和 String默认情况下将按名称匹配的方式绑定到 URL 参数上,可以通过 @RequestParam 注解改变默认的绑定规则request/response/session既可以是 Servlet API 的也可以是 Portlet API 对应的对象,Spring 会将它们绑定到 Servlet 和 Portlet 容器的相应对象上org.springframework.web.context.request.WebRequest内部包含了 request 对象java.util.Locale绑定到 request 对应的 Locale 对象上java.io.InputStream/java.io.Reader

可以借此访问 request 的内容

java.io.OutputStream / java.io.Writer可以借此操作 response 的内容任何标注了 @RequestParam 注解的入参

被标注 @RequestParam 注解的入参将绑定到特定的 request 参数上

java.util.Map / org.springframework.ui.ModelMap它绑定 Spring MVC 框架中每个请求所创建的潜在的模型对象,它们可以被 Web 视图对象访问(如 JSP)命令/表单对象(注:一般称绑定使用 HTTP GET 发送的 URL 参数的对象为命令对象,而称绑定使用 HTTP POST 发送的 URL 参数的对象为表单对象)它们的属性将以名称匹配的规则绑定到 URL 参数上,同时完成类型的转换。而类型转换的规则可以通过 @InitBinder 注解或通过 HandlerAdapter 的配置进行调整org.springframework.validation.Errors / org.springframework.validation.BindingResult为属性列表中的命令/表单对象的校验结果,注意检验结果参数必须紧跟在命令/表单对象的后面rg.springframework.web.bind.support.SessionStatus

可以通过该类型 status 对象显式结束表单的处理,这相当于触发 session 清除其中的通过 @SessionAttributes 定义的属性

 

方法返回参数

 

请求处理方法返回的可选类型说明void

 此时逻辑视图名由请求处理方法对应的 URL 确定,如以下的方法:

@RequestMapping("/welcome.do")
public void welcomeHandler() {
}

对应的逻辑视图名为“welcome”

String

 此时逻辑视图名为返回的字符,如以下的方法:

@RequestMapping(method = RequestMethod.GET)
public String setupForm(@RequestParam("ownerId") int ownerId, ModelMap model) {
  Owner owner = this.clinic.loadOwner(ownerId);
  model.addAttribute(owner);
  return "ownerForm";
}

对应的逻辑视图名为“ownerForm”

org.springframework.ui.ModelMap

和返回类型为 void 一样,逻辑视图名取决于对应请求的 URL,如下面的例子:

@RequestMapping("/vets.do")
public ModelMap vetsHandler() {
  return new ModelMap(this.clinic.getVets());
}

对应的逻辑视图名为“vets”,返回的 ModelMap 将被作为请求对应的模型对象,可以在 JSP 视图页面中访问到。

ModelAndView当然还可以是传统的 ModelAndView。


应该说使用 String 作为请求处理方法的返回值类型是比较通用的方法,这样返回的逻辑视图名不会和请求 URL 绑定,具有很大的灵活性,而模型数据又可以通过 ModelMap 控制。当然直接使用传统的 ModelAndView 也不失为一个好的选择。

 

如何准备数据

 

在传统的 SimpleFormController 里,是通过复写其 referenceData() 方法来准备引用数据的。在 Spring 2.5 时,可以将任何一个拥有返回值的方法标注上 @ModelAttribute,使其返回值将会进入到模型对象的属性列表中

@Controller
@RequestMapping("/bbtForum.do")
public class BbtForumController {
  @Autowired
  private BbtForumService bbtForumService;
  
@ModelAttribute("items")//<——①向模型对象中添加一个名为items的属性
  public List<String> populateItems() {
    List<String> lists = new ArrayList<String>();
    lists.add("item1");
    lists.add("item2");
    return lists;
  }
  @RequestMapping(params = "method=listAllBoard")
  public String listAllBoard(@ModelAttribute("currUser")User user, ModelMap model) {
    bbtForumService.getAllBoard();
    //<——②在此访问模型中的items属性
    
System.out.println("model.items:" + ((List<String>)model.get("items")).size());
    return "listBoard";
  }
}

在 ① 处,通过使用 @ModelAttribute 注解,populateItem() 方法将在任何请求处理方法执行前调用,Spring MVC 会将该方法返回值以“items”为名放入到隐含的模型对象属性列表中。

所以在 ② 处,我们就可以通过 ModelMap 入参访问到 items 属性,当执行 listAllBoard() 请求处理方法时,② 处将在控制台打印出“model.items:2”的信息。当然我们也可以在请求的视图中访问到模型对象中的 items 属性。

<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* csdn 横长 */google_ad_slot = "7322168821";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>