SpringMVC中@Controller和@RequestMapping用法

观书散遗帙,探古穷至妙。这篇文章主要讲述SpringMVC中@Controller和@RequestMapping用法相关的知识,希望能为你提供帮助。
一、简介                  在SpringMVC  中,控制器Controller  负责处理由DispatcherServlet  分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model  ,然后再把该Model  返回给对应的View  进行展示。在SpringMVC  中提供了一个非常简便的定义Controller  的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller  标记一个类是Controller  ,然后使用@RequestMapping  和@RequestParam  等一些注解用以定义URL  请求和Controller  方法之间的映射,这样的Controller  就能被外界访问到。此外Controller  不会直接依赖于HttpServletRequest  和HttpServletResponse  等HttpServlet  对象,它们可以通过Controller  的方法参数灵活的获取到。为了先对Controller  有一个初步的印象,以下先定义一个简单的Controller  :
java代码   

SpringMVC中@Controller和@RequestMapping用法

文章图片
  1. @Controller   
  2. public  class  MyController  {   
  3.    
  4.         @RequestMapping  (  "/showView"  )   
  5.         public  ModelAndView  showView()  {   
  6.               ModelAndView  modelAndView  =  new  ModelAndView();    
  7.               modelAndView.setViewName(  "viewName"  );    
  8.               modelAndView.addObject(  "  需要放到  model  中的属性名称  "  ,  "  对应的属性值,它是一个对象  "  );    
  9.               return  modelAndView;    
  10.         }   
  11.    
  12. }     
 
在上面的示例中,@Controller  是标记在类MyController  上面的,所以类MyController  就是一个SpringMVC Controller  对象了,然后使用@RequestMapping(“/showView”)  标记在Controller  方法上,表示当请求/showView.do  的时候访问的是MyController  的showView  方法,该方法返回了一个包括Model  和View  的ModelAndView  对象。这些在后续都将会详细介绍。
二、使用  @Controller  定义一个  Controller  控制器                  @Controller  用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller  对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping  注解。@Controller  只是定义了一个控制器类,而使用@RequestMapping  注解的方法才是真正处理请求的处理器,这个接下来就会讲到。
      单单使用@Controller  标记在一个类上还不能真正意义上的说它就是SpringMVC  的一个控制器类,因为这个时候Spring  还不认识它。那么要如何做Spring  才能认识它呢?这个时候就需要我们把这个控制器类交给Spring  来管理。拿MyController  来举一个例子
 
Java代码   
SpringMVC中@Controller和@RequestMapping用法

文章图片
  1. @Controller   
  2. public  class  MyController  {   
  3.         @RequestMapping  (  "/showView"  )   
  4.         public  ModelAndView  showView()  {   
  5.               ModelAndView  modelAndView  =  new  ModelAndView();    
  6.               modelAndView.setViewName(  "viewName"  );    
  7.               modelAndView.addObject(  "  需要放到  model  中的属性名称  "  ,  "  对应的属性值,它是一个对象  "  );    
  8.               return  modelAndView;    
  9.         }   
  10.    
  11. }     
 
这个时候有两种方式可以把MyController  交给Spring  管理,好让它能够识别我们标记的@Controller  。
      第一种方式是在SpringMVC  的配置文件中定义MyController  的bean  对象。
< bean class="com.host.app.web.controller.MyController"/>
      第二种方式是在SpringMVC  的配置文件中告诉Spring  该到哪里去找标记为@Controller  的Controller  控制器。
Xml代码   
SpringMVC中@Controller和@RequestMapping用法

文章图片
  1. <   context:component-scan  base-package  =  "com.host.app.web.controller"  >    
  2.       <   context:exclude-filter  type  =  "annotation"   
  3.               expression  =  "org.springframework.stereotype.Service"  />    
  4. < /  context:component-scan  >      
        注:
              上面  context:exclude-filter  标注的是不扫描  @Service  标注的类
三、使用  @RequestMapping  来映射  Request  请求与处理器                  可以使用@RequestMapping  来映射URL  到控制器类,或者是到Controller  控制器的处理方法上。当@RequestMapping  标记在Controller  类上的时候,里面使用@RequestMapping  标记的方法的请求地址都是相对于类上的@RequestMapping  而言的;当Controller  类上没有标记@RequestMapping  注解时,方法上的@RequestMapping  都是绝对路径。这种绝对路径和相对路径所组合成的最终路径都是相对于根路径“/  ”而言的。
 
Java代码   
SpringMVC中@Controller和@RequestMapping用法

