Java框架之SpringMVC 03-RequestMapping-请求数据-响应数据

SpringMVC

SpringMVC是一种轻量级的、基于MVC的Web层应用框架。

通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。

采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

优点:

  1、天生与Spring框架集成,如:(IOC,AOP)

  2、支持Restful风格

  3、支持灵活的URL到页面控制器的映射

  4、非常容易与其他视图技术集成,如:Velocity、FreeMarker等等

  5、因为模型数据不存放在特定的API里,而是放在一个Model里(Map数据结构实现,因此很容易被其他框架使用)

  6、非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,

  7、更加简单、强大的异常处理

  8、对静态资源的支持

  9、支持灵活的本地化、主题等解析

 常用主要组件

  ① DispatcherServlet:前端控制器
  ② Controller:处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理
  ③ HandlerMapping:请求映射到处理器,找谁来处理,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器对象)
  ④ View Resolver : 视图解析器,找谁来处理返回的页面。把逻辑视图解析为具体的View,进行这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为JSP视图
  ⑤ LocalResolver:本地化、国际化
  ⑥ MultipartResolver:文件上传解析器
  ⑦ HandlerExceptionResolver:异常处理器

Spring MVC 的配置文件

流程分析

基本步骤:

  ①    客户端请求提交到DispatcherServlet

  ②    由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller

  ③    DispatcherServlet将请求提交到Controller(也称为Handler)

  ④    Controller调用业务逻辑处理后,返回ModelAndView

  ⑤    DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

  ⑥    视图负责将结果显示到客户端

标准的 HTTP 请求报头

@RequestMapping

1、使用@RequestMapping 注解来映射请求的 URL    

  @RequestMapping可以应用的地方

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {…}

  请求的方式有

public enum RequestMethod {
        GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
    }

  @RequestMapping可以为控制器指定可以处理哪些 URL 请求,将该注解中的 value 属性值映射成URL,客户端可以通过该URL请求到指定类中的方法。

    1)在控制器的类定义或方法定义处都可标注 @RequestMapping
      ① 标记在类上:提供初步的请求映射信息。相对于 WEB 应用的根目录
      ② 标记在方法上:提供进一步的细分映射信息。相对于标记在类上的 URL。
    2)若类上未标注 @RequestMapping,则方法处标记的 URL 相对于 WEB 应用的根目录 
    3)作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。

  @RequestMapping属性

    value:指定URL路径
    method:指定请求方式 
    params:指定请求参数
    headers:指定请求头信息

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

    1)@RequestMapping 除了可以使用请求 URL 映射请求外,还可以使用请求方法、请求参数及请求头来精确映射对应请求
    2)@RequestMapping 的 value【重点】、method【重点】、params【了解】 及 heads【了解】 分别表示请求 URL、请求方式、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化。即:需满足所有映射条件才可匹配到对应方法
    3)params 和 headers支持简单的表达式:
      param1: 表示请求必须包含名为 param1 的请求参数
      !param1: 表示请求不能包含名为 param1 的请求参数
      param1 != value1: 表示请求包含名为 param1 的请求参数,但其值不能为 value1
      {"param1=value1", "param2"}: 请求必须包含名为 param1 和param2 的两个请求参数,且 param1 参数的值必须为 value1

Ant 路径风格

  Ant 风格资源地址支持 3 种匹配符:【了解】
    ?:匹配文件名中的一个字符
    *:匹配文件名中的任意字符
    **:** 匹配多层路径

/user/*/**/createUser??
匹配 /user/xxx/多层/createUserXX 

REST

REST是什么?因为REST的内涵非常丰富,所以很难用一两句话解释清楚这个问题。首先,REST是Web自身的架构风格。

参考资料:理解本真的REST架构风格  

  REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便

  资源(Resources):资源是一种看待服务器的方式。是网络上的一个实体,可以是一段文本、一张图片,可以用一个URI(统一资源定位符,独一无二的识别符)指向它,获取这个资源,访问它的URI就可以了

  表现层资源的表述(Representation)是一段对于资源在某个特定时刻的状态的描述,即把资源具体呈现出来的形式, 比如,文本可以用 txt 、JSON 格式表现,甚至可以采用二进制格式。

  状态转化(State Transfer):状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。如:每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。

  统一接口(Uniform Interface)REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。例如:HTTP/1.1协议定义了一个操作资源的统一接口。REST还要求,对于资源执行的操作,其操作语义必须由HTTP消息体之前的部分完全表达,不能将操作语义封装在HTTP消息体内部。这样做是为了提高交互的可见性

  超文本驱动(Hypertext Driven)将Web应用看作是一个由很多状态(应用状态)组成的有限状态机。资源之间通过超链接相互关联,超链接既代表资源之间的关系,也代表可执行的状态迁移。即:客户端应该依赖的是超媒体的状态迁移语义,而不应该对于是否存在某个URI或URI的某种特殊构造方式作出假设。一切都有可能变化,只有超媒体的状态迁移语义能够长期保持稳定。

  具体对于HTTP来说,就是 HTTP 协议里面对应的四种常用基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。应使用由客户端定义的请求方式指定对应的某种操作,而不应该通过某种特殊构造方式进行指定

