zoukankan      html  css  js  c++  java
  • SpringMVC请求输入与请求响应

    SpringMVC请求输入

    1. 请求处理方法签名

    • Spring MVC 通过分析处理方法的签名,HTTP请求信息绑定到处理方法的相应人参中。

    • Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名。

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

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

    2.常见注解

    2.1 @RequestParam注解

    在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法

    • value:参数名

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

    • defaultValue: 默认值,当没有传递参数时使用该值

    实验代码

    增加控制器方法

    /**
     * @RequestParam 注解用于映射请求参数
     *         value 用于映射请求参数名称
     *         required 用于设置请求参数是否必须的
     *         defaultValue 设置默认值,当没有传递参数时使用该值
     */
    @RequestMapping(value="/testRequestParam")
    public String testRequestParam(
    @RequestParam(value="username") String username,
    @RequestParam(value="age",required=false,defaultValue="0") int age){
    System.out.println("testRequestParam - username="+username +",age="+age);
    return "success";
    }
    

    2.2. @RequestHeader 注解

    • 使用 @RequestHeader 绑定请求报头的属性值

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

    实验代码

    //了解: 映射请求头信息 用法同 @RequestParam
    @RequestMapping(value="/testRequestHeader")
    public String testRequestHeader(@RequestHeader(value="Accept-Language") String al){
    System.out.println("testRequestHeader - Accept-Language:"+al);
    return "success";
    }
    

    2.3. @CookieValue 注解

    • 使用 @CookieValue 绑定请求中的 Cookie 值

    • @CookieValue 可让处理方法入参绑定某个 Cookie 值

    实验代码

    //了解:@CookieValue: 映射一个 Cookie 值. 属性同 @RequestParam
    @RequestMapping("/testCookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
       System.out.println("testCookieValue: sessionId: " + sessionId);
       return "success";
    }
    

    2.4 使用POJO作为参数

    • 使用 POJO 对象绑定请求参数值

    • Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等

    实验代码

    ① 增加控制器方法、表单页面

    /**
     * Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值。
     * 支持级联属性
     *                 如:dept.deptId、dept.address.tel 等
     */
    @RequestMapping("/testPOJO")
    public String testPojo(User user) {
    System.out.println("testPojo: " + user);
    return "success";
    }
    

    如果中文有乱码,需要配置字符编码过滤器,且配置其他过滤器之前,如(HiddenHttpMethodFilter),否则不起作用。(思考method=”get”请求的乱码问题怎么解决的)

    	<!-- 配置字符集 -->
    	<filter>
    		<filter-name>encodingFilter</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>encodingFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    

    2.5 使用Servlet原生API作为参数

    /**
     * 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型
     * 
     * HttpServletRequest 
     * HttpServletResponse 
     * HttpSession
     * java.security.Principal 
     * Locale InputStream 
     * OutputStream 
     * Reader 
     * Writer
     * @throws IOException 
     */
    @RequestMapping("/testServletAPI")
    public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException {
    System.out.println("testServletAPI, " + request + ", " + response);
    out.write("hello springmvc");
    //return "success";
    }
    
    <!-- 测试 Servlet API 作为处理请求参数 -->
    <a href="springmvc/testServletAPI">testServletAPI</a>
    
    

    SpringMVC响应输出

    提供了以下几种途径输出模型数据:

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

    • Map 及 Model: 入参为 org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。

    • @SessionAttributes: 将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性

    • @ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中

    image-20210420094342509

    3.处理模型数据之 ModelAndVieW

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

    ② 添加模型数据:

    MoelAndView addObject(String attributeName, Object attributeValue)

    ModelAndView addAllObject(Map<String, ?> modelMap)

    ③ 设置视图:

    void setView(View view)

    void setViewName(String viewName)

    实验代码

    /**
     * 目标方法的返回类型可以是ModelAndView类型
     *                 其中包含视图信息和模型数据信息
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
    System.out.println("testModelAndView");
    String viewName = "success";
    ModelAndView mv = new ModelAndView(viewName );
    mv.addObject("time",new Date().toString()); //实质上存放到request域中 
    return mv;
    }
    

    4. 处理模型数据之 Map

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

    具体使用步骤

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

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

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

    //目标方法的返回类型也可以是一个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

    ② 测试参数类型

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

    image-20210420141118357

    5.处理模型数据之 SessionAttributes 注解

    若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC 将在模型中对应的属性暂存到 HttpSession 中。

    @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。

    例如:

    ① @SessionAttributes(types=User.class) 会将隐含模型中所有类型为 User.class 的属性添加到会话中。

    ② @SessionAttributes(value={“user1”, “user2”})

    ③ @SessionAttributes(types={User.class, Dept.class})

    ④ @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})

    实验代码

    @Controller
    //@SessionAttributes("user")
    @SessionAttributes(value={"user"},types={String.class})
    public class SpringMVCController {
    /**
     * @SessionAttributes
     *  除了可以通过属性名指定需要放到会话中的属性外(实际上是通过value指定key值),
     *  还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上是通过types指定类型)
     * 注意:只能放在类的上面,不能修饰方法
     */
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map<String,Object> map){
    User user = new User("Tom","123","tom@dalianpai.com",22);                
    map.put("user", user);
    map.put("school", "dalianpai");  
    //默认是被存放到request 域,如果设置了@SessionAttribute注解,就同时存放到session域中
    return "success";
    }
    }
    
    <!--测试 @SessionAttribute 将数据存放到session域中 -->
    <a href="testSessionAttributes">testSessionAttributes</a>
    

    6.@ModelAttribute注解

    6.1 使用场景

    image-20210420142436195

    场景一句话概括就是:当进行修改的时候,其实只想修改一个字段,但是容易对别的值,进行覆盖掉,当加了这个注解以后,每次执行方法的时候,先去执行@ModelAttribute的这个标准的方法,然后要把修改的值进行替换即可。

    6.2@ModelAttribute注解之示例代码

    • 在方法定义上使用 @ModelAttribute 注解:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了 @ModelAttribute 的方法。

    • 在方法的入参前使用 @ModelAttribute 注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参

    • 将方法入参对象添加到模型中

    ① 页面表单

    <!--测试 @ModelAttribute 类似Struts2框架的模型驱动 -->
    <!-- 
    模拟修改操作:
    1.原始数据为:1,Tom,123456,tom@atguigu.com,12
    2.密码不需要修改
    3.表单回显,模拟操作直接在表单value属性上赋值
     -->
    <form action="springmvc/testModelAttribute" method="POST">
    <input type="hidden" name="id" value="1"><br>
    username: <input type="text" name="username" value="Tom"/><br>
    email: <input type="text" name="email" value="tom@atguigu.com"/><br>
    age: <input type="text" name="age" value="12"/><br>
    <input type="submit" value="Submit"/>                
    </form>
    

    ② 增加@ModelAttribute注解

    //1. 由 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用!
    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(User user){
    System.out.println("user="+user);                
    return "success";
    }
     
    @ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,Map<String,Object> map){
    if(id!=null){        
    //模拟从数据库中获取到的user对象
    User user = new User(1,"Tom","123456","tom@atguigu.com",12);
    System.out.println("从数据库中查询的对象:user="+user );
    map.put("user", user);
    }
    }
    

    6.3 @ModelAttribute注解之运行原理

    运行原理

    ① 执行@ModelAttribute注解所修饰的方法,将从数据库中获取的对象存放到Map集合中,key为user

    ② SpringMVC从Map集合中获取 user对象,将表单数据封装到与参数名称对应的user对象属性上

    ③ SpringMVC将user对象作为参数,传递给目标方法。

    注意:@ModelAttribute 注解修饰的方法中,放入到Map集合中的key值,应该和目标方法参数类型的类名称首字母小写一致。

    6.4 @ModelAttribute注解之源码分析

    源代码分析的流程

    ① 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.

    ② 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性

    1). 创建 WebDataBinder 对象:

    ​ 【1】确定 objectName 属性: 若传入的 attrName 属性值为 "", 则 objectName 为类名第一个字母小写.

    注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则attrName 值即为 @ModelAttribute 的 value 属性值

    ​ 【2】确定 target 属性:

    ​ - 在 implicitModel 中查找 attrName 对应的属性值. 若存在, ok

    ​ - 若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中获取 attrName 所对应的属性值.

    ​ - 若 session 中没有对应的属性值, 则抛出了异常.

    ​ - 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key和 attrName 相匹配, 则通过反射创建了 POJO 对象

    2). SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性.

    3). SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel. 进而传到 request 域对象中.

    4). 把 WebDataBinder 的 target 作为参数传递给目标方法的入参.

    7. @ResponseStatus注解的使用

    带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析。可以实现自定义的一些异常,同时在页面上进行显示。具体的使用方法如下:

    /**
     * @author WGR
     * @create 2021/4/20 -- 14:57
     */
    @ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "用户名和密码不匹配!")
    public class UserNameNotMatchPasswordException extends RuntimeException{
    
    }
    
    /**
     * @author WGR
     * @create 2021/4/20 -- 14:54
     */
    @Controller
    public class TestController {
    
        @RequestMapping("/testResponseStatusExceptionResolver")
        public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
            if (i==13){
                throw new UserNameNotMatchPasswordException();
            }
            System.out.println("testResponseStatusExceptionResolver....");
            return "success";
        }
        
    }
    

    image-20210420150142926

    8. @RequestAttribute

    尝试访问一个request中不存在的值时,@RequestAttribute抛出异常:

    @RequestMapping("/demo1")
        public String demo1(@RequestAttribute String name){
            System.out.println(name);
            return "test";
        }
    
    @ModelAttribute
    public void storeEarly(HttpServletRequest request){
        request.setAttribute("name","dalianpai");
    }
    
  • 相关阅读:
    I NEED A OFFER!
    水题 Codeforces Round #303 (Div. 2) A. Toy Cars
    模拟 HDOJ 5099 Comparison of Android versions
    模拟 HDOJ 5095 Linearization of the kernel functions in SVM
    贪心 HDOJ 5090 Game with Pearls
    Kruskal HDOJ 1863 畅通工程
    Kruskal HDOJ 1233 还是畅通工程
    并查集 HDOJ 1232 畅通工程
    DFS/并查集 Codeforces Round #286 (Div. 2) B
    水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta's Gift
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14681600.html
Copyright © 2011-2022 走看看