1、包装类型pojo参数绑定
1.1、需求:
商品查询controller方法中实现商品查询条件传入。
1.2、实现方法
第一种方法:在形参中添加HttpServletRequest request参数,通过request接收查询条件参数。
第二种方法:在形参中让包装类型的pojo接收查询条件参数。
分析:
页面传参数的特点:复杂、多样性。
如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。
建议使用包装类型的pojo,pojo中属性是pojo。
1.3、页面参数和controller方法形参定义
页面参数:
<form action="${pageContext.request.contextPath }/items/queryItems.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td>
商品名称:<input name="itemsCustom.name"/>
</td>
<td><input type="submit" value="查询"/></td>
</tr>
controller方法形参:
@RequestMapping("/queryItems")
public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
2、集合类型绑定
2.1、数组绑定
//批量删除商品信息
@RequestMapping("/deleteItems")
public String deleteItems(Integer[] items_id) throws Exception{
2.1.3、页面定义:
商品列表:
<table width="100%" border=1>
<tr>
<td>选择</td>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<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>
2.2、list绑定
public class ItemsQueryVo {
// 商品信息
private Items items;
private ItemsCustom itemsCustom;
private List<ItemsCustom> itemsList;
修改商品信息提交的方法:
//通过ItemsQueryVo接收批量提交的商品信息,将商品信息存储到itemsQueryVo中itemsList属性中
@RequestMapping("/editItemsAllsubmit")
public String editItemsAllsubmit(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
页面定义:
2.3、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>
3、springmvc校验
3.1、校验理解 <!-- 校验器 -->
<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>
3.5、将校验器注入到处理器适配器中
4、数据回显
5、异常处理
package lsq.study.ssm.exception;
/**
* 系统自定义异常类,针对预期的异常,需要在程序中抛出此类的异常
* @author lsq
*
*/
public class CustomException extends Exception {
// 异常信息
public String message;
public CustomException(String message) {
super(message);
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
5.3、全局异常处理器
package lsq.study.ssm.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* 全局异常处理类
* @author lsq
*
*/
public class CustomExceptionResolver implements HandlerExceptionResolver{
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
//handler就是处理器适配器要执行的handler对象(只有method)
// 1)解析出异常类型
// 2)如果该异常类型是系统自定义异常,直接取出异常信息,在错误页面显示
// String message = null;
// if(ex instanceof CustomException){
// message = ((CustomException)ex).getMessage();
// }else {
3)如果该异常类型不是系统自定义异常,构造一个自定义的异常类型(信息为“未知错误”)
// 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;
}
}
5.4、错误提示页面
<!--
全局异常处理器:
只要实现HandlerExceptionResolver接口就是全局异常处理器
-->
<bean class="lsq.study.ssm.exception.CustomExceptionResolver"></bean>
5.6、异常测试
6、上传图片
<!-- 文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
6.3、加入上传图片的jar包
也可以直接修改tomcat的配置:
7、json数据交互
7.1、为什么要进行json数据交互?
7.2、springmvc进行json交互
7.3、环境准备
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
☆注意:如果使用<mvc:annotation-driven/>,则不用定义上边的内容。
7.4、json交互测试
8、RESTful支持
9、拦截器
package lsq.study.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class HandlerInterceptor1 implements HandlerInterceptor{
//进入Handler方法之前执行
//用于身份认证、身份授权
//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//return false 表示拦截,不再向下执行
//return true 表示放行
return false;
}
//进入Handler方法之后,返回modelandview之前执行
//应用场景:(从ModelAndView出发)将公用的模型数据在这里传到视图,也可以在这里统一制定视图
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
throws Exception {
}
//执行Handler完成执行此方法
//应用场景:统一异常处理,统一日志处理
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
9.2、拦截器配置
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
该方法一般不推荐使用。
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- /**表示所有url包括子url路径 -->
<mvc:mapping path="/**"/>
<bean class="lsq.study.ssm.interceptor.HandlerInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="lsq.study.ssm.interceptor.HandlerInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
9.3、拦截测试
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle
HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion
总结:
preHandle方法按顺序执行,
postHandle和afterCompletion按拦截器配置的逆向顺序执行。
9.3.4、拦截器1放行,拦截器2不放行
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion
总结:
拦截器1放行,拦截器2preHandle才会执行。
拦截器2preHandle不放行,拦截器2postHandle和afterCompletion不会执行。
只要有一个拦截器不放行,postHandle不会执行。
9.3.5、拦截器1不放行,拦截器2不放行
HandlerInterceptor1...preHandle
总结:
拦截器1preHandle不放行,postHandle和afterCompletion不会执行。
拦截器1不执行,拦截器2不执行。
9.3.6、小结
根据测试结果,对拦截器应用。
比如:统一日志处理拦截器,需要该拦截器preHandle一定要放行,且将它放在拦截器链中第一个位置,这样afterCompletion方法才会执行。
比如:登录认证拦截器,放在拦截器链中第一个位置。权限校验拦截器,放在登录认证拦截器之后。(因为登录通过后才校验权限)