Springmvc数据绑定

       在struts2中,是通过在Action中定义一个成员变量来接收前台传进来的参数,而在springmvc中,接收页面提交的数据是通过方法形参来接收的。从客户端请求的key/value数据,经过参数绑定,将key/value数据绑定到controller方法的形参上,然后就可以在controller中使用该参数。springmvc提供了很多转换器Converter来将页面参数绑定到controller方法的形参。

默认类型

  在controller的方法的形参中直接定义上面这些类型的参数,springmvc会自动绑定。

  HttpServletRequest对象
  HttpServletResponse对象
  HttpSession对象
  Model/ModelMap对象:ModelMap是Model接口的实现类,我们可通过Model或ModelMap向页面传递数据
@RequestMapping("/itemEdit")
public String editItem(HttpServletRequest request, 
        HttpServletResponse response, HttpSession session, Model model) {
    // 从request中取出参数
    String strId = request.getParameter("id");
    int id = new Integer(strId);
    // 调用服务
    Items items = itemService.getItemById(id);

    // 使用模型设置返回结果,model是框架给我们传递过来的对象,所以这个对象也不需要我们返回
    model.addAttribute("item", items); // 类似于:modelAndView.addObject("item", items);
    // 返回逻辑视图
    return "editItem";
}

简单类型绑定

  前台通过url将参数传递进来

<a href="${pageContext.request.contextPath}/editItems.action?id=${item.id}">修改</a>
@RequestMapping("/editItems")
public String editItems(Model model, Integer id) throws Exception {
    //根据id查询对应的Items
    ItemsCustom itemsCustom = itemsService.findItemsById(id);

    model.addAttribute("itemsCustom", itemsCustom);

    //通过形参中的model将model数据传到页面
    //相当于modelAndView.addObject方法
    return "/WEB-INF/jsp/items/editItems.jsp";
}

  代码中可以看出model可以直接作为参数,springmvc默认会绑定它,然后使用model将查询到的数据放到request域中,这样就可以在前台页面取出该数据。简单类型的绑定中,方法形参中的参数名要和前台传进来的名一样才能完成参数的绑定,或者使用@RequestParam参数

@RequestMapping("/editItems")
public String editItems(Model model, @RequestParam(value="id",required=true)Integer item_id) throws Exception {

普通的POJO绑定

  对于基本类型,要求页面中input标签的name属性值和controller的pojo形参中的属性名称一致,即可将页面中数据绑定到pojo。即前台页面传进来的name要和封装的pojo属性名一模一样,然后就可以将该pojo作为形参放到controller的方法中。

<form method="post" action="${pageContext.request.contextPath}/user/showUser">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="userName"  value="${user.userName}"/></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" value="${user.password}"/></td>
        </tr>
        <tr>
            <td>姓名:</td>
            <td><input type="text" name="realName" value="${user.realName}"/></td>
        </tr>
        <tr>
            <td>生日:</td>
            <td><input type="text" name="birthday" value="${user.birthday}"/></td>
        </tr>
        <tr>
            <td>工资:</td>
            <td><input type="text" name="salary" value="${user.salary}"/></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" name="提交"/></td>
        </tr>
    </table>
</form>

  注意String类型转为Date类型出错解决:

一、使用注解方式

      import org.springframework.format.annotation.DateTimeFormat;

    @Past
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

二、自定义类型转换器

  实现Converter接口

package com.smart.converter;

import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.datetime.DateFormatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDataConverter implements Converter<String,Date> {

    private static Logger logger= Logger.getLogger(CustomDataConverter.class);
    @Override
    public Date convert(String source) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            return dateFormat.parse(source);
        } catch (ParseException e) {
            logger.error("parse string to date is wrong!");
        }
        return null;
    }
}

  在webApplicationContext.xml配置文件中进行配置

  <mvc:annotation-driven conversion-service="conversionService"/>

     <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
          <property name="converters">
               <list>
                    <bean class="com.smart.converter.CustomDataConverter"/>
               </list>
          </property>
     </bean>

  乱码解决

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

  包装类pojo参数绑定

第一种:在控制器中传入HttpServletRequest的request对象,从中request中取

第二种:包装类的pojo属性直接接收值

       例如:User中含有Address对象,Address包含city、street、doorNumber

     <tr>
            <td>城市</td>
            <td><input type="text" name="address.city" value="${user.address.city}"/></td>
        </tr>
        <tr>
            <td>街道</td>
            <td><input type="text" name="address.street" value="${user.address.street}"/></td>
        </tr>
        <tr>
            <td>门牌号</td>
            <td><input type="text" name="address.doorNumber" value="${user.address.doorNumber}"/></td>
        </tr>

  数组绑定

  checkbox标签的name属性与pojo的数组标签保持一致

     <tr>
            <td>&nbsp;</td>
            <td>
                   <input type="checkbox" name="interests" value="0">篮球</checkbox> &nbsp;
                   <input type="checkbox" name="interests" value="1">足球</checkbox> &nbsp;
                   <input type="checkbox" name="interests" value="2">游泳</checkbox> &nbsp;
            </td>
        </tr>

  User的兴趣属性

   private int[] interest

      在进行跳转显示

 爱好 <c:forEach items="${user.interests}" var="interest">
          <c:if test="${interest == 0}">篮球</c:if>
          <c:if test="${interest == 1 }">足球</c:if>
          <c:if test="${interest == 2 }">游泳</c:if>
     </c:forEach>

     List集合进行绑定

  通常在需要批量提交数据时,将提交的数据绑定到list<pojo>中,比如:成绩录入(录入多门课成绩,批量提交)

    UserQueryVo拓展类,含有user列表

