Spring MVC—请求参数获取、请求参数绑定、原生API、常用注解、页面转发

4.SpringMVC的使用(1)

1、SpringMVC请求参数的处理

在之前的servlet中我们可以通过request.getParameter()来获取请求中的参数,但是在我们编写的SpringMVC的应用程序中,在具体请求的方法中并不包含request参数。采用注解的方式获取请求参数

  • 如何获取SpringMVC中请求中的信息

    默认情况下,可以直接在方法的参数中填写跟请求一样的名称,此时会默认接受参数如果有值,直接赋值,如果没有,那么直接给空值。

  • 需要使用的有以下几个注解

    1. @RequestParam:获取请求的参数
    2. @RequestHeader:获取请求头信息
    3. @CookieValue:获取Cookie中的值
1、@RequestParam
  1. 功能:获取请求中的参数值,使用此注解之后,参数的名称不需要跟请求的名称一致,但是必须要写

     public String request(@RequestParam("user") String username)
     //相当于servlet中的request.getParameter("user");   
    
  2. 此注解还包含三个参数

    1. value:表示要获取的参数值
    2. 表示此参数是否必须,默认是true,如果不写参数那么会报错,如果值为false,那么不写参数不会有任何错误
    3. defaultValue:如果在使用的时候没有传递参数,那么定义默认值即可
  3. 演示

      @RequestMapping(value = "/request")
        public String rest(@RequestParam(value = "name",required = false) String username){
            System.out.println( username);
            return "success";
        }
    
2、@RequestHeder
  1. 功能:获取请求头信息

    public String header(@RequestHeader("User-Agent") String agent)
    //request.getHeader("User-Agent")
    //User-Agent:告知访问者是用什么工具类请求的 
    
  2. 三个参数:

    1. value:表示要获取的参数值(请求头),如果要获取请求头中没有的信息,那么此时会报错
    2. 表示此参数是否必须,默认是true,如果不写参数那么会报错,如果值为false,那么不写参数不会有任何错误
    3. defaultValue:如果在使用的时候没有传递参数,那么定义默认值即可
  3. 演示

     @RequestMapping(value = "/request")
        public String rest(@RequestHeader(value = "User-Agent",required = false) String Agent){
            System.out.println( Agent);
            return "success";
        }
    
3、@CookieValue
  1. 功能:获取Cookie中的值,如果要获取cookie中没有的信息,那么此时会报错,同样,此注解中也包含三个参数,跟@RequestParam一样。

    public String cookie(@CookieValue("JSESSIONID") String id)
    //相当于servlet中的request.getCookies();
    
  2. 三个参数

    1. value:表示要获取Cookie中的参数值,如果要获取cookie中没有的信息,那么此时会报
    2. 表示此参数是否必须,默认是true,如果不写参数那么会报错,如果值为false,那么不写参数不会有任何错误
    3. defaultValue:如果在使用的时候没有传递参数,那么定义默认值即可
  3. 演示

    @RequestMapping("/cookie")
        public String cookie(@CookieValue("JSESSIONID") String id){
            System.out.println(id);
            return "success";
        }
    
2、请求参数的绑定

我们都知道,表单中请求参数都是基于 key=value 的。 SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。

1、绑定说明
  1. 支持的数据类型

    • 基本数据类型和String类型
    • POJO类型(包括实体类)
    • 数组和集合类型(数组,list,map)
  2. 使用要求

    • 基本数据类型和String类型:要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)

    • POJO类型:要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。

    • 数组和集合类型:在表单中请求参数名称要和 POJO 中集合属性名称相同,给 List 集合中的元素赋值,使用下标。给 Map 集合中的元素赋值,使用键值对。

2、基本数据类型和String类型的演示
  1. 访问:http://localhost:8080/date?id=1&name=haha

  2. 代码:

    @Controller
    public class datatypecontroller {
        @RequestMapping("/date")
        public String data(Integer id, String name) {
            System.out.println(id + "    " + name);
            return "success";
        }
    }
    
