02-SpringMVC_获得用户请求

问题:用户的请求,是如何被后台获得的,即用户的请求信息是怎么分配给不同的处理器?后台又是如何获得用户数据的?这些问题会后面的课程中一一解答

一、 使用@RequestMapping映射请求

  • SpringMVC使用@RequestMapping注解,为控制器指定可以处理哪些URL请求
  • DispathcherSevle截获请求后,就通过控制器上@RequestMapping提供的映射信息确定请求所对应的处理方法
  • 查看@RequestMapping源码,可以知道它可以修饰方法,也可以修饰类
    

1、@RequestMapping修饰方法

  • 测试类

  1. @Controller
  2. public class SpringMVCTest {
  3. @RequestMapping("/testMappingMethod")
  4. public String testRequestMapping(){
  5. System.out.println("testMappingMethod");
  6. return "success";
  7. }
  8. }
  • URL
  1. <a href="testMappingMethod"></a>

2 @RequestMapping修饰类

  •  测试类
  1. @RequestMapping("/mappingClass")
  2. @Controller
  3. public class MappingClassTest {
  4. @RequestMapping("/testMappingMethod")
  5. public String testRequestMapping(){
  6. System.out.println("testRequestMapping");
  7. return "success";
  8. }
  9. }

  • 请求的url
  1. <a href="mappingClass/testMappingMethod">testMappingClass</a>

3 总结

  • @RequestMapping可以标注在控制器类的定义或方法定义处。
    • 类定义:提供初步的请求映射信息,相对于WEB应用的根目录
    • 方法处:提供进一步细分映射信息,相对于类定义处的URL;若类定义处未标注@RequestMapping,则方法处标注的URL相对WEB应用的根目录

