【SpringMVC】注解驱动的控制器详解

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

Spring2.5引入注解式处理器支持,通过@Controller和@RequestMapping注解定义我们的处理器类。并且提供了一组强大的注解需要通过处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter来开启支持@Controller和@RequestMapping注解的处理器。

@Controller:用于标识是处理器类;

@RequestMapping:请求到处理器功能方法的映射规则;

@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;

@ModelAttribute:请求参数到命令对象的绑定;

@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;

一、视图返回

1、返回String对象

	@RequestMapping(value ="/index")//相对于根目录的路径
	public String test(ModelMap model) {
		model.addAttribute("message", "调用FirstController的test方法");
		return "index";//指定页面要跳转的view视图路径
	}

直接返回视图的名称,结果:

2、返回ModelAndView对象

	@RequestMapping("/index1")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
		modelAndView.addObject("message", "调用FirstController的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
		return modelAndView;
	}

结果:

其中

modelAndView.setViewName("index1");

也可以写成:

modelAndView.setView(new RedirectView("index1"));

ModelAndView()

这个构造方法构造出来的ModelAndView
不能直接使用,应为它没有指定view,也没有绑定对应的model对象。当然,model对象不是必须的,但是view确实必须的。
用这个构造方法构造的实例主要用来在以后往其中加view设置和model对象。
给ModelAndView
实例设置view的方法有两
个:setViewName(String viewName) 和 setView(View view)。前者是使用view
name,后者是使用预先构造好的View对象。其中前者比较常用。事实上View是一个接口,而不是一个可以构造的具体类,我们只能通过其他途径来获取
View的实例。对于view
name,它既可以是jsp的名字,也可以是tiles定义的名字,取决于使用的ViewNameResolver如何理解这个view name。
如何获取View的实例以后再研究。
而对应如何给ModelAndView
实例设置model则比较复杂。有三个方法可以使用:

addObject(Object modelObject)
addObject(String modelName, Object modelObject)
addAllObjects(Map modelMap)

二、@RequestMapping

对于各种注解而言,排第一的当然是“@Controller”,表明某类是一个controller。“@RequestMapping”请求路径映射,如果标注在某个controller的类级别上,则表明访问此类路径下的方法都要加上其配置的路径;最常用是标注在方法上,表明哪个具体的方法来接受处理某次请求。

@RequestMapping 参数说明

value
定义处理方法的请求的 URL 地址。
method
定义处理方法的 http method 类型,如 GET、POST 等。
params
定义请求的 URL 中必须包含的参数。
headers
定义请求中 Request Headers 必须包含的参数

2.1 拦截路径设置

(1) 方法上的拦截

@Controller
public class FirstController {
	@RequestMapping(value ="/index")//相对于根目录的路径
	public String test(ModelMap model) {
		model.addAttribute("message", "调用FirstController的test方法");
		return "index";//指定页面要跳转的view视图路径
	}
}

表示拦截:http://localhost:8080/SpringMVCLearningChapter2/index1

(2)类上的拦截

@Controller
@RequestMapping("/user")
public class SecondController {
	@RequestMapping(value ="/index")
	public String test(ModelMap model) {
		model.addAttribute("message", "调用SecondController 的test方法");
		return "index";//指定页面要跳转的view视图路径
	}

	@RequestMapping("/index1")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
		modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
		return modelAndView;
	}
}

表示拦截:http://localhost:8080/SpringMVCLearningChapter2/user/index

和http://localhost:8080/SpringMVCLearningChapter2/user/index1

即拦截:根目录/user/index根目录/user/index1

请求映射

  • 普通URL路径映射

@RequestMapping(value={"/login.do","/user/login.do"}):多个URL路径可以映射到同一个处理器的功能处理方法。

  • URL模板模式映射

@RequestMapping(value="/users/{userId}"):{xxx}占位符,请求的URL可以是"/users/123456"或"/users/abcd"。

@RequestMapping(value="/users/{userId}/login.do"):这样也是可以的,请求的URL可以是"/users/123/login.do"。

@RequestMapping(value="/users/{userId}/channel/{channelId}"):这样也是可以的,请求的URL可以是"/users/123/channel/456"。

  • Ant风格的URL路径映射