3、POJO类型的演示
  • 不含集合的POJO类

    1. 创建POJO类

      user.java

      package com.mvc.bean;
      
      public class User {
      
          private  Integer id;
          private  String name;
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      '}';
          }
      }
      

      Address.java

      public class Address {
          private String province;
          private String city;
          private String town;
      
          public String getProvince() {
              return province;
          }
      
          public void setProvince(String province) {
              this.province = province;
          }
      
          public String getCity() {
              return city;
          }
      
          public void setCity(String city) {
              this.city = city;
          }
      
          public String getTown() {
              return town;
          }
      
          public void setTown(String town) {
              this.town = town;
          }
      
          @Override
          public String toString() {
              return "Address{" +
                      "province='" + province + '\'' +
                      ", city='" + city + '\'' +
                      ", town='" + town + '\'' +
                      '}';
          }
      }
      
      
    2. 控制层

      @RequestMapping("/pojo")
          public String data(User user) {
              System.out.println(user);
              return "success";
          }
      
      
    3. 创建login.jsp页面

      <%--
        Created by IntelliJ IDEA.
        User: Lenovo
        Date: 2021/3/22
        Time: 10:57
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <%
      pageContext.setAttribute("ctp",request.getContextPath());
      %>
      <body>
      <form action="${ctp}/pojo" method="post">
              编号:<input type="text" name="id"/><br>
              姓名:<input type="text" name="name"/><br>
              省份:<input type="text" name="address.province"/><br>
              城市:<input type="text" name="address.city"/><br>
              区域:<input type="text" name="address.town"/><br>
              <input type="submit" value="submit"/><br>
      </form>
      </body>
      </html>
      
      
      
    4. 访问,login.jsp,填入数据。访问成功。

  • 含集合的POJO类演示

    1. 创建POJO类

      package com.mvc.bean;
      
      public class Address {
          private String city;
          private String town;
      
      
          public String getCity() {
              return city;
          }
      
          public void setCity(String city) {
              this.city = city;
          }
      
          public String getTown() {
              return town;
          }
      
          public void setTown(String town) {
              this.town = town;
          }
      
          @Override
          public String toString() {
              return "Address{" +
                      "city='" + city + '\'' +
                      ", town='" + town + '\'' +
                      '}';
          }
      }
      
      -------------------------
      package com.mvc.bean;
      
      import java.io.Serializable;
      import java.util.List;
      import java.util.Map;
      
      public class User {
      
          private Integer id;
          private String name;
          private List<Address> list;
          private Map<String, Address> map;
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public List<Address> getList() {
              return list;
          }
      
          public void setList(List<Address> list) {
              this.list = list;
          }
      
          public Map<String, Address> getMap() {
              return map;
          }
      
          public void setMap(Map<String, Address> map) {
              this.map = map;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", list=" + list +
                      ", map=" + map +
                      '}';
          }
      }
      
      
      
  1. 控制层

      @RequestMapping("/pojo")
          public String data(User user) {
              System.out.println(user);
              return "success";
          }
    
    
  2. login.jsp页面

      <form action="${ctp}/pojo" method="post">
              编号:<input type="text" name="id"/><br>
              姓名:<input type="text" name="name"/><br>
              省份:<input type="text" name="list[0].city"/><br>
              城市:<input type="text" name=list[0]town."/><br>
              省份:<input type="text" name="map[one].city"/><br>
              城市:<input type="text" name="map[one].town"/><br>
              <input type="submit" value="submit"/><br>
      </form>
    
    
  3. 访问login.jsp页面,填入数据,访问成功。

3、乱码问题的解决
1、GET请求
  • 在server.xml文件中,添加URIEncoding=“UTF-8”

  • 步骤:进入tomcat–》conf—》server.xml文件。修改

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"  URIEncoding="UTF-8" />

2、POST请求
  • 在web.xml中编写过滤器实现

        <!--设置编码格式-->
        <filter>
            <filter-name>encoding</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>encoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
  • 注意:如果有其他的过滤器,编码格式过滤器应该放在第一位,否则会失效。

4.SpringMVC对原生API的支持
  • SpringMVC可以在参数上使用原生Servlet API

  • Servlet API

    • HttpServletRequest

    • HttpServletResponse

    • HttpSession

    • ava.security.Principal 安全协议相关

    • Locale:国际化相关的区域信息对象

    • InputStream

    • OutputStream

    • Reader Writer

  • 演示

      @RequestMapping("/api")
        public String api(HttpServletRequest request, HttpServletResponse response){
            System.out.println(request);
            System.out.println(response);
            return "success";
        }
    
    
5、常用注解(传递参数)

在刚开始的helloworld项目中,我们传递了参数回到我们页面,但是后续的操作都只是接受用户的请求,那么在SpringMVC中除了可以使用原生servlet的对象传递数据之外,还有什么其他的方式呢?

1、使用Model,Map,ModelMap传输数据到页面
  1. 演示

    写好OutputController类,在jsp中用四种内置对象分别获取参数值,最终所有参数值都在request作用域中

    @Controller
    public class OutputController {
    
        @RequestMapping("output1")
        public String output1(Model model){
            model.addAttribute("msg","hello,Springmvc");
            return "output";
        }
    
        @RequestMapping("output2")
        public String output2(ModelMap model){
            model.addAttribute("msg","hello,Springmvc");
            return "output";
        }
    
        @RequestMapping("output3")
        public String output1(Map map){
            map.put("msg","hello,Springmvc");
            return "output";
        }
    }
    
    
  2. jsp有4大作用域,分别是page、reques、session、application,经过测试,所有的是参数值都会到request作用域中。上面的三个对象是什么关系呢?

