SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器

一、参数绑定、@RequestMapping、Controller返回值


绑定数组:在jsp页面中传入数组,在Controller页面接收

	//数组参数绑定测试   
	//jsp页面传来一个 Integer数组
	@RequestMapping(value="/deletes.action")
	public ModelAndView deletes(Integer[] ids){   //ids为多个id,数组形式
		
		//测试输出数组
		for (Integer integer : ids) {
			System.out.println(integer);
		}
		
		ModelAndView modelAndView = new ModelAndView();
		//跳转到成功界面
		modelAndView.setViewName("editItem");
		return modelAndView;
	}

绑定List:
作用:可批量修改表单
描述:在jsp页面提交List,在Controller页面接收

jsp页面
	在<c:forEach> 中使用  varStatus。 目的:使用循环变量状态作为集合序号
	<c:forEach items="${itemList }" var="item" varStatus="s"> 
	<tr>
		<td><input type="checkbox" name="ids" value="${item.id}"/></td>
		
		 <!--  itemList[0]在集合中放入名称、价格  itemList[${s.index }].name   -->
		<td><input type="text" name="itemList[${s.index }].name"   value="${item.name }" /></td>  
		<td><input type="text" name="itemList[${s.index }].price"   value="${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 }/toEdit.action?id=${item.id}">修改</a></td>
	</tr>
	</c:forEach>
	
Controller代码	
	//集合参数绑定测试
	//jsp页面传来list(多个对象)
	@RequestMapping(value="/updates.action")
	public ModelAndView updates(QueryVo vo) throws MessageException{   //list集合需要存入QueryVo中
		
		
		//测试输出List
		for (Items item : vo.getItemList()) {
			System.out.println(item.getName());
			System.out.println(item.getPrice());
		}
		
		ModelAndView modelAndView = new ModelAndView();
		//跳转到成功界面
		modelAndView.setViewName("success");
		return modelAndView;
	}

@RequestMapping

作用:通过@RequestMapping注解可以定义不同的处理器映射规则
	1)URL路径映射  @RequestMapping(value="路径")
	
	2)指定通用请求前缀:在class上添加@RequestMapping(url)
	
	3)请求方法限定:限定get/post请求方式
		[email protected](method = RequestMethod.GET)
		[email protected](method = RequestMethod.POST)
		[email protected](method = {RequestMethod.GET,RequestMethod.POST})

Controller方法返回值

1)返回ModelAndView     带着数据与视图路径    不建议使用

2)返回void      ajax、json 异步请求使用

3)返回字符串     返回视图路径   并使用model带数据   (官方推荐:原因、解耦 .数据视图分离)  
	 1.Redirect重定向
	 2.forward转发

二、异常


两类:
1)未知异常
2)预期异常

springMVC异常处理流程:
SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器

未知异常

实现步骤:
 	1)自定义异常类,实现 HandlerExceptionResolver 接口
 	2)配置springmvc.xml
	 		<!-- springMVC 自定义异常处理器实例化 -->
			<bean class="springmvc.exception.ExceptionResolver"/>

未知异常示例:

/**
 * 自定义实现异常处理器
 * 
 * 实现接口HandlerExceptionResolver
 * @author 一万年行不行
 *
 */
public class ExceptionResolver implements HandlerExceptionResolver {

	@Override
	public ModelAndView resolveException( HttpServletRequest req, HttpServletResponse res, Object obj,Exception e) {
		//obj  为发生异常的地方  为字符串格式(包名+类名+方法名)  日志中会记录obj
		//e 子类异常会被Exception接收 
		
		ModelAndView mav = new ModelAndView();
		
		mav.addObject("error","未知异常");

		mav.setViewName("error");  //设置跳转视图
		return mav;
	}
}

预期异常

实现步骤:
1)创建异常信息类 、配置springmvc.xml
2)在Controller中设定异常信息,并抛出异常
3)异常处理器,处理异常

1)创建异常信息类

	//继承Exception类  可作为子类在自定义异常中输出msg
	public class MessageException extends Exception {
		private String msg;
		
		//构造器
		public MessageException(String msg) {
			super();
			this.msg = msg;
		}
	
		public String getMsg() {
			return msg;
		}
	
		public void setMsg(String msg) {
			this.msg = msg;
		}
	}

