User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Spring   ›   SpringMVC   ›   正文
SpringMVC

SpringMVC笔记8—参数绑定

2020-04-05 02:05:42
741  0 0
参考目录 隐藏
1) 1.默认支持的参数类型
2) 2.简单数据类型
3) 3.实体类
4) 4.自定义参数绑定
5) 5.集合类的参数

阅读完需:约 12 分钟

1.默认支持的参数类型

默认支持的参数类型,就是可以直接写在 @RequestMapping 所注解的方法中的参数类型,一共有四类:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • Model/ModelMap

这几个例子可以参考上一小节。

在请求的方法中,默认的参数就是这几个,如果在方法中,刚好需要这几个参数,那么就可以把这几个参数加入到方法中。

2.简单数据类型

Integer、Boolean、Double 等等简单数据类型也都是支持的。例如添加一本书:

首先,在 /jsp/ 目录下创建 add book.jsp 作为图书添加页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/doAdd" method="post">
    <table>
        <tr>
            <td>书名:</td>
            <td><input type="text" name="name"></td>
        </tr>
        <tr>
            <td>作者:</td>
            <td><input type="text" name="author"></td>
        </tr>
        <tr>
            <td>价格:</td>
            <td><input type="text" name="price"></td>
        </tr>
        <tr>
            <td>是否上架:</td>
            <td>
                <input type="radio" value="true" name="ispublic">是
                <input type="radio" value="false" name="ispublic">否
            </td>
        </tr>
        <tr>
           <td colspan="2">
               <input type="submit" value="添加">
           </td>
        </tr>
    </table>
</form>
</body>
</html>

创建控制器,控制器提供两个功能,一个是访问 jsp 页面,另一个是提供添加接口:

@Controller
public class BookController {
    @RequestMapping("/book")
    public String addBook() {
        return "addbook";
    }

    @RequestMapping(value = "/doAdd",method = RequestMethod.POST)
    @ResponseBody
    public void doAdd(String name,String author,Double price,Boolean ispublic) {
        System.out.println(name);
        System.out.println(author);
        System.out.println(price);
        System.out.println(ispublic);
    }
}

注意,由于 doAdd 方法确实不想返回任何值,所以需要给该方法添加 @ResponseBody 注解,表示这个方法到此为止,不用再去查找相关视图了。另外, 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>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

最后,浏览器中输入 http://localhost:8080/book ,就可以执行添加操作,服务端会打印出来相应的日志。

在上面的绑定中,有一个要求,表单中字段的 name 属性要和接口中的变量名一一对应,才能映射成功,否则服务端接收不到前端传来的数据。有一些特殊情况,我们的服务端的接口变量名可能和前端不一致,这个时候我们可以通过 @RequestParam 注解来解决。

  • @RequestParam

这个注解的的功能主要有三方面:

  1. 给变量取别名
  2. 设置变量是否必填
  3. 给变量设置默认值

如下:

@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(@RequestParam("name") String bookname, String author, Double price, Boolean ispublic) {
    System.out.println(bookname);
    System.out.println(author);
    System.out.println(price);
    System.out.println(ispublic);
}

注解中的 “name” 表示给 bookname 这个变量取的别名,也就是说,bookname 将接收前端传来的 name 这个变量的值。在这个注解中,还可以添加 required 属性和 defaultValue 属性,如下:

@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(@RequestParam(value = "name",required = true,defaultValue = "三国演义") String bookname, String author, Double price, Boolean ispublic) {
    System.out.println(bookname);
    System.out.println(author);
    System.out.println(price);
    System.out.println(ispublic);
}

required 属性默认为 true,即只要添加了 @RequestParam 注解,这个参数默认就是必填的,如果不填,请求无法提交,会报 400 错误,如果这个参数不是必填项,可以手动把 required 属性设置为 false。但是,如果同时设置了 defaultValue,这个时候,前端不传该参数到后端,即使 required 属性为 true,它也不会报错。

3.实体类

参数除了是简单数据类型之外,也可以是实体类。实际上,在开发中,大部分情况下,都是实体类。