文章图片
  1. @Controller   
  2. public  class  MyController  {   
  3.         @RequestMapping  (  "/showView"  )   
  4.         public  ModelAndView  showView()  {   
  5.               ModelAndView  modelAndView  =  new  ModelAndView();    
  6.               modelAndView.setViewName(  "viewName"  );    
  7.               modelAndView.addObject(  "  需要放到  model  中的属性名称  "  ,  "  对应的属性值,它是一个对象  "  );    
  8.               return  modelAndView;    
  9.         }   
  10.    
  11. }     
 
在这个控制器中,因为MyController  没有被@RequestMapping  标记,所以当需要访问到里面使用了@RequestMapping  标记的showView  方法时,就是使用的绝对路径/showView.do  请求就可以了。
 
Java代码   
SpringMVC中@Controller和@RequestMapping用法

文章图片
  1. @Controller   
  2. @RequestMapping  (  "/test"  )   
  3. public  class  MyController  {   
  4.         @RequestMapping  (  "/showView"  )   
  5.         public  ModelAndView  showView()  {   
  6.               ModelAndView  modelAndView  =  new  ModelAndView();    
  7.               modelAndView.setViewName(  "viewName"  );    
  8.               modelAndView.addObject(  "  需要放到  model  中的属性名称  "  ,  "  对应的属性值,它是一个对象  "  );    
  9.               return  modelAndView;    
  10.         }   
  11.    
  12. }     
 
      这种情况是在控制器上加了@RequestMapping  注解,所以当需要访问到里面使用了@RequestMapping  标记的方法showView()  的时候就需要使用showView  方法上@RequestMapping  相对于控制器MyController上@RequestMapping  的地址,即/test/showView.do  。
(一)使用  URI  模板URI  模板就是在URI  中给定一个变量,然后在映射的时候动态的给该变量赋值。如URI  模板http://localhost/app/{variable1}/index.html  ,这个模板里面包含一个变量variable1  ,那么当我们请求http://localhost/app/hello/index.html  的时候,该URL  就跟模板相匹配,只是把模板中的variable1  用hello  来取代。在SpringMVC  中,这种取代模板中定义的变量的值也可以给处理器方法使用,这样我们就可以非常方便的实现URL  的RestFul  风格。这个变量在SpringMVC  中是使用@PathVariable  来标记的。在SpringMVC  中,我们可以使用@PathVariable  来标记一个Controller  的处理方法参数,表示该参数的值将使用URI  模板中对应的变量的值来赋值。
例3
SpringMVC中@Controller和@RequestMapping用法

文章图片
SpringMVC中@Controller和@RequestMapping用法

文章图片
@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 中的属性名称 " , " 对应的属性值,它是一个对象 " ); return modelAndView; } }

SpringMVC中@Controller和@RequestMapping用法

文章图片
SpringMVC中@Controller和@RequestMapping用法

文章图片
在例3的代码中我们定义了两个URI  变量,一个是控制器类上的variable1  ,一个是showView  方法上的variable2  ,然后在showView  方法的参数里面使用@PathVariable  标记使用了这两个变量。所以当我们使用/test/hello/showView/2.do  来请求的时候就可以访问到MyController  的showView  方法,这个时候variable1  就被赋予值hello  ,variable2  就被赋予值2  ,然后我们在showView  方法参数里面标注了参数variable1  和variable2  是来自访问路径的path  变量,这样方法参数variable1  和variable2  就被分别赋予hello  和2  。方法参数variable1  是定义为String  类型,variable2  是定义为int  类型,像这种简单类型在进行赋值的时候Spring  是会帮我们自动转换的,关于复杂类型该如何来转换在后续内容中将会讲到。
      在上面的代码中我们可以看到在标记variable1  为path  变量的时候我们使用的是@PathVariable  ,而在标记variable2  的时候使用的是@PathVariable(“variable2”)  。这两者有什么区别呢?第一种情况就默认去URI  模板中找跟参数名相同的变量,但是这种情况只有在使用debug  模式进行编译的时候才可以,而第二种情况是明确规定使用的就是URI  模板中的variable2  变量。当不是使用debug  模式进行编译,或者是所需要使用的变量名跟参数名不相同的时候,就要使用第二种方式明确指出使用的是URI  模板中的哪个变量。
      除了在请求路径中使用URI  模板,定义变量之外,@RequestMapping  中还支持通配符“*  ”。如下面的代码我就可以使用/myTest/whatever/wildcard.do  访问到Controller  的testWildcard  方法。
SpringMVC中@Controller和@RequestMapping用法

文章图片
SpringMVC中@Controller和@RequestMapping用法

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

SpringMVC中@Controller和@RequestMapping用法

