数据绑定——springmvc入门介绍(二)

数据绑定概念及绑定过程

在springmvc入门介绍(一)中介绍了几种服务器端的数据如何传递给前端去展示。本节主要介绍如何将前端的数据传送到服务端,即view的数据如何传送到controller中对应的处理方法中。springmvc主要将要传送的数据通过与处理方法的形参进行绑定,完成数据传递的过程。绑定过程如下图所示:
在这里插入图片描述
SpringMVC框架提供了一个数据绑定组件(DataBinder),前端请求将请求数据包裹在request中发送给DataBinder组件,通过RequestMaping映射的方法也将自己的入参交给绑定组件,DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中;再调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验;校验完成后生成数据绑定结果BindingResult对象,springmvc将此对象中内容赋给处理方法相应的参数。
根据客户端请求参数类型和个数不同,我们将数据绑定分为默认参数类型、简单参数类型和复杂参数类型,以下前端使用jsp、处理方法的返回值为string为例,详细介绍数据绑定过程。示例项目工程目录如下:
在这里插入图片描述
为了简单期间,不访问数据库使用静态数据作为示例,controller准备工作代码如下:

@Controller
@RequestMapping("/product")
public class product {
  private static List<ProductVO> products = new ArrayList<>();

  static {
      ProductVO product = new ProductVO();
      product.setId(1);
      product.setProduceName("联想笔记本");
      product.setProduceDesc("thinkpad T 系列");
      products.add(product);

      ProductVO product2 = new ProductVO();
      product2.setId(2);
      product2.setProduceName("Dell笔记本");
      product2.setProduceDesc("移动工作站  系列");
      products.add(product2);

      ProductVO product3 = new ProductVO();
      product3.setId(3);
      product3.setProduceName("HP笔记本");
      product3.setProduceDesc("ProBook  系列");
      products.add(product3);
  }

  @RequestMapping("/list")
  public String getList(Model model){
      model.addAttribute("datas",products);

      return "WEB-INF/view/ListPage";
  }
}

在浏览器URL栏输入:http://localhost:8080/webapp/product/list,展示列表页面,我们以商品的增加、删除、修改为例介绍springmvc数据绑定
在这里插入图片描述

默认参数类型

后台方法的形参中直接使用Spring MVC提供的默认参数类型进行数据绑定,常用的默认参数类型包括:

  • HttpServletRequest:通过request对象获取请求信息;
  • HttpServletResponse:通过response处理响应信息;
  • HttpSession:通过session对象得到session中存放的对象;
  • Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域

查询商品名称为"联想笔记本"的数据,使用HttpServletRequest携带参数:
jsp查询部分代码如下:

   <form action="${pageContext.request.contextPath}/product/query1" method="post">
       查询条件
       <table>
           <tr>
               <td>
                   <label>商品名称: </label><input type="text" name="productName" value=""/>
                   <input type="submit" value="查询"/>
               </td>
           </tr>
       </table>
   </form>

controller中方法如下,使用HttpServletRequest传入参数,使用HttpServletResponse返回。

  //默认支持类型,HttpServletRequest、HttpServletResponse、HttpSession、Model等
    @RequestMapping(value = "/query1", method={RequestMethod.POST,RequestMethod.GET})
    public void queryProduct1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String productName = request.getParameter("productName");

        System.out.println(productName);
        Iterator<ProductVO> it = products.iterator();
        while(it.hasNext()){
            if(!productName.equals(it.next().getProduceName())){
                it.remove();
            }
        }

        response.sendRedirect(request.getContextPath()+"/product/list");

        return ;
    }

通过前端form表单绑定request域值传递参数。

简单参数

简单参数包括基本数据类型如:int、boolean、double等,包装类型如:Integer、Boolean、Double、String、pojo类型等。以下分别通过查询传送商品名称(String)和商品的添加为例进行验证。
验证String接收参数,jsp代码如上不变,controller代码片段如下:

  //java基本类型和包装类型绑定,int、double、Integer、Double、String等
  @RequestMapping(value = "/query2", method={RequestMethod.POST,RequestMethod.GET})
  public String queryProduct2(Model model, String productName){
      System.out.println(productName);
      Iterator<ProductVO> it = products.iterator();
      while(it.hasNext()){
          if(!productName.equals(it.next().getProduceName())){
              it.remove();
          }
      }

      model.addAttribute("datas",products);
      return "WEB-INF/view/ListPage";
  }

