包装类型pojo参数绑定
需求
商品查询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
集合类型绑定
数组绑定
需求
商品批量删除,用户在页面选择多个商品,批量删除。
表现层实现
关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。(思路)
controller方法定义:
页面定义:
list绑定
需求
通常在需要批量提交数据时,将提交的数据绑定到list<pojo>中,比如:成绩录入(录入多门课成绩,批量提交),
本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。
表现层实现
controller方法定义:
- 进入批量商品修改页面(页面样式参考商品列表实现)
- 批量修改商品提交
使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list<pojo>属性
页面定义:
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());
}
springmvc校验
校验理解
项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。
服务端校验:
控制层conroller:校验页面请求的参数的合法性。在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
持久层dao:一般是不校验的。
springmvc校验需求
springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。
校验思路:
页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
具体需求:
商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。
环境准备
hibernate的校验框架validation所需要jar包:
配置校验器
校验器注入到处理器适配器中
在pojo中添加校验规则
在ItemsCustom.java中添加校验规则:
CustomValidationMessages.properties
在CustomValidationMessages.properties配置校验错误信息:
捕获校验错误信息
//在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
//注意:@Validated和BindingResult bindingResult是配对出现,并且形参顺序是固定的(一前一后)。
在页面显示校验错误信息
在controller中将错误信息传到页面即可。
页面显示错误信息:
分组校验
需求
在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。
解决方法:
定义多个校验分组(其实是一个java接口),分组中定义有哪些规则
每个controller方法使用不同的校验分组
校验分组
在校验规则中添加分组
在controller方法使用指定分组的校验
异常处理
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
自定义异常类
对不同的异常类型定义异常类,继承Exception。
全局异常处理器
思路:
系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。
全局异常处理器处理思路:
解析出异常类型
- 如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
- 如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
springmvc提供一个HandlerExceptionResolver接口
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
//handler就是处理器适配器要执行Handler对象(只有method)
// 解析出异常类型
// 如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
// String message = null;
// if(ex instanceof CustomException){
// message = ((CustomException)ex).getMessage();
// }else{
如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
// message="未知错误";
// }
//上边代码变为
CustomException customException = null;
if(ex instanceof CustomException){
customException = (CustomException)ex;
}else{
customException = new CustomException("未知错误");
}
//错误信息
String message = customException.getMessage();
ModelAndView modelAndView = new ModelAndView();
//将错误信息传到页面
modelAndView.addObject("message", message);
//指向错误页面
modelAndView.setViewName("error");
return modelAndView;
}
错误页面
在springmvc.xml配置全局异常处理器
异常测试
在controller、service、dao中任意一处需要手动抛出异常。
如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。
在商品修改的controller方法中抛出异常 .
在service接口中抛出异常:
如果与业务功能相关的异常,建议在service中抛出异常。
与业务功能没有关系的异常,建议在controller中抛出。
上边的功能,建议在service中抛出异常。