Spring MVC学习随笔-控制器(Controller)开发详解:接受客户端(Client)请求参数

news2025/1/23 10:42:05

学习视频:孙哥说SpringMVC:结合Thymeleaf,重塑你的MVC世界!|前所未有的Web开发探索之旅

第三章、SpringMVC控制器开发详解

3.1 核心要点

3.2 控制器接受客户端(client)请求参数详解

3.2.1 回顾:Web开发中如何接受Client请求参数

3.2.2 基于Servlet API接受Client请求参数

@Controller
@RequestMapping("/param")
public class ParamController {

    @RequestMapping("param1")
    public String param(HttpServletRequest request) {
        String name = request.getParameter("name");
        String password = request.getParameter("password");

        System.out.println("name = " + name);
        System.out.println("password = " + password);
        return  "param1";
    }
}
**注意:这种方式虽然最为直观,简单,但是代码冗余且与ServletAPI存在耦合,所以在SpringMVC开发中并不建议使用**

3.2.3 基于简单变量接受Client请求参数

  1. 所谓简单变量:指的就是8种基本类型+String这些类型的变量。把这些类型的变量,作为控制器方法的形参,用于接受client提交的数据。
  • 思路分析

  • 代码

    @Controller
    @RequestMapping("/param")
    public class ParamController {
    
        @RequestMapping("param2")
        public String param2(String name,String password) {
    
            System.out.println("name = " + name);
            System.out.println("password = " + password);
            return  "param1";
        }
    }
    
  • 细节分析

    • 常见类型自动转换

      @RequestMapping("param3")
      public String param3(String name,int age) {
          System.out.println("name = " + name);
          System.out.println("age = " + age);
          return  "param1";
      }
      
      SpringMVC底层针对age接受数据时会自动调用 int age = Integer.parseInt("10")
      
      1. 常见类型泛指:8种基本类型及其包装器,String等常见类型。
      2. Date日期等特殊类型,默认不支持,需要程序员自定义类型转换器【后续讲解】
    • 基本类型尽量使用包装器

      客户端请求:http://localhost:8989/param/param/param3?name=jack
      @Controller
      @RequestMapping("/param")
      public class ParamController {
      
          @RequestMapping("param3")
          public String param3(String name,int age) {
              System.out.println("name = " + name);
              System.out.println("age = " + age);
              return  "param1";
          }
      }
      程序报错:原因在于age没有提交内容,等同于null,而int是基本类型无法存储null值,所以报错
      改正方式:1.age参数使用包装器类型,可以存储null2.为age参数设置默认值,需要@RequestParam注解配合使用。
      

3.2.4 基于POJO类型接受Client请求参数

  • 什么是POJO
    1. POJO全称叫做 Plain Ordinary Java Object(简单的Java对象)
    2. POJO类型对象的特点是:
      1. 类型中如果存在成员变量,必须提供set get
      2. 提供默认无参构造
      3. 可以实现Serializable,也可以不实现
      4. 不实现容器或者框架所规定的接口
    3. 用户根据业务封装的实体,DTO这些类型就是POJO
  • 使用场景