在这里插入图片描述

2、使用ModelAndView对象传输数据到页面
  1. 演示

    @Controller
    public class OutputController {
    
        @RequestMapping("mv")
        public ModelAndView mv(){
            ModelAndView mv = new ModelAndView();
            mv.setViewName("output");
            mv.addObject("msg","hello.modelAndView");
            return mv;
        }
    }
    
    
  2. 发现当使用modelAndView对象的时候,返回值的类型也是此对象,可以将要跳转的页面设置成view的名称,来完成跳转的功能,同时数据也是放到request作用中。

3、使用session传输数据到页面
  1. 由于上面我们都知道。将数据传输到页面,使用的是map、model、modelmap,三种方法都是将数据存入request作用域中,那我们想要将数据存入session中怎么办呢,为什要将数据存入session中,因为session可以存储用户的个人信息。此时可以使用SessionAttribute注解。

  2. @SessionAttribute:此注解可以表示,当向request作用域设置数据的时候同时也要向session中保存一份,此注解有两个参数,一个value(表示将哪些值设置到session中),另外一个type(表示按照类型来设置数据,一般不用,因为有可能会将很多数据都设置到session中,导致session异常)。

  3. 演示

    @Controller
    @SessionAttributes(value = "msg")
    public class OutputController {
        @RequestMapping("output1")
        public String output1(Model model){
            model.addAttribute("msg","hello,Springmvc");
            System.out.println(model.getClass());
            return "output";
        }
    }
    
    