文章图片
SpringMVC中@Controller和@RequestMapping用法

文章图片
 
(二)使用  @RequestParam  绑定  HttpServletRequest  请求参数到控制器方法参数例4
@RequestMapping ( "requestParam" ) public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) { return "requestParam" ; }

在上面代码中利用@RequestParam  从HttpServletRequest  中绑定了参数name  到控制器方法参数name  ,绑定了参数age  到控制器方法参数age  。值得注意的是和@PathVariable  一样,当你没有明确指定从request  中取哪个参数时,Spring  在代码是debug  编译的情况下会默认取更方法参数同名的参数,如果不是debug  编译的就会报错。此外,当需要从request  中绑定的参数和方法的参数名不相同的时候,也需要在@RequestParam  中明确指出是要绑定哪个参数。在上面的代码中如果我访问/requestParam.do?name=hello& age=1  则Spring  将会把request请求参数name  的值hello  赋给对应的处理方法参数name  ,把参数age  的值1  赋给对应的处理方法参数age  。
在@RequestParam  中除了指定绑定哪个参数的属性value  之外,还有一个属性required  ,它表示所指定的参数是否必须在request  属性中存在,默认是true  ,表示必须存在,当不存在时就会报错。在上面代码中我们指定了参数name  的required  的属性为false  ,而没有指定age  的required  属性,这时候如果我们访问/requestParam.do而没有传递参数的时候,系统就会抛出异常,因为age  参数是必须存在的,而我们没有指定。而如果我们访问/requestParam.do?age=1  的时候就可以正常访问,因为我们传递了必须的参数age  ,而参数name  是非必须的,不传递也可以。
(三)使用  @CookieValue  绑定  cookie  的值到  Controller  方法参数例5
@RequestMapping ( "cookieValue" ) public String testCookieValue( @CookieValue ( "hello" ) String cookieValue, @CookieValue String hello) { System. out .println(cookieValue + "-----------" + hello); return "cookieValue" ; }

在上面的代码中我们使用@CookieValue  绑定了cookie  的值到方法参数上。上面一共绑定了两个参数,一个是明确指定要绑定的是名称为hello  的cookie  的值,一个是没有指定。使用没有指定的形式的规则和@PathVariable、@RequestParam  的规则是一样的,即在debug  编译模式下将自动获取跟方法参数名同名的cookie  值。
(四)使用  @RequestHeader  注解绑定  HttpServletRequest  头信息到Controller  方法参数例6
@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  请求头  host  到Controller  的方法参数。上面方法的三个参数都将会赋予同一个值,由此我们可以知道在绑定请求头参数到方法参数的时候规则和  @PathVariable  、  @RequestParam  以及  @CookieValue  是一样的,即没有指定绑定哪个参数到方法参数的时候,在  debug  编译模式下将使用方法参数名作为需要绑定的参数。但是有一点  @RequestHeader  跟另外三种绑定方式是不一样的,那就是在使用  @RequestHeader  的时候是大小写不敏感的,即  @RequestHeader(“Host”)  和  @RequestHeader(“host”)  绑定的都是  Host  头信息。记住在  @PathVariable  、  @RequestParam  和  @CookieValue  中都是大小写敏感的。
(五)  @RequestMapping  的一些高级应用在RequestMapping  中除了指定请求路径value  属性外,还有其他的属性可以指定,如params  、method  和headers  。这样属性都可以用于缩小请求的映射范围。
1.params属性
例7
@RequestMapping (value= "https://www.songbingjia.com/android/testParams" , params={ "param1=value1" , "param2" , "!param3" }) public String testParams() { System. out .println( "test Params..........." ); return "testParams" ; }

在上面的代码中我们用@RequestMapping  的params  属性指定了三个参数,这些参数都是针对请求参数而言的,它们分别表示参数param1  的值必须等于value1  ,参数param2  必须存在,值无所谓,参数param3  必须不存在,只有当请求/testParams.do  并且满足指定的三个参数条件的时候才能访问到该方法。所以当请求/testParams.do?param1=value1& param2=value2  的时候能够正确访问到该testParams  方法,当请求/testParams.do?param1=value1& param2=value2& param3=value3  的时候就不能够正常的访问到该方法,因为在@RequestMapping  的params  参数里面指定了参数param3  是不能存在的。
2.method属性
例8
@RequestMapping (value= "https://www.songbingjia.com/android/testMethod" , method={RequestMethod. GET , RequestMethod. DELETE }) public String testMethod() { return "method" ; }