准备一个实体,成员变量名字要和表单的name对应,其次在控制器方法中,将POJO类作为形参类型定义在控制器方法参数中。
  • 代码

    // POJO
    public class User implements Serializable {
        private String name;
        private String password;
        private int age;
    
    // Controller
    @RequestMapping("param4")
        public String param4(User user) {
            System.out.println("user = " + user);
            return  "param1";
        }
    // 表单请求
    <form method="post" action="${pageContext.request.contextPath}/param/param4">
        UserName <input type="text" name="name"><br>
        Password <input type="text" name="password"><br>
        Age <input type="text" name="age"><br>
        <input type="submit" value="reg">
    </form>
    **POJO的成员变量的名字要和请求参数的key或者表单name属性的值严格对应**
    
  • 注意1.提交的表单中的name和控制器方法的name同名,那么谁会获取到内容?

    http://localhost:8989/param/param/param4?name=小明&age=12&password=12
    @RequestMapping("param4")
        public String param4(**String name**,User user) {
            System.out.println("user = " + user);
            return  "param1";
     }
    **name形参与user对象的name属性都会获取对应的内容,这个特定在后续前后端分离中会使用。**
    
  • 注意2.

    1. 如果SpringMVC发现控制器形参类型,是8种基本类型+String的话,他会通过形参名与请求参数的key对象,接受数据
    2. 如果SpringMVC发现控制器形参类型,不是8种基本类型+String的话,他会通过形参类型的属性名与请求参数的key对象,接受数据
    3. 如果存在自定义类型转换器不适用于上述规律

3.2.5 接受一组简单变量的请求参数

  • 使用场景

  • 代码

    @RequestMapping("param5")
    public String param5(Integer[] ids) {
        for (Integer id : ids) {
            System.out.println("id = " + id);
        }
        return  "param1";
    }
    // checkbox表单
    <form method="post" action="${pageContext.request.contextPath}/param/param5">
        <input type="checkbox" name="ids" value="1"><br>
        <input type="checkbox" name="ids" value="2"><br>
        <input type="checkbox" name="ids" value="3"><br>
        <input type="checkbox" name="ids" value="4"><br>
        <input type="checkbox" name="ids" value="5"><br>
        <input type="submit" value="reg">
    </form>
    
  • 细节分析 以List类举例

    @RequestMapping("param6")
    public String param6(ArrayList<Integer> ids) {
        for (Integer id : ids) {
            System.out.println("id = " + id);
        }
        return  "param1";
    }
    没有异常,但接收不到数据:SpringMVC会按照POJO的匹配方式,进行成员变量查找
    
    @RequestMapping("param6")
        public String param6(List<Integer> ids) {
            for (Integer id : ids) {
                System.out.println("id = " + id);
            }
            return  "param1";
        }
    抛出异常:SpringMVC无法提供具体的实现类、实例化形参
    

3.2.6 接收一组POJO类型对象的请求参数

  • 使用场景

按照POJO的匹配方式,对于非8种基本类型的方法形参,只有将List实例化作为成员变量封装在POJO类中,并将这个类作为形参才能正确接收数据。

  • 代码

    **// POJO类**
    public class UsersDTO {
        private List<User> users = new ArrayList<>();
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    }
    **//Controller类**
    @RequestMapping("param7")
        public String param7(UsersDTO usersDTO) {
            List<User> users = usersDTO.getUsers();
            for (User user : users) {
                System.out.println("user = " + user);
            }
            return  "param1";
        }
    
    **//JSP页**
    <form method="post" action="${pageContext.request.contextPath}/param/param7">
        UserName <input type="text" name="users[0].name"><br>
        Password <input type="text" name="users[0].password"><br>
        Age <input type="text" name="users[0].age"><br>
        <hr>
        UserName <input type="text" name="users[1].name"><br>
        Password <input type="text" name="users[1].password"><br>
        Age <input type="text" name="users[1].age"><br>
        <input type="submit" value="submit">
    </form>
    

3.3 接收Client请求参数的总结

3.4@RequestParam注解

作用:用于修饰控制器方法的形参

@RequestMapping("param2")
public String param2(@RequestParam String name,@RequestParam String password)

3.4.1 @RequestParam注解详解

  • 解决请求参数与方法形参名字不一致的问题

    Http请求:http://localhost:8989/param/param1/param1?n=jack&p=1234
    @RequestMapping("/param1")
    public String param1(@RequestParam("n") String name, @RequestParam("p") String password) {
        System.out.println("name = " + name);
        System.out.println("password = " + password);
        return "param1";
    }
    
    
  • 注意

    1. @RequestParam注解简写形式:不书写value书写的内容,@RequestParam默认会把对应形参名作为value属性的值

    2. 使用了@RequestParam注解的形参,客户端必须传递数据,不能省略,否则报错。

    3. POJO类型的形参,不能与@RequestParam注解联用。会报400错误

    4. 典型的应用场景

      htpp请求:http://localhost:8989/param/paramController/param1?id≤10
      @RequestMapping("/param1")
      public String param1(@RequestParam("id<") Integer id) {
      }
      **当提交的数据参数名不符合java的变量命名规则时,可以采用这种方式**
      
  • @RequestParam的required属性

    required = true时:@RequestParam修饰的控制器方法参数,客户端必须提交数据,否则报错,默认值

    required = false时:@RequestParam修饰的控制器方法参数,客户端可以不提交数据,不会报错

    解决了使用@RequestParam注解时,客户端必须传递数据的问题。

  • @RequestParam的defaultValue属性

    • 客户端没有提交数据的时候,给对应的形参提供默认值

      http://localhost:8989/param/paramController/param1?name=jack
      @RequestMapping("/param4")
          public String param4(@RequestParam String name, @RequestParam(defaultValue="9999") String password) {
              System.out.println("name = " + name);
              System.out.println("password = " + password);
              return "param1";
          }
      注意:如果使用了defaultValue,则required属性也默认设置成了false
      
    • 解决控制器方法形参,使用包装器的问题

      @RequestMapping("param6")
      public String param6(@RequestParam(defaultValue = "0") int age) {
          System.out.println("age = " + age);
          return "param1";
      }
      
    • defaultValue典型的使用场景

      默认值操作,一个典型的应用场景是:分页首页查询,不传页号的设计

      http://localhost:8989/param/page/findall
      http://localhost:8989/param/page/findall?pageNum=2
      @RequestMapping("findall")
      public String findall(@RequestParam(defaultValue = "0") int pageNum) {
         
      }
      

3.5 中文请求参数的乱码问题

3.5.1 回顾JavaWeb开发中 中文乱码的解决方案

  • GET请求乱码的解决方案

  • POST请求乱码的解决方案

3.5.2 SpringMVC解决中文字符集乱码

  1. GET请求的中文乱码

    UTF-8字符集,Tomcat8已经内部处理,无需我们处理。GBK字符集或者Tomcat8以前版本,需要配置server.xml

  2. POST请求的中文乱码,SpringMVC提供了过滤器解决

    org.springframework.web.filter.CharacterEncodingFilter

  • web.xml配置(通过alt+insert插入)

    <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>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

3.6 SpringMVC的类型转换器

3.6.1 SpringMVC中的内置类型转换器

  • 分析

  • 内置类型转换器的概念

    1. SpringMVC中提供了内置类型转换器,把客户端提交的字符串类型的请求参数,转换承控制器方法参数需要的数据类型

    2. SpringMVC并不是对于所有的类型,都提供了内置的类型转换器,他只是提供了常见类型的转换器

      比如:8种基本类型,常见的集合类型等

  • 原理分析

在SpringMVC启动时,会通过mvc:annotation-driven/把FormattingConversionServiceFactoryBean。引入到SpringMVC体系中。FormattingConversionServiceFactoryBean存储了SpringMVC种所有的内置类型转换器。后续client提交请求参数时,如果对于控制器方法形参不是字符串类型,那么FormattingConversionServiceFactoryBean就会调用对应的类型转换器,进行类型转换,最终完成控制器方法形参的赋值。

3.6.2 SpringMVC中自定义类型转换器

SpringMVC在接收客户端提交请求参数时,如果请求参数对应的控制器方法形参,是非常规数据类型,SpringMVC默认情况下无法进行类型转换。会抛出异常,程序员可以通过自定义类型转换器解决上述问题。例如:日期类型
  • 开发思路

  • 编码

    **// 实现Converter<S,T>接口**
    public class DateConverter implements Converter<String, Date> {
    
        @Override
        public Date convert(String source) {
            Date date = null;
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            try {
                date = sdf.parse(source);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }
    // **配置类型转换器,让Spring进行对象的创建**
    <bean id="dateConverter" class="com.baizhi.DateConverter"/>
    // **进行类型转换器注册,让SpringMVC能够识别日期类型转换的类型转换器-->**
    <bean id="serviceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="converters">
                <set>
                    <ref bean="dateConverter"/>
                </set>
            </property>
        </bean>
    // **最后一步**
    <mvc:annotation-driven conversion-service="serviceFactoryBean"/>
    
    // **上述第一步 第二步可以合二为一**
    <bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="converters">
                <set>
                    <bean id="converter" class="com.baizhi.DateConverter"/>
                </set>
            </property>
        </bean>
    

3.7 接收其他请求数据

3.7.1 动态参数收集

  • 单值动态参数收集(一个key对应一个请求数据)

    http://localhost:8989/param/param2/param1?name=suns
    http://localhost:8989/param/param2/param1?age=10
    @RequestMapping("/param1")
        public String param1(@RequestParam Map<String, String> params) {
            Set<String> keys = params.keySet();
            for (String key : keys) {
                System.out.println("key = " + key+",value = "+params.get(key));
            }
            return "param1";
        }
    **注意:如果需要接收动态参数,必须保证Map的形参前面加入@RequestParam注解,否则接收不到数据**
    
  • 多值动态参数收集(一个key对应多个请求数据)

    http://localhost:8989/param/param2/param1?id=2&id=3&id=4
    
    **第一种解决思路:通过数组形参接收请求参数**
    @RequestMapping("param5")
    public String param5(Integer[] ids) {
        for (Integer id : ids) {
            System.out.println("id = " + id);
        }
        return  "param1";
    }
    存在的问题:请求参数的key发生改变就接收不到请求数据
    
    第二种解决思路:通过MultiValueMap<K,V> 接收请求参数
    @RequestMapping("/param2")
        public String param2(@RequestParam MultiValueMap<String, String> params) {
            Set<String> keys = params.keySet();
            for (String key : keys) {
                List<String> values = params.get(key);
                System.out.println("key = " + key);
                for (String value : values) {
                    System.out.println("value = " + value);
                }
            }
            return "param1";
        }
    
  • 典型应用场景

3.7.2 接收cookie数据

  • 回顾Servlet中获取的方式

  • SpringMVC获取Cookie的方式

    测试Cookie 通过postman测试
    @RequestMapping("/param4")
    public String param4(@CookieValue("name") String value) {
        System.out.println("value = " + value);
        return "param1";
    }
    推荐使用@CookieValue获取cookie
    
    @RequestMapping("/param3")
    public String param3(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if ("name".equals(cookie.getName())) {
                System.out.println("cookie.getValue() = " + cookie.getValue());
            }
        }
        return "param1";
    }
    这种方式基于Servlet API存在耦合,不推荐使用。
    

3.7.3 接收请求头数据

  • 什么是请求头

  • 获取请求头的方式
    • Servlet中的获取方式

      核心代码
      String value = request.getHeader("key");
      
    • SpringMVC中的获取方式

      @RequestMapping("/param6")
      public String param6(@RequestHeader("Host") String host) {
          System.out.println("host = " + host);
          return "param1";
      }
      推荐使用@RequestHeader的方式获取请求头
      
      @RequestMapping("/param5")
      public String param5(HttpServletRequest request) {
          String host = request.getHeader("Host");
          System.out.println("host = " + host);
          return "param1";
      }
      这种方式存在与Servlet API的耦合问题,不建议后续使用
      

下一章:Spring MVC学习随笔-控制器(Controller)开发详解:调用业务对象、父子工厂拆分(applicationContext.xml、dispatcher.xml)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux脚本awk命令

目录 一. awk命令简介 1. awk版本 2. awk与vim的区别 3. awk与sed的区别 4. awk工作原理 5. awk格式 6. awk常用选项 二. awk基础用法 1. awk基础用法 2. BEGIN和END语句块 3. 指定分隔符 4. 首尾关键字 三. awk内置变量 1. FS变量 2. OFS变量 3. RS变量 4. NF…

【Unity动画】为一个动画片段添加事件Events

动画不管播放到那一帧&#xff0c;我们都可以在这里“埋伏”一个事件&#xff08;调用一个函数并且给函数传递一个参数&#xff0c;参数在外部设置&#xff0c;甚至传递一个物体&#xff09;&#xff01; 嗨&#xff0c;亲爱的Unity小伙伴们&#xff01;你是否曾想过为你的动画…

语言模型文本处理基石:Tokenizer简明概述

编者按&#xff1a;近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大型语言模型的问世&#xff0c;让 AI 写作、聊天等能力有了质的飞跃。如何更好地理解和利用这些生成式 AI&#xff0c;成为许多开发者和用户关心的问题。 今天&#xff0c;我们推出的这篇文章有助…

【小沐学Python】网络爬虫之lxml

文章目录 1、简介2、安装3、基本功能3.1 lxml.etree3.2 解析HTML网页3.3 读取并解析HTML文件3.4 提取所有a标签内的文本信息3.5 树迭代3.6 序列化3.7 元素以字典的形式携带属性3.8 元素包含文本 4、代码测试4.1 lxml解析网页4.2 使用xpath获取所有的文本4.3 使用xpath获取 clas…

TA-Lib学习研究笔记(二)——Overlap Studies上

TA-Lib学习研究笔记&#xff08;二&#xff09;——Overlap Studies 1. Overlap Studies 指标 [BBANDS, DEMA, EMA, HT_TRENDLINE, KAMA, MA, MAMA, MAVP, MIDPOINT, MIDPRICE, SAR, SAREXT, SMA, T3, TEMA, TRIMA, WMA]2.数据准备 get_data函数参数&#xff08;代码&#x…

mongoose学习记录

mongoose安装和连接数据库 npm i mongoose导入mongoose const mongoose require(mongoose) mongoose.set("strictQuery",true)连接数据库 mongoose.connect(mongodb:127.0.0.1:27017/test)设置回调 mongoose.connection.on(open,()>{console.log("连接成…

利用段落检索和生成模型进行开放域问答12.2

利用段落检索和生成模型进行开放域问答 摘要引言2 相关工作3 方法 摘要 事实证明&#xff0c;开放域问答的生成模型具有竞争力&#xff0c;无需借助外部知识。虽然很有希望&#xff0c;但这种方法需要使用具有数十亿个参数的模型&#xff0c;而这些模型的训练和查询成本很高。…

还在Wins 11怀念10的右键单击菜单?别担心,可通过注册表来实现

到目前为止&#xff0c;Windows 11最令人讨厌的新“功能”是右键单击任何内容时会出现截断的上下文菜单。以前版本的Windows显示了你的所有选项&#xff0c;包括可以打开文件的不同程序&#xff0c;而新菜单仅限于少数选项&#xff0c;不一定是你想要的。 例如&#xff0c;当我…

SHAP(五):使用 XGBoost 进行人口普查收入分类

SHAP&#xff08;五&#xff09;&#xff1a;使用 XGBoost 进行人口普查收入分类 本笔记本演示了如何使用 XGBoost 预测个人年收入超过 5 万美元的概率。 它使用标准 UCI 成人收入数据集。 要下载此笔记本的副本&#xff0c;请访问 github。 XGBoost 等梯度增强机方法对于具有…

C++ day48 打家劫舍

题目1&#xff1a;198 打家劫舍 题目链接&#xff1a;打家劫舍 对题目的理解 专业小偷偷盗房屋的钱财&#xff0c;每个房屋存放的金额用非负整数数组表示&#xff1b; 如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警&#xff1b; 不触动警报装置的情况…

吸积效应:为什么接口会越来越臃肿?我们从一个接口说起

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章&#xff0c;主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等&#xff0c;同时欢迎大家加我微信「java_front」一起交流学习 1 从一个接口说起 1.1 初始接口 假设现在有一个创建订单接口&#xff1a; pub…

C语言每日一题(44)删除排序链表中的重复元素 II

力扣 82 删除排序链表中的重复元素 II 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示…

mac安装解压缩rar后缀文件踩坑

mac默认能够解压缩zip后缀的文件&#xff0c;如果是rar后缀的自己需要下载相关的工具解压 下载地址&#xff1a; https://www.rarlab.com/download.htm mac我是因特尔芯片所以下载 x64 然后解压缩文件进入目录 rar中 将可执行文件 rar、unrar 移动到 /usr/local/bin目录下即…

【高效开发工具系列】jackson入门使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

ASP.NET Core MVC过滤器

1、过滤器分为授权过滤、资源访问过滤、操作方法&#xff08;Action&#xff09;过滤、结果过滤、异常过滤、终结点过滤。上一次咱们没有说异常过滤和终结点过滤&#xff0c;不过老周后面会说的。对这些过滤器&#xff0c;你有印象就行了。 2、所有过滤器接口都有同步版本和异…

可视化开源编辑器Swagger Editor本地部署并实现远程访问管理编辑文档

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 Swagger Editor本地接口文档公网远程访问1. 部署Swagge…

【Python百练——第3练】矩形类及操作

&#x1f490;作者&#xff1a;insist-- &#x1f490;个人主页&#xff1a;insist-- 的个人主页 理想主义的花&#xff0c;最终会盛开在浪漫主义的土壤里&#xff0c;我们的热情永远不会熄灭&#xff0c;在现实平凡中&#xff0c;我们终将上岸&#xff0c;阳光万里 ❤️欢迎点…

一缕青丝寄相思

10年8月16日七夕节男孩向女孩表白,女孩不知道那天是七夕,也没有读懂男孩的爱,女孩在9月22日中秋,向男孩打开了心门,男孩却没有懂女孩的心思.13年后的一封问候邮件,一束女孩的长发和回不去的青春 洒满阳光的午后 转眼间看到你的笑脸 微笑着你对我说 遇上你认识我真好 你说得好莫…

论文解读--Robust lane detection and tracking with Ransac and Kalman filter

使用随机采样一致性和卡尔曼滤波的鲁棒的车道线跟踪 摘要 在之前的一篇论文中&#xff0c;我们描述了一种使用霍夫变换和迭代匹配滤波器的简单的车道检测方法[1]。本文扩展了这项工作&#xff0c;通过结合逆透视映射来创建道路的鸟瞰视图&#xff0c;应用随机样本共识来帮助消…

力扣日记12.3-【二叉树篇】二叉树的所有路径

力扣日记&#xff1a;【二叉树篇】二叉树的所有路径 日期&#xff1a;2023.12.3 参考&#xff1a;代码随想录、力扣 257. 二叉树的所有路径 题目描述 难度&#xff1a;简单 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径…