二、映射请求参数、请求方式或请求头

  • @RequestMapping除了可以使用请求Url映射请求以外,还可以使用请求方法、请求参数及请求头映射请求.对应的@RequestMapping源码如下
  1. @Target({ElementType.METHOD, ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Mapping
  5. public @interface RequestMapping {
  6. ...
  7. RequestMethod[] method() default {};
  8. ...
  9. String[] params() default {};
  10. String[] headers() default {};
  11. ...
  12. }
  • @RequestMapping的vaule、method、params及headers分别表请求URL、请求方法、请求参数及请求头的映射条件,他们之间是“与”的关系,联合使用多个条件可让请求映射更加精确化

1、method的属性

  • 控制器
  1. @RequestMapping(value="/testMethod",method=RequestMethod.POST)
  2. public String testMethod(){
  3. System.out.println("testMethod");
  4. return "success";
  5. }
  • 超链接是使用get请求,所以不会成功
  1. <a href="mappingOther/testMethod">测试请求方式</a>
  • form请求
  1. <form action="mappingOther/testMethod" method="post">
  2. <input type="submit" value="提交">
  3. </form>

2、params的属性 

2.1 params支持简单的表达式

  • param1:表示请求必须包含名为param1的请求参数
  • !param1:表示请求不能包含名为param1的请求参数
  • param1!=value1:表示请求包含名为param1的参数,但其值不能为value1
  • {"param1=value1",param2}:请求必须包含名为param1和param2的两个请求参数,且param1的参数的值必须是value1

2.2 测试

  • 控制器
  1. @RequestMapping(value="/testParams",params={"username","age!=10"})
  2. public String testParams(){
  3. System.out.println("testParams");
  4. return "success";
  5. }
含义:必须包含参数username和age,且age的值不能为10
  • 请求
  1. <a href="mappingOther/testParams?username=imentor&age=10">测试参数</a>
    不能成功,因为age的值为10

3、header

  • 获得headers的值,可以通过firebug来查看

  • 控制器中的编写如下
  1. @RequestMapping(value="/testHeaders",headers={"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"})
  2. public String testHeaders(){
  3. System.out.println("testHeader");
  4. return "success";
  5. }

三、映射请求路径

  • @RequestMapping支持Ant风格的请求路径,见源码
    

1、 Ant风格资源地址支持3种匹配符

  • ?:匹配文件名中的一个字符
  • *  :匹配文件名中的任意字符
  • ** :匹配多层路径

2 @RequestMapping支持Ant风格的URL

 
  • /user/*/createUser   :匹配/user/aaa/createUser
  •                                     匹配/user/bbb/createUser
  • /user/**/createUser   :匹配/user/createUser
  •                                     匹配/user/aaa/bbb/createUser
  • /user/createUser??   :匹配/user/createUseraa
  •                                      匹配/user/createUserbb

3、测试

  • 控制器
  1. @RequestMapping(value="/user/*/createUser")
  2. public String createUser(){
  3. System.out.println("createUser");
  4. return "success";
  5. }
  • 请求
  1. a href="mappingOther/user/aaa/createUser">ant风格</a>

四、REST

1、知识点

  •  浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求,该过滤器为HiddenHttpMethodFilter。
  •  HiddenHttpMethodFilter的父类是OncePerRequestFilter,它继承了父类的doFilterInternal方法,工作原理是将jsp页面的form表单的method属性值在doFilterInternal方法中转化为标准的Http方法,即GET,、POST、 HEAD、OPTIONS、PUT、DELETE、TRACE,然后到Controller中找到对应的方法。例如,在使用注解时我们可能会在Controller中用于@RequestMapping(value = "list", method = RequestMethod.PUT),所以如果你的表单中使用的是<form method="put">,那么这个表单会被提交到标了Method="PUT"的方法中。
  • REST:Representational State Transfer.即(资源)表现层状态转化。
    • 资源(Resources):网络上的一个实体,它可以是一段文本、一张图片、一首歌曲、一种服务等。可以用一个URI指向它。第一种资源对应一个特定的URI.也就是说,URI即为每个资源的独一无二的识别符。
    • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式。
    • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务端。因此,如果客户想要操作服务器,必须通过某种手段,让服务端发生“状态转化”。而这种转化是建立在表现之上的。具体来说,就是HTTP协议里面,四个表示操作方式的动词
      • GET:获取资源
      • POST:新建资源
      • PUT:更新资源
      • DELETE:删除资源
  • 示例
    • /order/1    HTTP GET:得到id=1的order
    • /order/1    HTTP DELETE:删除id=1的order
    • /order/1    HTTP PUT:更新id=1的order
    • /order/1    HTTP POST:新增id=1的order
  • HiddenHttpMethodFilter
    • 浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持
    • Spring3.0添加一个过滤器,可以将这些请求转换为标准的http方法,使其支持GET、POST、PUT与DELETE请求

2、测试

  • 在web.xml文件中HiddenHttpMethodFilter
  1. <filter>
  2. <filter-name>hiddenHttpMethodFilter</filter-name>
  3. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>hiddenHttpMethodFilter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>
  • 控制器
  1. @RequestMapping("/testREST")
  2. @Controller
  3. public class TestREST {
  4. @RequestMapping(value="/testRest/{id}",method=RequestMethod.GET)
  5. public String testRestGet(@PathVariable Integer id){
  6. System.out.println("testRest GET:"+id);
  7. return "success";
  8. }
  9. @RequestMapping(value="/testRest/{id}",method=RequestMethod.POST)
  10. public String testRestPost(@PathVariable Integer id){
  11. System.out.println("testRest POST:"+id);
  12. return "success";
  13. }
  14. @RequestMapping(value="/testRest/{id}",method=RequestMethod.DELETE)
  15. public String testRestDelete(@PathVariable Integer id){
  16. System.out.println("testRest Delete:"+id);
  17. return "success";
  18. }
  19. @RequestMapping(value="/testRest/{id}",method=RequestMethod.PUT)
  20. public String testRestPut(@PathVariable Integer id){
  21. System.out.println("testRest Put:"+id);
  22. return "success";
  23. }
  24. }
  • 请求
  1. <a href="testREST/testRest/1">测试Get</a>
  2. <form action="testREST/testRest/1" method="post">
  3. <input type="submit" value="测试post">
  4. </form>
  5. <form action="testREST/testRest/1" method="post">
  6. <input type="hidden" name="_method" value="DELETE">
  7. <input type="submit" value="测试DELETE">
  8. </form>
  9. <form action="testREST/testRest/1" method="post">
  10. <input type="hidden" name="_method" value="PUT">
  11. <input type="submit" value="测试PUT">
  12. </form>

3、注意

  1. 如果用tomcat8作为服务器,在测试DELETE和Put的时候,会报405错误
        
解决方法有三种
  • 一是将Tomcat8改为Tomcat7,在Tomcat7下运行是正常的.或者升级到tomcat 8.0.9以上版本
  • 二是将请求转发(forward)改为redirect
  • 三是自己手动写一个Filter来包装HttpRequest中的getMethod方法
下面主要介绍一下第三种方法:也就是自己写一个Filter来包装从服务器发回来的HttpRequest请求:

    


大致说一下流程,
 
1. 在第1步中,客户端发送请求至服务器,这时如果发送的是POST请求且带有以_method为名的参数会被Spring的HiddenHttpMethodFilter给拦截。
 
2. HiddenHttpMethodFilter内有一个静态内部类通过继承HttpServletRequestWrapper类并重写getMethod()方法,将该方法返回值设为_method隐藏域的值。
 
3. HiddenHttpMethodFilter在包装好Request后,将请求发往服务器的控制器中对应的方法处理器,这时的请求变成了图中的 3、WrapperRequest by SpringFilter
 
4. 服务器处理完请求后,产生了一个forward请求,产生相应的请求处理信息发往客户端,注意这时的request的getMethod()方法仍然是HiddenHttpMethodFilter包装过的
 
5. 我们需要在服务器的响应请求到达客户端前进行拦截,这也是最关键的一步,通过自定义过滤器 MyMethodConvertingFilter  进一步包装请求,将getMethod()方法返回值改成POST或GET即可 
  1. public class MyMethodConvertingFilter implements Filter {
  2. @Override
  3. public void destroy() {
  4. // TODO Auto-generated method stub
  5. }
  6. @Override
  7. public void doFilter(ServletRequest request, ServletResponse response,
  8. FilterChain chain) throws IOException, ServletException {
  1. chain.doFilter(wrapRequest((HttpServletRequest) request), response);
  1. }
  2. @Override
  3. public void init(FilterConfig arg0) throws ServletException {
  4. // TODO Auto-generated method stub
  5. }
  6. private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) {
  7. return new HttpServletRequestWrapper(request) {
  8. @Override
  9. public String getMethod() {
  10. return "GET";
  11. }
  12. };
  13. }
  14. }
6. 在web.xml中配置该filter,注意dispatcher结点值必须为FORWARD。
  1. <filter-mapping>
  2. <filter-name>myFilter</filter-name>
  3. <url-pattern>/*</url-pattern>
  4. <dispatcher>FORWARD</dispatcher>
  5. </filter-mapping>




关注我们
    师享空间的宗旨是分享知识,传播价值。关注我们,及时获得更多信息。



捐赠我们

    如果您对我们的成果表示认同并且觉得对你有所帮助,欢迎您对我们捐赠^_^。
       








posted @ 2015-12-01 09:45  师享空间  阅读(433)  评论(0编辑  收藏  举报