springmvc高级知识(一)&注解开发

本文主要介绍注解开发的介绍包装类型的参数绑定

.包装类型的参数绑定

需求

商品查询controller方法中实现商品查询条件传入。

实现方法

第一种方法:在形参中添加HttpServletRequest request参数,通过request接收查询条件参数。
第二种方法:在形参中让包装类型的pojo接收查询条件参数。
分析:

页面传参数的特点:复杂,多样性。条件包括:用户账号、商品编号、订单信息。。。

如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。建议使用包装类型的pojo,pojo中属性是pojo。

页面参数和controller方法形参定义

页面参数:
商品名称:<input name="itemsCustom.name" />

注意:itemsCustom和包装pojo中的属性名一致即可。

controller方法形参:
public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception

包装类ItemsQueryVo中部分属性:
public class ItemsQueryVo {

    //商品信息
    private Items items;

    //为了系统 可扩展性,对原始生成的po进行扩展
    private ItemsCustom itemsCustom;
可见,ItemsQueryVo中属性itemsCustom和页面参数中一致

3.集合类型绑定

数组绑定

需求

商品批量删除,用户在页面选择多个商品,批量删除。

表现层实现

关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。

controller方法定义:
// 批量删除 商品信息
@RequestMapping("/deleteItems")
public String deleteItems(Integer[] items_id) throws Exception
页面定义:
<c:forEach items="${itemsList }" var="item">
<tr>
    <td><input type="checkbox" name="items_id" value="${item.id}"/></td>
    <td>${item.name }</td>
    <td>${item.price }</td>
    <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
    <td>${item.detail }</td>

    <td><a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td>

</tr>
</c:forEach>

list绑定

需求

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

本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。

表现层实现

controller方法定义:
1、进入批量商品修改页面(页面样式参考商品列表实现)
2、批量修改商品提交
使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list属性

public class ItemsQueryVo {

    //商品信息
    private Items items;

    //为了系统 可扩展性,对原始生成的po进行扩展
    private ItemsCustom itemsCustom;

    //批量商品信息
    private List<ItemsCustom> itemsList;
// 批量修改商品提交
// 通过ItemsQueryVo接收批量提交的商品信息,将商品信息存储到itemsQueryVo中itemsList属性中。
@RequestMapping("/editItemsAllSubmit")
public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo) throws Exception {

    return "success";
}
页面定义:
<c:forEach items="${itemsList }" var="item" varStatus="status">
    <tr>

        <td><input name="itemsList[${status.index }].name" value="${item.name }"/></td>
        <td><input name="itemsList[${status.index }].price" value="${item.price }"/></td>
        <td><input name="itemsList[${status.index }].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
        <td><input name="itemsList[${status.index }].detail" value="${item.detail }"/></td>

    </tr>
</c:forEach>
 name="itemsList对应包装的pojo中的list类型的属性名
${status.index 下标从0开始
detail" value="${item.detail 对应了包装pojo中List类型的属性的pojo的属性名

name的格式:

对应包装pojo中的list类型属性名[下标(从0开始)].包装pojo中List类型的属性中pojo的属性名

例子

“name=”itemsList[${status.index }].price”

可以和包装类型的参数绑定归纳对比一下,其实就是在包装类的pojo基础上多了个下标。只不过包装类参数绑定时,要和包装pojo中的pojo类性的属性名一致,而list参数绑定时,要和包装pojo中的list类型的属性名一致。

map绑定

也通过在包装pojo中定义map类型属性。

在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。

包装类中定义Map对象如下:

Public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
  //get/set方法..
}
页面定义如下:
<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>
Contrller方法定义如下:
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

4.服务端校验

项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。

服务端校验:

控制层conroller:校验页面请求的参数的合法性。在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
持久层dao:一般是不校验的。
springmvc校验需求

springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。

校验思路

页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。

具体需求:

商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。

环境准备

我们需要三个jar包:

hibernate-validator.jar
jboss-logging.jar
validation-api.jar
这里我们添加maven依赖

<!-- hibernate 校验 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.4.Final</version>
</dependency>

查看maven依赖树

[INFO] \- org.hibernate:hibernate-validator:jar:5.2.4.Final:compile
[INFO]    +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO]    +- org.jboss.logging:jboss-logging:jar:3.2.1.Final:compile
[INFO]    \- com.fasterxml:classmate:jar:1.1.0:compile
可以看到,另外两个jar包被hibernate-validator依赖,所以不用再额外添加了

配置校验器

在springmvc.xml中添加

<!-- 校验器 -->
<bean id="validator"
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- hibernate校验器-->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
    <!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
    <property name="validationMessageSource" ref="messageSource" />
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <!-- 资源文件名-->
    <property name="basenames">
        <list>
            <value>classpath:CustomValidationMessages</value>
        </list>
    </property>
    <!-- 资源文件编码格式 -->
    <property name="fileEncodings" value="utf-8" />
    <!-- 对资源文件内容缓存时间,单位秒 -->
    <property name="cacheSeconds" value="120" />
</bean>
校验器注入到处理器适配器中
<mvc:annotation-driven conversion-service="conversionService"
                       validator="validator">
</mvc:annotation-driven>

在CustomValidationMessages.properties配置校验错误信息:

添加校验的错误提示信息

items.name.length.error=请输入1到30个字符的商品名称
items.createtime.isNUll=请输入商品的生产日期
在pojo中添加校验规则

在ItemsCustom.java中添加校验规则:

public class Items {
    private Integer id;
    //校验名称在1到30字符中间
    //message是提示校验出错显示的信息
    //groups:此校验属于哪个分组,groups可以定义多个分组
    @Size(min=1,max=30,message="{items.name.length.error}")
    private String name;