@RequestMapping(value="/users/**"):可以匹配"/users/abc/abc"。

@RequestMapping(value="/model?"):可匹配"/model1"或"/modela" ,但不匹配"/model"或"/modelaa";

@RequestMapping(value="/model*"):可匹配"/modelabc"或"/model",但不匹配"/modelabc/abc";

@RequestMapping(value="/model/*"):可匹配"/model/abc",但不匹配"/modelabc";

@RequestMapping(value="/model/**/{modelId}"):可匹配"/model/abc/abc/123”或"/model/123",

也就是Ant风格和URI模板变量风格可混用;

  • 正则表达式风格的URL路径映射

从Spring3.0开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式}

@RequestMapping(value="/login/{userId://d+}.do"):可以匹配

"/login/123.do",但不能匹配"/login/abc.do",这样可以设计更加严格的规则。

  • 组合使用是"或"的关系

如@RequestMapping(value={"/login.do","/user/login.do"})组合使用是或的关系,即"/login.do"或

"/user/login.do"请求URL路径都可以映射到@RequestMapping指定的功能处理方法。

2、param参数

如果想给一个页面设置传递的参数,可以写成如下:

@Controller
@RequestMapping("/third")
public class ThirdController {
	@RequestMapping(value ="/index",params="name")//要求传递参数name,浏览器中输入name后,控制器会自动把参数传递给test中的name
	public String test(ModelMap model,String name) {
		model.addAttribute("message", name);
		return "index";
	}
}

这时输入http://localhost:8080/SpringMVCLearningChapter2/third/index是无法访问的:

因为它要求你一定要传递一个name参数,所以得这样写:

当然,这里也可以把需要的参数注解到方法的参数上去

	@RequestMapping(value ="/index")//要求传递参数name,浏览器中输入name后,控制器会自动把参数传递给test中的name
	public String test(ModelMap model,@RequestParam("name")String name) {
		model.addAttribute("message", name);
		return "index";
	}

效果和上面和一样的。这时如果还是想访问http://localhost:8080/SpringMVCLearningChapter2/third/index,把required=false加上

	@RequestMapping(value ="/index")
	public String test(ModelMap model,@RequestParam(value="name",required=false)String name) {
		model.addAttribute("message", name);
		return "index";
	}

3、method

	@RequestMapping(value ="/index1",method = RequestMethod.GET,params="name")
	public ModelAndView test2() {
		ModelAndView modelAndView = new ModelAndView();
		///modelAndView.setView(new RedirectView("index1"));
		modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
		modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
		return modelAndView;
	}	

表明只能通过GET来访问,或要POST,改成

method = RequestMethod.POST

4、head