这里String携带参数productName,使用String返回逻辑视图名,Model携带参数返回。注意:这里形参名必须和form表单中绑定的input name完全一致,否则报错
针对上述问题,SpringMVC提供了一个注解符@RequestParam解决此问题。代码如下:

//基本参数类型绑定,当名称不一致时操作
    @RequestMapping(value = "/query3", method={RequestMethod.POST,RequestMethod.GET})
    public String queryProduct3(Model model, @RequestParam("productName") String name){
        System.out.println(name);
        Iterator<ProductVO> it = products.iterator();
        while(it.hasNext()){
            if(!it.next().getProduceName().contains(name)){
                it.remove();
            }
        }

        model.addAttribute("datas",products);
        return "WEB-INF/view/ListPage";
    }

通过注解符@RequestParam完成前端绑定的名称和后台处理方法使用的参数变量解耦。假设查询条件很多,那么一个条件一个形参,这样是能够解决问题,但是不是很方便,那么我们可以pojo类型解决问题,在这里我们使用ProductVO进行验证。jsp代码片段如下:

<form action="${pageContext.request.contextPath}/product/query4" method="post">
    查询条件
    <table>
        <tr>
            <td>
                <label>商品ID: </label><input type="text" name="id" value=""/>
                <label>商品名称: </label><input type="text" name="produceName" value=""/>
                <label>商品描述: </label><input type="text" name="produceDesc" value=""/>
                <input type="submit" value="查询"/>
            </td>
        </tr>
    </table>
</form>

接收代码如下,这里仅为验证,将接收过来的数据输出到控制台上

//基本参数类型绑定,当名称不一致时操作
    @RequestMapping(value = "/query4", method={RequestMethod.POST,RequestMethod.GET})
    public String queryProduct4(ProductVO productVO){
        System.out.println(productVO.toString());

        return "WEB-INF/view/Success";
 }

运行系统,输入参数名称:
在这里插入图片描述
查看控制台输出,结果如下:
在这里插入图片描述
表明已经使用ProductVO接收到了对象。再考虑一种复杂情况,如:商品是一个pojo对象,生产厂家也是一个pojo对象,商品类中持有了对象的引用,此时如何处理,pojo代码如下

public class FactoryVO {
    private Integer id;
    private String FactoryName;
    private String FactoryAdress;
    //省略get、set
    @Override
    public String toString() {
        return "FactoryVO{" +
                "id=" + id +
                ", FactoryName='" + FactoryName + '\'' +
                ", FactoryAdress='" + FactoryAdress + '\'' +
                '}';
    }
}

public class ProductVO2 {
    private int id;
    private String produceName;
    private String ProduceDesc;
    private FactoryVO factoryVO;
    //省略get、set
    @Override
    public String toString() {
        return "ProductVO{" +
                "id=" + id +
                ", produceName='" + produceName + '\'' +
                ", ProduceDesc='" + ProduceDesc + '\'' +
                ", 厂家信息="+ factoryVO.toString()+'\'' +
                '}';
    }
}

在这里插入图片描述
控制台输出结果:
在这里插入图片描述
使用pojo完成传参时,需要表单上绑定name与pojo的属性名一致,如果不匹配的属性制null。

自定义绑定

springmvc提供的数据类型转换基本能满足我们的开发,但也有特殊数据类型无法直接进行数据绑定,必须先经过数据转换,例如日期数据,pringmvc也允许我们开发一些自定义的类型转换器,完成特殊类型的转换,spring提供了两个接口(Converter和Formatter)在我们开发自定义类型转换器时使用,如:我们开发一个日期类型转换器,就需要完成以下代码。

