1.高级参数绑定
1.1 包装类型pojo来接收查询条件参数
分析:页面传参数的特点 :复杂,多样性;
规则:页面 参数和controller方法参数定义:<input name="属性1.属性" /> 和 包装类中的属性1一样;
例如:
(1) 客户信息包装类
package cn.labelnet.ssm.po;
/**
* 客户信息包装类
* @author yuan
*
*/
public class FClientCustomVo {
//别名
private String uname;
//客户信息
private FClient client;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public FClient getClient() {
return client;
}
public void setClient(FClient client) {
this.client = client;
}
}
(2)controller
@RequestMapping(value = "/editClientIfofour")
public String editClientIfofour(FClientCustomVo fcvo) throws Exception{
//业务开发
return "/success.jsp";
}
(3)jsp
在这里可以发现 :客户姓名的 input标签name值为 包装类属性.属性
<form method="post" action="${pageContext.request.contextPath}/clients/editClientIfofour.action" enctype="">
<!--
<input type="file" value="上傳圖片 :" name=""><br> -->
客户姓名: <input type="text" name="client.username" /><br> <br>
别名 : <input type="text" name="uname"> <br> <br>
<input type="submit" value="提交">
</form>
1.2 数组绑定
关键:将页面的多选操作,传数组操作
规则:controller的方法参数定义为 数组 :Integer [] ids;
name值一样为 controller的数组名;
<input type="checkbox" name="ids" />
1.3 list绑定
需求:需要批量提交数据的时候,讲提交的数据绑定到List<pojo> 中
比如:成绩的录入,多门课程成绩提交
使用List接收页面提交的批量数据,通过pojo接收,在包装类pojo中,定义list<pojo>属性;
参数定义 :pojo属性 itemlist list;
规则:
实例:
(1)list作为参数时,需要将其封装在包装类中使用
/**
* 客户信息包装类
* @author yuan
*
*/
public class FClientCustomVo {
//别名
private String uname;
//客户信息
private FClient client;
//list类型
private List<FClient> clients;
public List<FClient> getClients() {
return clients;
}
public void setClients(List<FClient> clients) {
this.clients = clients;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public FClient getClient() {
return client;
}
public void setClient(FClient client) {
this.client = client;
}
}
(2)controller :还是包装类
@RequestMapping(value = "/editClientIfofour")
public String editClientIfofour(FClientCustomVo fcvo) throws Exception{
//业务开发
return "/success.jsp";
}
(3)jsp页面中表单 的name值 规则为 :
<c:forEach items="${itemList}" var="item" varStaus="status" >
<input name=" list[${status.index}].name" value="" />
<input name=" list[${status.index}].age" value="" />
</c:forEach>
1.4 map绑定
在包装类中定义map对象,并添加get、set方法,action使用包装对象接收 ;
(1)包装类实现
public classs QueryVo{
private Map<String,Object> itemsinfo=new HashMap<String,Object>();
//get、set
}
(2)页面定义:
<input name="itemsinfo['name']" value="" />
<input name="itemsinfo['age']" value="" />
2.服务端校验
通常使用较多的是前端校验,比如页面js校验。对于安全要求较高的建议在服务端进行校验;
2.1 服务端校验 ?
控制层 controller :校验页面请求的参数的合法性,在控制层校验,不区分客户端(浏览器,手机客户端,远程调用等);
业务层 service : 主要校验关键业务参数,仅限于service接口中使用的参数;
持久层 dao :一般是不校验的;
故,重视业务层的开发,校验比较多;
2.2 springmvc校验开发
springmvc使用hibernate的校验框架validation,但和hibernate没有任何关系;
思路:
页面提交请求参数,请求到controller方法中,使用validation进行校验,如果校验出错,讲错误信息展示到页面;
示例 :需求:添加校验,比如注册日期是否为空的校验;
(1)导入 jar 包
免积分下载 : http://download.youkuaiyun.com/detail/lablenet/9394974
(2)配置校验器
在SpringMvc.xml 中实现配置 校验器 :
<!-- 校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- 配置hibernate校验器 -->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
<!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如过不指定默认使用classpath下的ValidationMessages.properties -->
<property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- 校验错误信息配置文件-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 资源文件名 -->
<property name="basenames">
<list>
<value>classpath:CustomValidationMessage</value>
</list>
</property>
<!-- 资源文件编码格式 -->
<property name="fileEncodings" value="utf-8"></property>
<!-- 对资源文件内容缓存时间,单位秒 -->
<property name="cacheSeconds" value="120"></property>
</bean>
(3)注入到适配器中
<!-- 配置自定义参数映射 -->
<mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>
(4)添加pojo校验规则
public class FClient {
private Integer id;
//校验名称在1~30之间,message是提示的错误显示信息
@Size(min=1,max=30,message="{item.name.length.error}",groups={ValidatedGroup1.class})
private String username;
private String client_certificate_no;
@NotNull(message="{item.born_date.isNull}")
private Date born_date;
private String family_register_address;
}
(5)配置校验提示信息
CustomValidationMessage.properties 配置校验提示信息 :
item.name.length.error=\u59D3\u540D\u957F\u5EA6\u4E0D\u591F1~30
item.born_date.isNull=\u8BF7\u8F93\u5165\u4F60\u7684\u751F\u65E5
(6)捕获校验信息
在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收出错信息;
注意:@Validated和BindingResult bindingResult 是配对出现的,并且形参顺序固定的;
示例 :
/**
* 使用@ModelAtt
* @param m
* @param id
* @param fc
* @param binResult
* @return
* @throws Exception
*/
@RequestMapping("editClientUpdateone")
public String editClientUpdateone(Model m,Integer id,@ModelAttribute("custom") @Validated(value={ValidatedGroup1.class}) FClient fc ,BindingResult binResult) throws Exception{
int i=1/0;
if(binResult.hasErrors()){
List<ObjectError> errors = binResult.getAllErrors();
for (ObjectError objectError : errors) {
System.out.println(objectError.getDefaultMessage());
}
m.addAttribute("errorlist", errors);
return "editClientIfo.action";
}
fc.setCreate_date(new Date());
String result = fcService.updateClientIfo(id, fc);
System.out.println(result);
return "/success.jsp";
}
(7)将错误信息传到页面上
使用Model参数实现 :
if(binResult.hasErrors()){
List<ObjectError> errors = binResult.getAllErrors();
for (ObjectError objectError : errors) {
System.out.println(objectError.getDefaultMessage());
}
m.addAttribute("errorlist", errors);
return "editClientIfo.action";
}
(8)分组校验
在pojo中定义校验规则,而pojo是被多个controller所共有,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验;
解决:定义多个校验分组,其实是一个java接口,分组中定义了那些规则;
定义一个接口 ,可以没有任何方法定义;
示例 :
validationGroup1接口 :
public interface ValidatedGroup1 {
/**
* 校验分组 1
*
*/
}
设置分组 :
public String editClientUpdateone(Model m,Integer id,@ModelAttribute("custom") @Validated(value={ValidatedGroup1.class}) FClient fc ,BindingResult binResult)
pojo 设置分组 :
@Size(min=1,max=30,message="{item.name.length.error}",groups={ValidatedGroup1.class})
private String username;
3.数据回显
什么是数据回显?提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面;
pojo数据回显方法:
(1)springmvc默认对pojo数据进行回显;
pojo数据传入controller方法后,springmvc自动将pojo数据放到request域中,key等于pojo类型的首字母小写;
使用@ModelAttribute("")指定pojo回显到页面在request中的key;
public String editClientUpdateone(Model m,Integer id,@ModelAttribute("custom") @Validated(value={ValidatedGroup1.class}) FClient fc ,BindingResult binResult) throws Exception{
(2)@ModelAttribute("") 还可以表示将方法的返回值放在request中的key中
例如:
//将方法的返回值放在request中的key中
@ModelAttribute("itemsType")
public Map<String,String> getItemTypes(){
Map<String,String> map=new HashMap<String, String>();
map.put("101","黄金");
map.put("102","白银");
return map;
}
注解的方法的返回值就可以获得到了,页面上就可以使用了;
(3)最简单的回显方式
不使用注解,使用model讲需要提交的pojo回显到页面;
model.addAttribute("");
简单类型的数据回显,只能使用model实现;
4.异常处理
预期异常:通过捕获
运行时异常:通过测试,减少dao,service,controller的异常;
思路:
dao,service,controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交给异常处理器进行异常处理;
(1) 自定义异常类
针对预期的异常,需要在程序中抛出此类的异常,继承Exception
package cn.labelnet.ssm.controller.exception;
/**
* 自定义异常类
* TODO
* 作者:原明卓
* 时间:2016年1月7日 下午4:36:10
* 工程:SpringMvcMybatis1Demo
*/
public class CustomException extends Exception {
private String msg;
public CustomException(String msg) {
super(msg);
this.msg=msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
(2) 全局异常处理器
思路:实现 HandlerExceptionResolver
解析出异常类型;
如果该异常类型是系统自定义的异常,直接取出异常信息并展示;
如果该异常类型不是自定义的异常,则构造一个自定义的异常类型信息;
package cn.labelnet.ssm.controller.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* 全局异常处理器
* TODO
* 作者:原明卓
* 时间:2016年1月7日 下午4:40:18
* 工程:SpringMvcMybatis1Demo
*/
public class CustomExceptionResover implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception ex) {
// 解析出异常类型;
// 如果该异常类型是系统自定义的异常,直接取出异常信息并展示;
// 如果该异常类型不是自定义的异常,则构造一个自定义的异常类型信息;
CustomException customException=null;
if(ex instanceof CustomException){
//是自定义异常类
customException=(CustomException) ex;
}else{
customException=new CustomException("未知错误:"+ex.getMessage());
}
String msg=customException.getMsg();
ModelAndView andView = new ModelAndView();
andView.addObject("msg", msg);
andView.setViewName("/error.jsp");
return andView;
}
}
(3) SpringMvc 配置使用
只要实现了HandlerExceptionResolver接口就是全局处理器,只需要配置class就可以了;
<!-- 配置全局异常处理类 -->
<bean class="cn.labelnet.ssm.controller.exception.CustomExceptionResover"></bean>
( 4)测试
如果与业务功能相关的异常,建议在service中抛出异常。
与业务功能没有关系的异常,建议在controller中抛出异常;