package com.smart.domain;

import java.util.List;

public class UserQueryVo {
    private List<User> users;

    public UserQueryVo(){

    }
    public UserQueryVo(List<User> userList) {
        this.users = userList;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

  控制器进行模拟

  RequestMapping(value="/editUsers")
    public ModelAndView queryAllUser(HttpServletRequest request, UserQueryVo userQueryVo){
        List<User> users = new ArrayList<>();
        users.add(new User("Lucy0001","111","明明"));
        users.add(new User("Jim0002","222","小强"));
        users.add(new User("Tom0003","333","自强"));

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("users",users);
        modelAndView.setViewName("user/editUsers");
        return modelAndView;
    }

  前台jsp页面中是如何传入参数的呢?

<form method="post" action="${pageContext.request.contextPath}/user/editResult">
    <table>
    <c:forEach items="${users}" var="user" varStatus="status">
        <tr>
            <td> <input name="users[${status.index}].userName" value="${user.userName}"/> </td>   <!--users与包装类中的list属性名相同-->
            <td><input name="users[${status.index}].password" value="${user.password}"/>  </td>
            <td><input name="users[${status.index}].realName" value="${user.realName}"/>  </td>
        </tr>
    </c:forEach>
    </table>
       <input type="submit" name="提交"/>
   </form>

  Map绑定

      Map的参数绑定传来的是Map中的key,然后value会自动绑定到Map中的那个对象的属性中

  public class UserQueryVo {
      private List<User> users;
      private Map<String,User> data;

  jsp配置页面

      <tr>
            <td>用户名:<input type="text" name="data['userName']"/> </td>
            <td>密  码:<input type="password" name="data['password']"></td>
        </tr>

  

注意事项:

     form表单无法提交input输入框属性设置为 disabled 的内容

<input type="text" disabled="disabled" name="metadataName"   maxlength="50" placeholder="这里输入模型英文名称" title="模型英文名称" "/>

      具有 disabled="disabled" 的属性,提交到 Controller后,metadataName 的值为null

  解决办法:改为 readonly="readonly"

  readonly:针对input(text / password)和textarea有效,在设置为true的情况下,用户可以获得焦点,但是不能编辑,在提交表单时,输入项会作为form的内容提交。

  disabled:针对所有表单元素(select,button,input,textarea),在设置为disabled为true的情况下,表单输入项不能获得焦点,在提交表单时,表单输入项不会被提交。

 

 form提交表单controller层无法自动绑定参数

     原因一:

     form表单文件上传,设置enctype=”multipart/form-data”时会导致参数绑定失败。

     需要在mvc配置文件中进行如下配置

<!-- 文件上传 -->
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置上传文件的最大尺寸为5MB -->
    <property name="maxUploadSize">
        <value>5242880</value>
    </property>
</bean>

   

     注意的是,如果Controller方法参数中定义的是基本数据类型,但是从页 面提交过来的数据为null或者”"的话,会出现数据转换的异常。就是必须保证表单传递过来的数据不能为null或”",在开发过程中,对可能为 空的数据,最好将参数数据类型定义成包装类型,具体参见下面的例子。

    Controller代码:

@RequestMapping("saysth.do")
public void test(Integer count) {
}

     表单代码:

<form action="xxx.do" method="post">
<input name="count" value="10" type="text"/>
......
</form>

     和基本数据类型基本一样,不同之处在于,表单传递过来的数据可以为null或”",以上面代码为例,如果表单中num为”"或者表单中无num这个input,那么,Controller方法参数中的num值则为null。

    form-data和x-www-form-urlencoded的区别:

      1、 x-www-form-urlencoded

       application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23

       2、form-data:

       http请求中的multipart/form-data,会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型; 
  由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,采用了键值对的方式,所以可以上传多个文件

  Response.AppendHeader("Content-Disposition","attachment;filename=FileName.txt");这样浏览器会提示保存还是打开,即使选择打开,也会使用相关联的程序比如记事本打开,

  Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名,

参考:

       https://www.cnblogs.com/ysocean/p/7425861.html(推荐)

      https://blog.csdn.net/yerenyuan_pku/article/details/72511611(推荐)

      https://www.cnblogs.com/linjiaxin/p/5554612.html

  https://blog.csdn.net/eson_15/article/details/51718633

posted on 2018-09-08 21:42  溪水静幽  阅读(170)  评论(0)    收藏  举报