2)在Controller中设定异常信息,并抛出异常

//集合参数绑定测试
	//jsp页面传来list(多个对象)
	@RequestMapping(value="/updates.action")
	public ModelAndView updates(QueryVo vo) throws MessageException{   //list集合需要存入QueryVo中
		
		//创建未知异常
		//Integer i = 1/0;  
		
		//创建预期异常
		if(null == null){
			throw new MessageException("商品信息不能为空");
		}
		
	
		
		ModelAndView modelAndView = new ModelAndView();
		//跳转到成功界面
		modelAndView.setViewName("success");
		return modelAndView;
	}

3)异常处理器,处理异常

/**
 * 自定义实现异常处理器
 * 
 * 实现接口HandlerExceptionResolver
 * @author 一万年行不行
 *
 */
public class ExceptionResolver implements HandlerExceptionResolver {

	@Override
	public ModelAndView resolveException(
			HttpServletRequest req, HttpServletResponse res, 
			Object obj,Exception e) {
		//obj  为发生异常的地方  为字符串格式(包名+类名+方法名)  日志中会记录obj
		//e 子类异常会被Exception接收 
		
		ModelAndView mav = new ModelAndView();
		
		//判断异常类型
		if(e instanceof MessageException){  //e为预期异常,
			
			 //将父类异常e 转为子类MessageException
			MessageException me = (MessageException) e; 
			
			System.out.println(me.getMsg());
			//将异常信息设置到 error中
			mav.addObject("error",me.getMsg()); 
		}else {
			mav.addObject("error","未知异常");
		}

		mav.setViewName("error");  //设置跳转视图
		return mav;
	}
}

三、上传图片


配置虚拟目录

目的:在本地建立目录保存图片,而不是放进WebRoot中
作用:防止项目在上线或操作过程中图片丢失

SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器

上传实现:

1)导入上传图片所需jar包

2)springmvc.xm中l配置上传解析器

3)jsp表单修改提交类型 : enctype="multipart/form-data"

4)Controller中实现图片上传

1)导入上传图片所需jar包
SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器
2)springmvc.xm中l配置上传解析器

	<!-- 上传图片实现类   id与class值固定-->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 上传图片大小 5M -->
		<property name="maxUploadSize" value="5242880"></property>
	</bean>

3)jsp表单修改提交类型 : enctype="multipart/form-data"

<form id="itemForm"	action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data">

4)Controller中实现图片上传

	//提交修改
	@RequestMapping(value = "/updateitem.action")
	public String updateitem(Items items,MultipartFile pictureFile) throws Exception{  //接收图片类型 
		
		//保存图片到本地E:\springmvc_pic
		//为图片设置名称,防止名称重复
		String picName = UUID.randomUUID().toString();
		
		// 获取文件名
		String oriName = pictureFile.getOriginalFilename();
		// 获取图片后缀
		String extName = oriName.substring(oriName.lastIndexOf("."));

		// 开始上传  pictureFile.transferTo()  可将图片直接保存到指定地址
		pictureFile.transferTo(new File("E:\\springmvc_pic\\" + picName + extName));

		items.setPic(picName + extName); //保存到数据库的图片名
		items.setCreatetime(new Date());
		//修改
		itemService.updateByPrimaryKeyWithBLOBs(items);;
		
		return "redirect:/toEdit.action?id=" + items.getId();  //重定向到修改页面,查看是否上传成功
	}

四、json数据交互


知识点:
1)@RequestBody
	作用:用于读取http请求的内容(字符串),
	细节:通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。

	本例应用:
	@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象进行绑定

2)@ResponseBody
	作用:用于将Controller的方法返回给对象,
	细节:通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
	
	本例应用:@ResponseBody注解实现将Controller方法返回java对象转换为json响应给客户端。

实现步骤:

1)导入jar包、

2)引入js、ajax编写

3)Controller编写

1)导入jar包
SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器
2)引入js、ajax编写
SpringMVC_02---参数绑定、异常处理、图片上传、json交互、拦截器

ajax编写
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
	$(function(){
		
		//定义Json格式字符串
		var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}';
		
		$.ajax({
			url : "${pageContext.request.contextPath }/json.action",
			data : params,
			contentType : "application/json;charset=UTF-8", //数据编码格式
			type : "post",
			dataType : "json",  //回调
			success : function(data){
				alert(data.name);
			}
		});
	});