    private Float price;

    private String pic;

    //非空校验
    @NotNull(message="{items.createtime.isNUll}")
    private Date createtime;

捕获和显示校验错误信息
在需要校验的pojo前边添加  @Validated ,在需要校验的pojo后边添加  BindingResult  bindingResult接收校验出错信息
注意 @Validated 和 BindingResult bindingResult是配对出现,并且和参数顺序是固定的(一前一后)
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(
        Model model,
        HttpServletRequest request,
        Integer id,
        @Validated ItemsCustom itemsCustom,
        BindingResult bindingResult)throws Exception {
在controller中将错误信息传到页面即可
//获取校验错误信息
if(bindingResult.hasErrors()){
    // 输出错误信息
    List<ObjectError> allErrors = bindingResult.getAllErrors();

    for (ObjectError objectError :allErrors){
        // 输出错误信息
        System.out.println(objectError.getDefaultMessage());
    }
    // 将错误信息传到页面
    model.addAttribute("allErrors", allErrors);

    //可以直接使用model将提交pojo回显到页面
    model.addAttribute("items", itemsCustom);

    // 出错重新到商品修改页面
    return "items/editItems";
}
页面显示错误信息:
<!-- 显示错误信息 -->
<c:if test="${allErrors!=null }">
    <c:forEach items="${allErrors }" var="error">
        ${ error.defaultMessage}<br/>
    </c:forEach>
</c:if>

分组校验

需求:
在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验
解决方法:
定义多个校验分组(其实是一个java接口),分组中定义有哪些规则
每个controller方法使用不同的校验分组

1.校验分组

public interface ValidGroup1 {
    //接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    //此分组只校验商品名称长度

}

2.在校验规则中添加分组

//校验名称在1到30字符中间
//message是提示校验出错显示的信息
//groups:此校验属于哪个分组,groups可以定义多个分组
@Size(min=1,max=30,message="{items.name.length.error}",groups = {ValidGroup1.class})
private String name;

3.在controller方法使用指定分组的校验

// value={ValidGroup1.class}指定使用ValidGroup1分组的校验
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(
        Model model,
        HttpServletRequest request,
        Integer id,
        @Validated(value = ValidGroup1.class)ItemsCustom itemsCustom,
        BindingResult bindingResult)throws Exception {

5.数据回显

提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面

pojo数据回显方法

1.springmvc默认对pojo数据进行回显。

pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

使用@ModelAttribute指定pojo回显到页面在request中的key

2.@ModelAttribute还可以将方法的返回值传到页面

在商品查询列表页面,通过商品类型查询商品信息。
在controller中定义商品类型查询方法,最终将商品类型传到页面。

 // 商品分类
//@ModelAttribute可以指定pojo回信啊到页面在request中的key
//itemtypes表示最终将方法返回值放在request中的key
@ModelAttribute("itemtypes")
public Map<String, String> getItemTypes() {

    Map<String, String> itemTypes = new HashMap<String, String>();
    itemTypes.put("101", "数码");
    itemTypes.put("102", "母婴");
    return itemTypes;
}
页面上可以得到itemTypes数据。
<td>
    商品名称:<input name="itemsCustom.name" />
    商品类型:
    <select name="itemtype">
        <c:forEach items="${itemtypes}" var="itemtype">
            <option value="${itemtype.key }">${itemtype.value }</option>
        </c:forEach>
    </select>
</td>

3.使用最简单方法使用model,可以不用@ModelAttribute

//可以直接使用model将提交pojo回显到页面
//model.addAttribute(“items”, itemsCustom);

简单类型数据回显
使用最简单方法使用model
model.addAttribute(“id”, id);

猜你喜欢

转载自blog.csdn.net/qq_39128354/article/details/81428537