还是上面的例子,我们改用一个 Book 对象来接收前端传来的数据:

public class Book {
    private String name;
    private String author;
    private Double price;
    private Boolean ispublic;

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", ispublic=" + ispublic +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Boolean getIspublic() {
        return ispublic;
    }

    public void setIspublic(Boolean ispublic) {
        this.ispublic = ispublic;
    }
}

服务端接收数据方式如下:

@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(Book book) {
    System.out.println(book);
}

前端页面传值的时候和上面的一样,只需要写属性名就可以了,不需要写 book 对象名。

当然,对象中可能还有对象。例如如下对象:

public class Book {
    private String name;
    private Double price;
    private Boolean ispublic;
    private Author author;

    public void setAuthor(Author author) {
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                ", ispublic=" + ispublic +
                ", author=" + author +
                '}';
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Boolean getIspublic() {
        return ispublic;
    }

    public void setIspublic(Boolean ispublic) {
        this.ispublic = ispublic;
    }
}
public class Author {
    private String name;
    private Integer age;

    @Override
    public String toString() {
        return "Author{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Book 对象中,有一个 Author 属性,如何给 Author 属性传值呢?前端写法如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/doAdd" method="post">
    <table>
        <tr>
            <td>书名:</td>
            <td><input type="text" name="name"></td>
        </tr>
        <tr>
            <td>作者姓名:</td>
            <td><input type="text" name="author.name"></td>
        </tr>
        <tr>
            <td>作者年龄:</td>
            <td><input type="text" name="author.age"></td>
        </tr>
        <tr>
            <td>价格:</td>
            <td><input type="text" name="price"></td>
        </tr>
        <tr>
            <td>是否上架:</td>
            <td>
                <input type="radio" value="true" name="ispublic">是
                <input type="radio" value="false" name="ispublic">否
            </td>
        </tr>
        <tr>
           <td colspan="2">
               <input type="submit" value="添加">
           </td>
        </tr>
    </table>
</form>
</body>
</html>

这样在后端直接用 Book 对象就可以接收到所有数据了。

4.自定义参数绑定

前面的转换,都是系统自动转换的,这种转换仅限于基本数据类型。特殊的数据类型,系统无法自动转换,例如日期。例如前端传一个日期到后端,后端不是用字符串接收,而是使用一个 Date 对象接收,这个时候就会出现参数类型转换失败。这个时候,需要我们手动定义参数类型转换器,将日期字符串手动转为一个 Date 对象。

@Component
public class DateConverter implements Converter<String, Date> {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    public Date convert(String source) {
        try {
            return sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

在自定义的参数类型转换器中,将一个 String 转为 Date 对象,同时,将这个转换器注册为一个 Bean。

接下来,在 SpringMVC 的配置文件中,配置该 Bean,使之生效。

<mvc:annotation-driven conversion-service="conversionService"/>
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="conversionService">
    <property name="converters">
        <set>
            <ref bean="dateConverter"/>
        </set>
    </property>
</bean>

配置完成后,在服务端就可以接收前端传来的日期参数了。

5.集合类的参数

  • String 数组

String 数组可以直接用数组去接收,前端传递的时候,数组的传递其实就多相同的 key,这种一般用在 checkbox 中较多。

例如前端增加兴趣爱好一项:

<form action="/doAdd" method="post">
    <table>
        <tr>
            <td>书名:</td>
            <td><input type="text" name="name"></td>
        </tr>
        <tr>
            <td>作者姓名:</td>
            <td><input type="text" name="author.name"></td>
        </tr>
        <tr>
            <td>作者年龄:</td>
            <td><input type="text" name="author.age"></td>
        </tr>
        <tr>
            <td>出生日期:</td>
            <td><input type="date" name="author.birthday"></td>
        </tr>
        <tr>
            <td>兴趣爱好:</td>
            <td>
                <input type="checkbox" name="favorites" value="足球">足球
                <input type="checkbox" name="favorites" value="篮球">篮球
                <input type="checkbox" name="favorites" value="乒乓球">乒乓球
            </td>
        </tr>
        <tr>
            <td>价格:</td>
            <td><input type="text" name="price"></td>
        </tr>
        <tr>
            <td>是否上架:</td>
            <td>
                <input type="radio" value="true" name="ispublic">是
                <input type="radio" value="false" name="ispublic">否
            </td>
        </tr>
        <tr>
           <td colspan="2">
               <input type="submit" value="添加">
           </td>
        </tr>
    </table>
</form>

在服务端用一个数组去接收 favorites 对象:

@RequestMapping(value = "/doAdd",method = RequestMethod.POST)
@ResponseBody
public void doAdd(Book book,String[] favorites) {
    System.out.println(Arrays.toString(favorites));
    System.out.println(book);
}

注意,前端传来的数组对象,服务端不可以使用 List 集合去接收。

  • List 集合

如果需要使用 List 集合接收前端传来的数据,List 集合本身需要放在一个封装对象中,这个时候,List 中,可以是基本数据类型,也可以是对象。例如有一个班级类,班级里边有学生,学生有多个:

public class MyClass {
    private Integer id;
    private List<Student> students;

    @Override
    public String toString() {
        return "MyClass{" +
                "id=" + id +
                ", students=" + students +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}
public class Student {
    private Integer id;
    private String name;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + 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;
    }
}

添加班级的时候,可以传递多个 Student,前端页面写法如下:

<form action="/addclass" method="post">
    <table>
        <tr>
            <td>班级编号:</td>
            <td><input type="text" name="id"></td>
        </tr>
        <tr>
            <td>学生编号:</td>
            <td><input type="text" name="students[0].id"></td>
        </tr>
        <tr>
            <td>学生姓名:</td>
            <td><input type="text" name="students[0].name"></td>
        </tr>
        <tr>
            <td>学生编号:</td>
            <td><input type="text" name="students[1].id"></td>
        </tr>
        <tr>
            <td>学生姓名:</td>
            <td><input type="text" name="students[1].name"></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="提交">
            </td>
        </tr>
    </table>
</form>

服务端直接接收数据即可:

@RequestMapping("/addclass")
@ResponseBody
public void addClass(MyClass myClass) {
    System.out.println(myClass);
}
  • Map

相对于实体类而言,Map 是一种比较灵活的方案,但是,Map 可维护性比较差,因此一般不推荐使用。

例如给上面的班级类添加其他属性信息:

public class MyClass {
    private Integer id;
    private List<Student> students;
    private Map<String, Object> info;

    @Override
    public String toString() {
        return "MyClass{" +
                "id=" + id +
                ", students=" + students +
                ", info=" + info +
                '}';
    }

    public Map<String, Object> getInfo() {
        return info;
    }

    public void setInfo(Map<String, Object> info) {
        this.info = info;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

在前端,通过如下方式给 info 这个 Map 赋值。

<form action="/addclass" method="post">
    <table>
        <tr>
            <td>班级编号:</td>
            <td><input type="text" name="id"></td>
        </tr>
        <tr>
            <td>班级名称:</td>
            <td><input type="text" name="info['name']"></td>
        </tr>
        <tr>
            <td>班级位置:</td>
            <td><input type="text" name="info['pos']"></td>
        </tr>
        <tr>
            <td>学生编号:</td>
            <td><input type="text" name="students[0].id"></td>
        </tr>
        <tr>
            <td>学生姓名:</td>
            <td><input type="text" name="students[0].name"></td>
        </tr>
        <tr>
            <td>学生编号:</td>
            <td><input type="text" name="students[1].id"></td>
        </tr>
        <tr>
            <td>学生姓名:</td>
            <td><input type="text" name="students[1].name"></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="提交">
            </td>
        </tr>
    </table>
</form>

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593880浏览

随机文章
Caffeine—缓存学习
2年前
Java—并发编程—AQS(二)
4年前
SpringSecurity—防御 CSRF 攻击
4年前
PostgreSQL—Explain查询计划
10个月前
Java—自定义注解
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593880 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付