</script>

3)Controller编写**

//测试json格式的数据交互
	@RequestMapping(value = "/json.action")
	public @ResponseBody 
	Items json(@RequestBody Items item){
		
		return item;  //返回对象
	}

五、拦截器


SpringMVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。

三种控制时机
	1)preHandler:进入方法前
	2)postHandler:进入方法后
	3)afterCompletion:视图渲染后

多个拦截器调用时序
	preHandle按拦截器定义顺序调用
	postHandler按拦截器定义逆序调用
	afterCompletion按拦截器定义逆序调用
	
	postHandler在拦截器链内所有拦截器返成功调用
	afterCompletion只有preHandle返回true才调用

实现步骤:
1)创建拦截器类,实现HandlerInterceptor接口,编写拦截方法
2)springmvc.xml中配置拦截器

1)创建拦截器类,实现HandlerInterceptor接口,编写拦截方法

/**
 * 拦截器:实现接口 HandlerInterceptor
 * @author 一万年行不行
 *
 */
public class Interceptor2 implements HandlerInterceptor {


	// Controller执行前调用此方法
	// 返回true表示继续执行,返回false中止执行
	// 这里可以加入登录校验、权限拦截等
	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		System.out.println("方法前");
		// 设置为true,测试使用
		return true;
	}

	// controller执行后但未返回视图前调用此方法
	// 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		System.out.println("方法后");
	}

	// controller执行后且视图返回后调用此方法
	// 这里可得到执行controller时的异常信息
	// 这里可记录操作日志
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		System.out.println("渲染后");
	}
}
2)springmvc.xml中配置拦截器
	
	<!-- 配置拦截器 -->
	<mvc:interceptors>
		<!-- 配置拦截器1 -->
		<mvc:interceptor>
			<mvc:mapping path="/**"/>  <!-- 设置被拦截的path -->
			<bean class="springmvc.interceptor.Interceptor1"/>   <!-- 拦截进入的类 -->
		</mvc:interceptor>
		
		<!-- 配置拦截器2 -->
		<mvc:interceptor>
			<mvc:mapping path="/**"/> 
			<bean class="springmvc.interceptor.Interceptor2"/> 
		</mvc:interceptor>
	</mvc:interceptors>

拦截器应用:拦截是否登陆

流程:
a) 拦截用户请求,判断用户是否登录(登录请求不能拦截)
b) 如果用户已经登录。放行
c) 如果用户未登录,跳转到登录页面。

1)创建拦截器类

/**
 * 拦截器:实现接口 HandlerInterceptor
 * 
 * 是/否放行--- true/false
 * 
 * @author 一万年行不行
 *
 */
public class Interceptor1 implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
		System.out.println("方法前1111");
		
		//得到当前URI 判断用户是否在登陆页面
		String requestURI = request.getRequestURI();
	
		if (!requestURI.contains("/login")) {  //用户不在login页面,判断是否登陆
		
			String username = (String) request.getSession().getAttribute("USER_SESSION");
		
			if(username == null){  //用户为登陆,跳转到登陆界面
				response.sendRedirect(request.getContextPath() + "/login.action");
				return false;  //不放行
			}
		} 
		return true; //用户在登陆界面,直接放行
	}
	
	
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		System.out.println("方法后11111");
	}
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		System.out.println("页面渲染后11111");
	}
}

2)springmvc.xml中配置拦截器

<!-- 配置拦截器 -->
	<mvc:interceptors>
		
		<!-- 配置拦截器 -->
		<mvc:interceptor>
			<mvc:mapping path="/**"/>  <!-- 设置被拦截的path -->
			<bean class="springmvc.interceptor.Interceptor1"/>   <!-- 拦截进入的类 -->
		</mvc:interceptor>

	</mvc:interceptors>

3)Controller编写

	//去登陆界面  //筛选get请求
	@RequestMapping(value="/login.action",method = RequestMethod.GET)
	public String login(){
		return "login";
	}
	
	//提交登陆  //筛选post请求
	@RequestMapping(value="/login.action",method = RequestMethod.POST)
	public String login(String username,HttpSession session){
		session.setAttribute("USER_SESSION", username);  //将用户名设置进session
		return "redirect:/itemList.action";  //重定向到列表页面
	}