@RequestMapping(headers)
headers 的作用也是用于细化映射。只有当请求的 Request Headers 中包含与 heanders 值相匹配的参数,处理方法才会被调用。
@RequestMapping(value = "/specify", headers = "accept=text/*")
public String specify(){
return "example_specify_page";
}
请求的 Request Headers 中 Accept 的值必须匹配 text/* ( 如 text/html ),方法才会被调用。

三、其它常用注解

handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)

A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解:   @PathVariable;

B、处理request header部分的注解:   @RequestHeader, @CookieValue;

C、处理request body部分的注解:@RequestParam,  @RequestBody;

D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

1、 @PathVariable

当使用@RequestMapping URI template 样式映射时, 即 /fourth/{num}, 这时的num可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。

示例代码:

@Controller
@RequestMapping("/fourth/{num}")
public class FourthController {
	@RequestMapping(value ="/index/{string}")
	public String test(ModelMap model,@PathVariable("num") int num,@PathVariable("string") String string) {
		model.addAttribute("message", "num="+String.valueOf(num)+"  string="+string);
		return "index";
	}
}

浏览器输入:http://localhost:8080/SpringMVCLearningChapter2/fourth/1234/index/linbingwen

上面代码把URI template 中变量num的值和string的值,绑定到方法的参数上。若方法参数名称和需要绑定的uri template中变量名称不一致,需要在@PathVariable("num")指定uri template中的名称。

2、 @RequestHeader、@CookieValue

@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。

	@RequestMapping(value = "/index", method = RequestMethod.GET)
	   public String  getHello(@RequestHeader ("host") String hostName,
	        @RequestHeader ("Accept") String acceptType,
	        @RequestHeader ("Accept-Language") String acceptLang,
	        @RequestHeader ("Accept-Encoding") String acceptEnc,
	        @RequestHeader ("Cache-Control") String cacheCon,
	        @RequestHeader ("Cookie") String cookie,
	        @RequestHeader ("User-Agent") String userAgent)
	   {
	    System.out.println("Host : " + hostName);
	    System.out.println("Accept : " + acceptType);
	    System.out.println("Accept Language : " + acceptLang);
	    System.out.println("Accept Encoding : " + acceptEnc);
	    System.out.println("Cache-Control : " + cacheCon);
	    System.out.println("Cookie : " + cookie);
	    System.out.println("User-Agent : " + userAgent);
	       return "index";
	   }

@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。

如有如下Cookie值:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

参数绑定的代码:

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie)  {

  //...

}

即把JSESSIONID的值绑定到参数cookie上

3、@RequestParam, @RequestBody

@RequestParam

A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;

B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;

C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

@RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;

它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。

因为配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded的内容,处理完的结果放在一个MultiValueMap<String, String>里,这种情况在某些特殊需求下使用,详情查看FormHttpMessageConverter api;

示例代码:

@RequestMapping(value = "/something", method = RequestMethod.PUT)
public void handle(@RequestBody String body, Writer writer) throws IOException {
  writer.write(body);
}

4、@SessionAttributes, @ModelAttribute

@SessionAttributes:

该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。

该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象;

示例代码:

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
}

@ModelAttribute

该注解有两个用法,一个是用于方法上,一个是用于参数上;

用于方法上时:  通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;

用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:

A) @SessionAttributes 启用的attribute 对象上;

B) @ModelAttribute 用于方法上时指定的model对象;

C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean中。

用到方法上@ModelAttribute的示例代码:

@ModelAttribute
public Account addAccount(@RequestParam String number) {
    return accountManager.findAccount(number);
}

这种方式实际的效果就是在调用@RequestMapping的方法之前,为request对象的model里put(“account”, Account);

用在参数上的@ModelAttribute示例代码:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) {

}

首先查询 @SessionAttributes有无绑定的Pet对象,若没有则查询@ModelAttribute方法层面上是否绑定了Pet对象,若没有则将URI template中的值按对应的名称绑定到Pet对象的各属性上。

四、补充讲解

问题: 在不给定注解的情况下,参数是怎样绑定的?

通过分析AnnotationMethodHandlerAdapter和RequestMappingHandlerAdapter的源代码发现,方法的参数在不给定参数的情况下:

若要绑定的对象时简单类型:  调用@RequestParam来处理的。

若要绑定的对象时复杂类型:  调用@ModelAttribute来处理的。

这里的简单类型指java的原始类型(boolean, int 等)、原始类型对象(Boolean, Int等)、String、Date等ConversionService里可以直接String转换成目标对象的类型;

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

时间: 2024-10-09 21:18:32

【SpringMVC】注解驱动的控制器详解的相关文章

idea spring+springmvc+mybatis环境配置整合详解

idea spring+springmvc+mybatis环境配置整合详解 1.配置整合前所需准备的环境: 1.1:jdk1.8 1.2:idea2017.1.5 1.3:Maven 3.5.2 2.查看idea中是否安装Maven插件: 2.1:File --> Settings --> Plugins 2.2:如下图所示的步骤进行操作(注:安装完插件,idea会重新启动) 3.idea创建Maven项目的步骤 4.搭建目录结构 下图就是我搭建Maven项目之后,添加对应的目录和文件 5.p

迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解

视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.com/s/1kTlGkcR 总线_设备_驱动注册流程详解 ? 注册流程图 ? 设备一般都需要先注册,才能注册驱动 – 现在越来越多的热拔插设备,反过来了.先注册驱动,设备来了再注册 设备 ? 本节使用的命令 – 查看总线的命令#ls /sys/bus/ – 查看设备号的命令#cat /proc/devices ? 设备都有主设备号和次设备号,否则255个设备号不

Hibernate注解----关联映射注解以及课程总结详解----图片版本

上一篇,记录了Hibernate注解----类级别注解以及属性注解详解 ,我们这一节主要讲解的是Hibernate注解----关联映射注解以及课程总结详解. 本节的主要内容: 第3章 关联映射注解 3-1 本章简介 3-2 实体之间的关系 3-3 一对一单向外键关联(一) 3-4 一对一单向外键关联(二) 3-5 一对一双向外键关联 3-6 一对一单向外键联合主键 3-7 多对一单向外键关联(一) 3-8 多对一单向外键关联(二) 3-9 一对多单向外键关联 3-9 一对多双向外键关联 3-10

Controller接口控制器详解(1)——SpringMVC

4.1.Controller简介 Controller控制器,是MVC中的部分C,为什么是部分呢?因为此处的控制器主要负责功能处理部分: 1.收集.验证请求参数并绑定到命令对象: 2.将命令对象交给业务对象,由业务对象处理并返回模型数据: 3.返回ModelAndView(Model部分是业务对象返回的模型数据,视图部分为逻辑视图名). 还记得DispatcherServlet吗?主要负责整体的控制流程的调度部分: 1.负责将请求委托给控制器进行处理: 2.根据控制器返回的逻辑视图名选择具体的视

SpringMVC配置web.xml文件详解(列举常用的配置)

常用的web.xml的配置 1.Spring 框架解决字符串编码问题:过滤器 CharacterEncodingFilter(filter-name) 2.在web.xml配置监听器ContextLoaderListener(listener-class) ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息.因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默

Linux的fasync驱动异步通知详解

工作项目用有个需求是监测某个GPIO输入方波的频率!通俗的讲就是一个最最简单的测方波频率的示波器!不过只是测方波的频率!频率范围是0~200HZ,而且频率方波不是一直都是200HZ,大多数的时候可能一直是0或者一个更低频率的方波!同时要考虑到方波有可能一直维持在200HZ ,同时保持效率和性能的情况下,fasync驱动异步通知是个不错的选择,当初写demo的时候实测1K的方波完全没有问题!应用到项目中也是完全能满足需求!驱动很简单!业余时间把自己之前学到的知识总结一下!对自己也是个提高! 根据需

Linux的fasync驱动异步通知详解【转】

本文转载自:http://blog.csdn.net/coding__madman/article/details/51851338 版权声明:本文为博主原创文章,未经博主允许不得转载. 工作项目用有个需求是监测某个GPIO输入方波的频率!通俗的讲就是一个最最简单的测方波频率的示波器!不过只是测方波的频率!频率范围是0~200HZ,而且频率方波不是一直都是200HZ,大多数的时候可能一直是0或者一个更低频率的方波!同时要考虑到方波有可能一直维持在200HZ ,同时保持效率和性能的情况下,fasy

一对一关联查询注解@OneToOne的实例详解

表的关联查询比较复杂,应用的场景很多,本文根据自己的经验解释@OneToOne注解中的属性在项目中的应用.本打算一篇博客把增删改查写在一起,但是在改的时候遇到了一些问题,感觉挺有意思,所以写下第二篇专门讲修改. 一.单向@OneToOne实例详解 假设一个场景,一个人只能领养一只宠物,根据人能够找到宠物,并且查看宠物的信息,关系是单向的. 创建人与宠物的数据表结构.下载地址:Person,Pet数据库建表. 创建实体. Person.java package com.my.model; impo

(三)Controller接口控制器详解(一)

4.1.Controller简介 Controller控制器,是MVC中的部分C,为什么是部分呢?因为此处的控制器主要负责功能处理部分: 1.收集.验证请求参数并绑定到命令对象: 2.将命令对象交给业务对象,由业务对象处理并返回模型数据: 3.返回ModelAndView(Model部分是业务对象返回的模型数据,视图部分为逻辑视图名). 还记得DispatcherServlet吗?主要负责整体的控制流程的调度部分: 1.负责将请求委托给控制器进行处理: 2.根据控制器返回的逻辑视图名选择具体的视