在上面的代码中就使用method  参数限制了以GET  或DELETE  方法请求/testMethod.do  的时候才能访问到该Controller  的testMethod  方法。
3.headers属性
例9
@RequestMapping (value= "https://www.songbingjia.com/android/testHeaders" , headers={ "host=localhost" , "Accept" }) public String testHeaders() { return "headers" ; }

headers  属性的用法和功能与params  属性相似。在上面的代码中当请求/testHeaders.do  的时候只有当请求头包含Accept  信息,且请求的host  为localhost  的时候才能正确的访问到testHeaders  方法。
以  @RequestMapping  标记的处理器方法支持的返回类型如果处理器方法被注解@ResponseBody  标记的话,那么处理器方法的任何返回类型都会通过HttpMessageConverters  转换之后写到HttpServletResponse  中,而不会像上面的那些情况一样当做视图或者模型来处理
@Responsebody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。 
作用: 
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。 
使用时机: 
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
当页面发出异步请求:
function login() { var datas = \'{"username":"\' + $(\'#username\').val() + \'","userid":"\' + $(\'#userid\').val() + \'","status":"\' + $(\'#status\').val() + \'"}\'; $.ajax({ type : \'POST\', contentType : \'application/json\', url : "${pageContext.request.contextPath}/user/login", processData : false, dataType : \'json\', data : datas, success : function(data) { alert("userid: " + data.userid + "username: " + data.username + "status: "+ data.status); }, error : function(XMLHttpRequest, textStatus, errorThrown) { alert("出现异常,异常信息:"+textStatus,"error"); } }); };

 
例如:
@RequestMapping(value = "https://www.songbingjia.com/android/user/login") @ResponseBody // 将ajax(datas)发出的请求写入 User 对象中,返回json对象响应回去 public User login(User user) { User user = new User(); user .setUserid(1); user .setUsername("MrF"); user .setStatus("1"); return user ; }

异步获取 json 数据,加上 @Responsebody 注解后,就会直接返回 json 数据。
@RequestBody@RequestBody 注解则是将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。
作用:
1) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上; 
2) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理); 
multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据); 
其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
B) PUT方式提交时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 必须;multipart/form-data, 不能处理;其他格式, 必须;
说明:request的body部分的数据编码格式由header部分的Content-Type指定;
例如:
@RequestMapping(value = "https://www.songbingjia.com/android/user/login") @ResponseBody // 将ajax(datas)发出的请求写入 User 对象中 public User login(@RequestBody User user) { // 这样就不会再被解析为跳转路径,而是直接将user对象写入 HTTP 响应正文中 return user; }



SpringMVC中使用@ResponseBody注解标注业务方法,将业务方法的返回值做成json输出给页面导包:
除了一些spring的包之外,还需要jackson-annotations.jar , jackson-core.jar , jackson-databind.jar 这三个包
 
开启@ResponseBody注解:
在 spring-mvc.xml 中通过< mvc:annotation-driven /> 开启@ResponseBody注解
 
【SpringMVC中@Controller和@RequestMapping用法】使用@ResponseBody标注业务方法
SpringMVC中@Controller和@RequestMapping用法

文章图片
package com.loger.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.loger.entity.User; /** * ResponseBody 注解,可以将如下类型的数据做成json: * 1)基本数据类型,如 boolean , String , int 等 * 2) Map 类型数据 * 3)集合或数组 * 4)实体对象 * 5)实体对象集合 * */@Controller @RequestMapping("/test") public class JsonController {@RequestMapping("test1.do") @ResponseBody public boolean test1(){ return true; }@RequestMapping("/test2.do") @ResponseBody public Map< String, Object> test2(){ Map< String , Object> map = new HashMap< String ,Object> (); map.put("id", "s20070"); map.put("name", "郑城斌"); return map; }@RequestMapping("/test3.do") @ResponseBody public List< String> test3(){ List< String> list = new ArrayList< > (); list.add("aaa"); list.add("bbb"); list.add("ccc"); return list; }@RequestMapping("/test4.do") @ResponseBody public User test4(){ User user = new User(); user.setId("s20068"); user.setName("余清波"); user.setAge(21); return user; }@RequestMapping("/test5.do") @ResponseBody public List< User> test5(){ List< User> list = new ArrayList< > (); User user1 = new User(); user1.setId("s200681"); user1.setName("余清波1"); user1.setAge(21); list.add(user1); User user2 = new User(); user2.setId("s200682"); user2.setName("余清波2"); user2.setAge(21); list.add(user2); User user3 = new User(); user3.setId("s200683"); user3.setName("余清波3"); user3.setAge(21); list.add(user3); return list; } }


    推荐阅读