HiddenHttpMethodFilter过滤器

  浏览器 form 表单只支持 GET 与 POST 请求,HiddenHttpMethodFilter 可以将POST请求转换为标准的 http 方法以达到REST风格

使用步骤

  1. 必须将form表单中的method设置为POST
  2. 提交表单时,必须提交"_method"参数,一般使用隐藏域

    原因:HiddenHttpMethodFilter过滤器将HttpServletRequest中的getMethod()方法,重写啦。

    <!--    配置处理请求方式-->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

处理请求数据

  Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。

  可以对方法及方法入参标注相应的注解( @PathVariable 、@RequestParam、@RequestHeader 等)

@PathVariable请求占位符

  是 Spring3.0 新增的功能,通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中

//@PathVariable 注解可以将请求URL路径中的请求参数,传递到处理请求方法的入参中
// 浏览器的请求为:  testPathVariable/1001
@RequestMapping(value="/testPathVariable/{id}",method=RequestMethod.DELET)
public String testPathVariable(@PathVariable("id") Integer id) {}

@RequestParam请求参数

  如果请求参数与形参不一致时,可以使用@RequestParam注解实现获取参数值

  书写位置:标注在方法的参数中,springMVC默认会将请求参数注入(绑定)到方法形参中(两个参数名一致)

  一旦使用该注解,必须为相应参数传参数。如果未传参,会报错:400,因为required默认为 true,

  value:用于映射请求参数名称

  required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常

  defaultValue: 默认值,当没有传递参数时使用该值作为默认值,不设默认为 null

 @RequestMapping(value="/testRequestParam?username=guigu&age=10")
    public String testRequestParam(
            @RequestParam(value="username") String username,
            @RequestParam(value="age",required=false,defaultValue="0") int age){
        return "success";
    }

 

@RequestHeader 请求头

  获取请求头信息,请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中 

@CookieValue 

  获取指定的Cookie信息,可让处理方法入参绑定某个 Cookie 值

使用POJO作为参数

  Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值支持级联属性

    @RequestMapping(value = "/emps",method = RequestMethod.PUT)
    public String updateEmp(Employee employee){
        employeeDao.save(employee);
        return "redirect:/emps";
    }
   //Spring MVC 会按请求参数名和 Employee 属性名进行自动匹配, 自动为该对象填充属性值。支持级联属性

 

配置字符编码过滤器

    <!--    处理POST请求和响应乱码-->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

GET请求乱码

  • GET请求参数是在地址后面的。我们需要修改tomcat的配置文件。需要在server.xml文件修改Connector标签,添加URIEncoding="utf-8"属性。

使用Servlet原生API

    /**
     * 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型
     * HttpServletRequest 
     * HttpServletResponse 
     * HttpSession
     * java.security.Principal 
     * Locale 
   * InputStream * OutputStream * Reader * Writer
*/ @RequestMapping("/testServletAPI") public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException { System.out.println("testServletAPI, " + request + ", " + response); out.write("hello springmvc"); }

 

处理响应数据

2、返回值会通过视图解析器解析为实际的物理视图

输出模型数据类型

  1)    ModelAndView: 作为返回值类型,响应数据:处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据

  2)  String: 作为返回值类型,即为视图信息直接找字符串映射 URL 路径,转发或重定向

  3)    Map 或 Model: 作为参数,响应数据:入参为 Model、ModelMap 或  Map,处理方法返回时,Map 中的数据会自动添加到模型中。

ModelAndView

  控制器处理方法的返回值如果为 ModelAndView, 则其包含视图信息包含模型数据信息

  1)  两个重要的成员变量:

    private Object view;                       【视图信息】

    private ModelMap model;              【模型数据】

  2)添加模型数据:

    MoelAndView addObject(String attributeName, Object attributeValue)   【设置模型数据】

    ModelAndView addAllObject(Map<String, ?> modelMap)

  4)设置视图:

    void setView(View view)                         【设置视图对象】

    void setViewName(String viewName)            【设置视图名字】

  5)获取模型数据

    protected Map<String, Object> getModelInternal()   【获取模型数据】

    public ModelMap getModelMap()

    public Map<String, Object> getModel()

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        String viewName = "success";
        ModelAndView mv = new ModelAndView(viewName);
        mv.addObject("time",new Date().toString()); //实质上存放到request域中 
        return mv;
    }

ModelAndView 底层工作原理,不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,将数据放到request域中,再通过转发实现页面跳转

Map   Model

  Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据

  Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器

  如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。

  在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据

    //目标方法的返回类型也可以是一个Map类型参数(也可以是Model,或ModelMap类型)
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map) { //【重点】
        System.out.println(map.getClass().getName());
    //org.springframework.validation.support.BindingAwareModelMap
        map.put("names", Arrays.asList("Tom", "Jerry", "Kite"));
        return "success";
    }

 

注意问题:Map集合的泛型,key为String,Value为Object,而不是String

由源码可知:不论用那个类型作为数据模型,其内部都会转化为BindingAwareModelMap类型使其指向同一map对象

BindingAwareModelMap底层支持两种接口(Map&Model)推荐使用 Map 便于框架移植

posted @ 2020-01-19 21:42  远离颠倒梦想  阅读(...)  评论(...编辑  收藏