3、使用@ModelAttribute来获取请求中的数据
  1. @ModelAttribute注解用于将方法的参数或者方法的返回值绑定到指定的模型属性上,并返回给web视图。首先来介绍一个业务场景,来帮助大家做理解,在实际工作中,有些时候我们在修改数据的时候可能只需要修改其中几个字段,而不是全部的属性字段都获取,那么当提交属性的时候,从form表单中获取的数据就有可能只包含了部分属性,此时再向数据库更新的时候,肯定会丢失属性,因为对象的封装是springmvc自动帮我们new的,所以此时需要先将从数据库获取的对象保存下来,当提交的时候不是new新的对象,而是在原来的对象上进行属性覆盖,此时就需要使用@ModelAttribute注解。

  2. 演示

    User.java

    package com.mashibing.bean;
    
    public class User {
        private Integer id;
        private String name;
        private String password;
        private Integer age;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", password='" + password + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    

    UserController.java

    package com.mashibing.controller;
    import com.mashibing.bean.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class UserController {
    
        Object o1 = null;
        Object o2 = null;
        Object o3 = null;
    
        @RequestMapping("update")
        public String update(@ModelAttribute("user") User user,Model model){
            System.out.println(user);
            o2 = model;
            //可以看到所有的model都是同一个对象
            System.out.println(o1==o2);
            //可以看到存储的user对象也是同一个
            System.out.println(user == o3);
            return "output";
        }
    
        @ModelAttribute
        public void MyModelAttribute(Model model){
            o1 = model;
            User user = new User();
            user.setId(1);
            user.setName("张三");
            user.setAge(12);
            user.setPassword("123");
            model.addAttribute("user",user);
            System.out.println("modelAttribute:"+user);
            o3 = user;
        }
    }
    
    

    jsp

    <%--
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>$Title$</title>
      </head>
      <body>
      <form action="update" method="post">
        <input type="hidden" value="1" name="id">
        姓名:张三<br>
        密码:<input type="text" name="password"><br>
        年龄:<input type="text" name="age"><br>
        <input type="submit" value="提交">
      </form>
      </body>
    </html>
    
    
    
    • 原理分析: @ModelAttribute使用在方法上时,会优先加载该方法,该方法创建user方法,并进行属性赋值,完成后将user对象传入model中(设置id=user),加载完成后。在方法参数加@ModelAttribute注解,将model中的对象传给参数(根据id获取)。当在jsp页面赋值的时候,实际上是拿被@ModelAttribute注解方法中的user对象进行属性覆盖。该对象地址没有改变,只是对象的属性改变了。简单来说就是MyModelAttribute()方法优先加载,获取到user对象,并将对象传给update()方法,在jsp页面输入其实就是在覆盖user的属性值
  3. 其实在使用的时候可以简化写法,也就是说,在方法的参数上不加@ModelAttribute也不会有问题,但是参数User的属性user必须和 model.addAttribute(“user”,user);中设置的属性一致。

        @RequestMapping("update")
        public String update(User user,Model model){
            System.out.println(user);
            o2 = model;
            //可以看到所有的model都是同一个对象
            System.out.println(o1==o2);
            //可以看到存储的user对象也是同一个
            System.out.println(user == o3);
            return "output";
        }
    
    
  4. 如果添加的@ModelAttribute(“”)属性的值不对,那么也是获取不到值的。同时可以添加@SessionAttributes属性,但是注意,如果没有设置值的话,会报错

    @Controller
    @SessionAttributes("u")
    public class UserController {
    
        Object o1 = null;
        Object o2 = null;
        Object o3 = null;
    
        @RequestMapping("update")
        public String update(@ModelAttribute("u") User user,Model model){
            System.out.println(user);
            o2 = model;
            //可以看到所有的model都是同一个对象
            System.out.println(o1==o2);
            //可以看到存储的user对象也是同一个
            System.out.println(user == o3);
            return "output";
        }
    
        @ModelAttribute
        public void MyModelAttribute(Model model){
            o1 = model;
            User user = new User();
            user.setId(1);
            user.setName("张三");
            user.setAge(12);
            user.setPassword("123");
            model.addAttribute("user",user);
            System.out.println("modelAttribute:"+user);
            o3 = user;
        }
    }
    
    
    
    • model.addAttribute(“user”,user);也就是说存入将user存入request中,并设置id=user,当时在获取的时候@ModelAttribute(“u”)和SessionAttributes(“u”)获取的id都是u,因此获取不到,将会报错。
  5. 总结:通过刚刚的给参数赋值,大家应该能够发现,当给方法中的参数设置值的时候,如果添加了@ModelAttribute注解,那么在查找值的时候,是遵循以下方式:

    1. 方法的参数使用参数的类型首字母小写,或者使用@ModelAttribute("")的值
    2. 先看之前是否在model中设置过该属性值,如果设置过就直接获取
    3. 看@SessionAttributes注解标注类中的方法是否给session中赋值,如果有的话,也是直接获取,没有报异常
4、使用forward实现页面转发
  1. ​ 在发送请求的时候,可以通过forward:来实现转发的功能:

  2. 演示:两种使用方法

    package com.mashibing.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class ForWardController {
    
        /**
         * 当使用转发的时候可以添加前缀forward:index.jsp,此时是不会经过视图解析器的,所以要添加完整的名称
         *
         * forward:也可以由一个请求跳转到另外一个请求
         *
         * @return
         */
        @RequestMapping("/forward01")
        public String forward(){
            System.out.println("1");
            return "forward:/index.jsp";
        }
    
    //实现多重转发
        @RequestMapping("/forward02")
        public String forward2(){
            System.out.println("2");
            return "forward:/forward01";
        }
    }
    
    
5、使用redirect来实现重定向
  1. 在发送请求的时候,可以通过redirect:来实现重定向的功能

  2. 演示:两种使用方法

    @Controller
    public class RedirectController {
    
    
        /**
         * redirect :重定向的路径
         *      相当于 response.sendRedirect("index.jsp")
         *      跟视图解析器无关
         * @return
         */
        @RequestMapping("redirect")
        public String redirect(){
            System.out.println("redirect");
            return "redirect:/index.jsp";
        }
    
        //双重
        @RequestMapping("/redirect2")
        public String redirect2(){
            System.out.println("redirect2");
            return "redirect:/redirect";
        }
    }
    
    
    
6、转发和冲定向的区别
  • 转发:由服务器的页面进行跳转,不需要客户端重新发送请求:

    1. 地址栏的请求不会发生变化,显示的还是第一次请求的地址

    2. 请求的次数,有且仅有一次请求

    3. 请求域中的数据不会丢失

    4. 根目录:localhost:8080/项目地址/,包含了项目的访问地址

      在这里插入图片描述

  • 重定向:在浏览器端进行页面的跳转,需要发送两次请求(第一次是人为的,第二次是自动的)

    1. 地址栏的地址发生变化,显示最新发送请求的地址

    2. 请求次数:2次

    3. 请求域中的数据会丢失,因为是不同的请求

    4. 根目录:localhost:8080/ 不包含项目的名称

在这里插入图片描述

  • 对比
区别转发forward()重定向sendRedirect()
根目录包含项目访问地址没有项目访问地址
地址栏不会发生变化会发生变化
哪里跳转服务器端进行的跳转浏览器端进行的跳转
请求域中数据不会丢失会丢失
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值