public class DataConvert implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        System.out.println("调用自定义日期转换器");
        if(s!=null && !"".equals(s)){
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            try {
                return  dateFormat.parse(s);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

配置写好的类型转换器,打开springmvc.xml文件,配置代码如下:

    <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
    <!--将自定义的转换器交给spring进行管理-->
    <bean id="dataConvert" class="com.bjwl.common.DataConvert"></bean>

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
         <!--注入自定义转换器-->
        <property name="converters" ref="dataConvert" />
    </bean>

验证代码如下:

    @RequestMapping("/edit1")
    public String edit1(Date createTime){
        System.out.println(createTime);
        return "WEB-INF/view/Success";
    }

打开浏览器,在地址栏输入:http://localhost:8080/webapp/product/edit1?createTime=2019-01-01 10:10。查看后台控制台输出如下:
在这里插入图片描述
将前端的String转换为参数为日期的值。注意:前端输入字符串格式应该与转换器中的格式完全一致,上例中,字符串格式为"yyyy-MM-dd HH:mm";带时分的,如果输入不带时分的字符串,如:2019-01-01,则会报错

复杂参数绑定

以上介绍了简单参数类型的绑定,如果要绑定数组、集合这些实际开发中也是十分常见的复杂参数又该如何做呢?以下就简单演示一下数组绑定和集合绑定。
数组绑定:假如要根据商品的id批量删除商品,就需要使用到数组。修改jsp页面,页面代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="C" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>列表页面</title>
</head>
<body>
<form name="frm" action="${pageContext.request.contextPath}/product/deleteIds" method="post">
    <input type="submit" value="批量删除" >
    <table border="1">
    <tr>
        <td>序号</td>
        <td>商品名称</td>
        <td>商品描述</td>
        <td>删除</td>
    </tr>
    <C:forEach items="${datas}" var="item">
        <tr>
            <td><span>${item.id}</span></td>
            <td><span>${item.produceName}</span></td>
            <td><span>${item.produceDesc}</span></td>
            <td><a href="${pageContext.request.contextPath}/product/modfy?id=${item.id}">修改</a></td>
            <td><input type="checkbox" name="ids" value="${item.id}"/></td>
        </tr>
    </C:forEach>
    </table>
   </form>
</body>
</html>

在这里插入图片描述

注意:这里checkbox name为ids。后端接收的controller方法为:

    @RequestMapping("/deleteIds")
    public String deleteData(Integer[] ids){
        for (int i = 0; i <ids.length ; i++) {
            System.out.println(ids[i]);
        }

        return "WEB-INF/view/Success";
    }

点击批量删除按钮,控制台显示结果如下:
在这里插入图片描述
集合绑定:批量修改产品时,需要一次提交多个pojo对象,就要使用到集合绑定。jsp代码修改为:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="C" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>列表页面</title>
</head>
<body>
<form name="frm" action="${pageContext.request.contextPath}/product/saveDatas" method="post">
    <input type="submit" value="保存修改">
    <table border="1">
        <tr>
            <td>序号</td>
            <td>商品名称</td>
            <td>商品描述</td>
            <td>删除</td>
        </tr>
        <C:forEach items="${datas}" var="item" varStatus="s">
            <tr>
                <td><input type="input" name="products[${s.index}].id" value="${item.id}"/></td>
                <td><input type="input" name="products[${s.index}].produceName" value="${item.produceName}"/></td>
                <td><input type="input" name="products[${s.index}].produceDesc" value="${item.produceDesc}"/></td>
                <td><a href="${pageContext.request.contextPath}/product/edit?id=${item.id}">修改</a></td>
                <td><input type="checkbox" name="ids" value="${item.id}"/></td>
            </tr>
        </C:forEach>
    </table>
</form>
</body>
</html>

集合绑定时,需要创建一个新的vo对象,用于存放List,代码如下:

public class ProductList {
    public List<ProductVO> getProducts() {
        return products;
    }

    public void setProducts(List<ProductVO> products) {
        this.products = products;
    }

    private List<ProductVO> products;
}

使用这个对象来接收参数,controller方法代码为:

    @RequestMapping("/saveDatas")
    public String saveDatas(ProductList products){
      for (ProductVO item :products.getProducts()){
          System.out.println(item.toString());
      }
        return "WEB-INF/view/Success";
    }

运行后,控制台显示以下信息:
在这里插入图片描述
这里需要注意的使用集合时,必须使用一个包装类,将集合包装类的内部,如:ProductList 就持有 List products集合对象,此时jsp页面要求使用包装类的属性products去接收参数,页面绑定名称与属性名不匹配,返回null

小结

参数绑定是将前端数据提交给后端控制器重要部分,虽然前后端分离项目中使用异步通讯,来回传递的是json,页面数据通过双向绑定来实现,但这些是基础,务必掌握使用方式。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值