springmvc参数绑定,异常处理,json数据交互,拦截器简单应用

1、包装类型pojo参数绑定

2.1、需求
批量修改数据

集合类型的参数绑定
第一步:在包装类ItemsVo中定义一个List<>属性用来批量保存商品信息
在这里插入图片描述

第二步:在controller中编写批量修改的方法

@RequestMapping("/editItems")
public String edtiItems(ItemsVo itemsVo) {
	// TODO Auto-generated method stub
	//修改操作暂不实现  。。。
	System.out.println(itemsVo);
	return "redirect:itemsList.action";
}

第三步:修改jsp页面中 的name属性
注意这里的命名方式

<c:forEach items="${itemsList}" var="item" varStatus="index">
    <tr>
         <td><input style="border: 0px;text-align: center;" type="text" name="itemsCustomes[${index.index}].id" value="${item.id}" readonly="readonly"> </td>
      <td><input type="text" style="border: 0px;text-align: center;" name="itemsCustomes[${index.index}].name" value="${item.name}"></td>
      <td style="width: 150px;height: 150px;"> </td>
      <td><input type="text" style="border: 0px;text-align: center;" name="itemsCustomes[${index.index}].createtime"
				value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd mm:HH:ss"/>"></td>
       <td><input type="text" style="border: 0px;text-align: center;" name="itemsCustomes[${index.index}].price" value="${item.price}"></td>
      <td><input type="text" style="border: 0px;text-align: center;" name="itemsCustomes[${index.index}].detail" value="${item.detail}"></td>				
      <td><a href="${pageContext.request.contextPath}/items/selectItemsById.action?id=${item.id}">修改</a></td>
		
</tr>
</c:forEach>

在这里插入图片描述

测试结果:

在这里插入图片描述

2.2、Map类型的参数绑定
在这里插入图片描述

3、服务端校验
3.1、校验理解
项目中使用较多的是前端的校验,如页面js校验,对于安全要求要求较高建议在服务端进行数据校验。

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

3.2、springmvc校验
springmvc使用的是hibernate的校验框架validation(和hiberanate没有任何关系)
校验思路:
页面提交请求的参数,提交到controller方法中,使用validation进行校验,如果校验出错,将错误信息展示到页面显示中。
3.2.1、需求:商品修改(商品名的长度和生产日期非空),添加校验,如果信息出错,在商品页面显示错误信息。

3.2.2、实现
1)导入jar包
在这里插入图片描述

2)在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"/>
	     <!-- 对资源文件缓存时间,单位秒 -->
	     <peoperty name="cacheSeconds" valie="120"/>
	 </bean>

3)将校验器注入到适配器中(注解驱动方式)
在这里插入图片描述
3.1)将校验器注入到适配器中(非注解驱动方式)
在这里插入图片描述

4)创建错误信息属性文件
在这里插入图片描述

5)在pojo中添加校验规则

在ItemsCustome.java(pojo)中添加校验规则
在这里插入图片描述
在这里插入图片描述

6)在Controller中捕捉错误信息

在这里插入图片描述

测试:

在这里插入图片描述

3.3、校验分组
3.3.1、问题:在pojo中定义校验规则,而pojo被多个controller公用,但是每个controller的校验需求是不同的

3.3.2、解决方法:定义校验分组(其实就是一个接口),分组中定义有不同的规则,每个controller方法根据需求使用不同的校验分组
根据不同需求指定校验规则
1)定义接口
在这里插入图片描述

2)在校验规则中添加分组
在这里插入图片描述

3)在controller中只用校验分组
在这里插入图片描述

4、数据回显
当从当前页面离开后再回到当前页面时,当前页面中的表单数据还存在;
例:当修改信息时,修改出错,回到修改页面,修改页面原本的数据应该还在

4.1、数据回显的实现
数据回显实际上就是将需要会显得数据保存到Request域中
4.1.1、springmvc默认对pojo数据进行回显,
pojo传入controller方法后,springmvc自动及那个pojo数据到request域而key就等于pojo的类名首字母小写

使用@ModelAttribute(“key”)指定pojo数据回显时数据在request域的key,
在这里插入图片描述

@ModelAttribute(“key”)还可以将方法的返回值传回页面保存到Request域
在这里插入图片描述

4.2、使用Model回显
在这里插入图片描述

4.3、简单类型的数据回显只能使用model
在这里插入图片描述

5、异常处理思路

5.1、系统中异常包括两类,预期异常和运行时异常RuntimeException,前者通过异常捕捉从而获得异常信息,后者主要通过规范代码开发、测试手段减少云心是异常的发生。
系统的dao、service、controller都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。如下图:
在这里插入图片描述
springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

5.2、自定义异常类
对不同的异常类型定义异常类型
5.2.1、自定义异常类

/**
 * 自定义异常类
 * 针对预期的异常,需要在程序中抛出异常
 * @author guai
 *
 */
public class CustomizeException  extends Exception{
	 /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//异常信息
	private String message;

	public CustomizeException(String message) {
		super();
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

5.3、全局异常处理器
思路:当系统遇到异常,controller会将全局异常抛给前端控制器,前端控制器调用全局异常处理器。
全局异常处理器处理思路:
解析出异常类型
如果该异常类型是系统自定义的异常,直接取出异常处理,在错误页面展示。
否则:异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误,请联系管理员”)

5.3.1、全局异常处理器需要继承HandlerExceptionResolver接口

/**
 * 全局异常处理类
 * @author guai
 *
 */
public class GlobalExceptionProcess implements HandlerExceptionResolver{

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		//handler就是处理器适配器要执行的Handler对象(只有method)
		//ex就是系统抛出的异常
		// TODO Auto-generated method stub
		CustomizeException ce=null;
		if(ex instanceof CustomizeException) {
			ce=(CustomizeException)ex;
		}else {
			//如果不是系统自定义异常(则属于未知异常),构造一个自定义的异常类型
			ce=new CustomizeException("未知异常!!");
		}
		ModelAndView modelAndView=new ModelAndView();
		modelAndView.addObject("errorMessage",ce.getMessage());
		modelAndView.setViewName("error");
		return modelAndView;
	}
}

5.3.2、搞个错误页面
在这里插入图片描述

5.4、在springmvc.xml中配置全局异常处理器
在这里插入图片描述

5.5、测试
如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出的异常,说明是一个运行时异常,在错误页面显示未知错误

5.5.1、根据id查询商品信息的controller中抛出异常
在这里插入图片描述
测试结果:
在这里插入图片描述

6、springmvc中对多部件类型解析

6.1、需求
在修改信息页面,添加上传商品图片功能

6.2、springmvc对多部件类型解析
在页面form中提交enctype=“multipart/form-data”的数据时,需要springmvc对multipart类型的数据进行解析。
要在springmvc中配置multipart类型解析器

6.3、实现:
在springmvc.xml中配置multipart类型解析器

<!-- 文件上传 -->
	 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	    <!-- 设置文件的最大尺寸 -->
	    <property name="maxUploadSize">
	        <value>5252880</value>
	    </property>
	 </bean>

注意:加入上传图片的jar包
在这里插入图片描述

6.4、创建图片虚拟目录 存储图片
配置虚拟目录
在这里插入图片描述

注意:在图片虚拟目录中,一定将图片分级创建(提高i/o性能),一般采用按日期分级创建。

6.5、上传图片代码
编辑 修改商品信息的controller

if(items_pic!=null) {
			//存储图片的物理路径
			String pic_path="D:\\Software\\Tomcat9.0\\images";
		    //获取原始名称
			String imgFilename=items_pic.getOriginalFilename();
			//新的图片名称
			String newfilename=UUID.randomUUID()+imgFilename.substring(imgFilename.lastIndexOf("."));
			//新图片
			File newFile=new File(pic_path+newfilename);
			
			//将内存中的数据写入磁盘
			items_pic.transferTo(newFile);
			
		    //将新图片名称存到itemsCustome中
			itemsCustome.setPic(newfilename);
		}

在这里插入图片描述

6.6、jsp页面
在这里插入图片描述
测试: 是 iu 呀

在这里插入图片描述

7、Json数据交互
7.1、为什么要进行json数据交互
json数据格式再接口调用中,html而页面中较常用,json格式比较简单,解析还比较方便。
比如:webservice接口,传输的就是json数据

7.2、springmvc进行json交互的两种方式
1)请求json输出json要求请求的时json串,所以在前端页面中需要将请求的内容转化成jsong,不常用
2)请求key/value值,输出json,此方法较为常用
在这里插入图片描述

7.3、环境准备
需要导入的jar包
在这里插入图片描述

7.4、在springmvc.xml中配置
在这里插入图片描述
若使用注解驱动,可以不用配置
在这里插入图片描述

7.5、创建jsp页面
使用jquery的ajax

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>json交互测试</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript">
//请求json,输出json
function requestJson(){
  
    $.ajax({
	type:'post',
	url:'${pageContext.request.contextPath}/items/requestJson.action',
	//设置数据格式
	contentType:'application/json',
	data:'{"name":"手机","price":9999}',
	//请求成功  返回的data数据
	success:function(data){
	    alert(data.name+data.price);
	}
    });
}
//请求key/value,输出时json
function responseJson(){
    $.ajax({
	type:'post',
	url:'${pageContext.request.contextPath}/items/responseJson.action',
	//默认格式为key/value请求
	data:"name=手机&price=9999",
	//请求成功  返回的data数据
	success:function(data){
	    alert(data.name+data.price);
	}
    });
}
</script>

</head>
<body>
<input type="button"onclick="requestJson()" value="请求json"/>
<input type="button"onclick="responseJson()" value="响应json"/>
</body>
</html>

7.6、创建controller方法

// 请求json
//@ResponseBody 指定响应数据为json
//@RequestBody  指定请求数据为json
@ResponseBody
@RequestMapping(value = "/requestJson", method = { RequestMethod.POST })
public  ItemsCustome requestJson(@RequestBody ItemsCustome itemsCustome) {
	System.out.println(itemsCustome);
	return itemsCustome;
}

// 响应json
@ResponseBody
@RequestMapping(value = "/responseJson", method = { RequestMethod.POST })
public ItemsCustome responseJson(ItemsCustome itemsCustome) {
	System.out.println(itemsCustome);
	return itemsCustome;
}

4.7、测试:
在这里插入图片描述

5、RESTful Representational State Trensfer

5.1、什么是RESTful
在这里插入图片描述

5.2、RESTful是一种开发理念
5.2.1、对url进行规范,写RESTful格式的url
非REST的url:http://queryItems.action?id=001&type=T01
REST的url:http://queryItems.action/001/T01
特点:url简洁
不管是删除、添加、更新,,,使用的url是一致的,如果要删除,设置http方法设置为delete,添加时甚至成为put
缺点:需要在controller判断到底进行哪种操作,当需求复杂时,controller中的逻辑判断会十分麻烦。

5.3、状态转换
在这里插入图片描述

5.4、REST简单应用
需求,查询商品信息,返回json数据
定义controller方法,进行REST风格的url映射,将查询商品信息的id传入controller
输出json

5.6、controller方法:
在这里插入图片描述

@ResponseBody
@RequestMapping("/restFulTest/{id}/{name}")
//{id}  表示占位符与@PathVariable中的参数对应
public ItemsCustome selectItemsCustome(@PathVariable("id") int id,@PathVariable("name") String name) {
	ItemsCustome ic=new ItemsCustome();
	ic.setId(id);
	ic.setName(name);
	return ic;
}

5.7、在web.xml中配置RESTful专用前端控制器

  <!-- 配置rest前端控制器 -->
  <servlet>
      <servlet-name>springmvc-rest</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--配置要扫描的springmvc配置文件-->
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc/springmvc.xml</param-value>
      </init-param>
  </servlet>
  <!-- <url-pattern>:指定相对于Servlet的URL的路径。该路径相对于web应用程序上下文的根路径。<servlet-mapping>将URL模式映射到某个Servlet,即该Servlet处理的URL。! -->
  <servlet-mapping>
      <servlet-name>springmvc-rest</servlet-name>
      <url-pattern>/</url-pattern>
  </servlet-mapping>

测试:

在这里插入图片描述

5.8、问题
使用/配置前端控制器的url-partten时,对静态资源的解析出现问题。无法找到静态资源
即下面这种情况
在这里插入图片描述

此时需要在springmvc.xml中配置对静态资源的解析
在这里插入图片描述
配置后:
在这里插入图片描述

6、拦截器
6.1、定义拦截器
需要继承HandlerInterceptor接口
实现接口的三个方法:

//进入Handler前执行
	//用于身份认证和身份授权 若认证不通过当前用户没有成功登录,需要此方法拦截不向下执行
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		//return false 表示拦截,不向下执行
		//return true表示放行
		return false;
	}

	//进入Handler方法之后返回modelAndView之前
	//应用场景从modelAndView出发,填充公用的模型数据在这里传到视图例如:菜单栏,也可以指定统一视图
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
	}

	//执行完Handler方法之后
	//应用场景:统一的异常处理,日志处理
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
	}

6.2、拦截器配置
springmvc不是全局的而是针对HandlerMapping进行拦截的。
1、如果在某个HandlerMapping中配置拦截器,经过该HandlerMapping映射成功的Handler时才拦截。
在这里插入图片描述

2、springmvc也可以配置类似全局的拦截器,springmvc框架会将配置的类似全局的拦截器注入到每个HandllerMapping中。

<!-- 拦截器 -->
	<mvc:interceptors>
	<!-- 多个拦截器顺序执行 -->
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<bean class="com.shuai.interceptor.ControllerInterceptor" />
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<bean class="com.shuai.interceptor.ControllerInterceptor2" />
		</mvc:interceptor>
	</mvc:interceptors>

3、测试多个拦截器在执行时的执行顺序
在拦截方法中加入
System.out.println(“HandlerInterceptor1/2—after/pre/postHandle”);
。。。。。。

两个拦截器都放行时的测试结果:
在这里插入图片描述
在这里插入图片描述

拦截器一放行,拦截器二拦截时测试结果:
在这里插入图片描述

拦截器一不放行,拦截器二不放行,
测试结果:
在这里插入图片描述
拦截器二不执行

6.3、小结:
根据测试结果,拦截器在应用时的注意事项:
对于统一日志处理的拦截器,需要拦截器preHandle一定要放行,且将它放在拦截器链接中第一个位置

对于登录认证的拦截器,放在拦截器链接中第一个位置。

对于权限校验的拦截器应该放在登录认证的拦截器之后。

6.4、登录认证
6.4.1、用户请求url
6.4.2、拦截器进行拦截校验
如果请求的url是不需要登录即可访问的url,允许放行
如果用户session不存在跳转到登录页面
如果用户session存在放行,继续操作

6.4.3、登录controller方法

//登录
	@RequestMapping("login")
	public String login(HttpSession session,String username,String password)throws Exception{
		
		//调用service运行用户身份认证
		
		session.setAttribute("username", username);
		//重定向到用户界面
		return "redirect:/items/selectItems.action";
	}

6.4.4、登录认证拦截实现

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		//获取请求的url
		String url=request.getRequestURI();
		//判断url是否是公开地址,实际应用中将url配在配置文件中
		if(url.indexOf("login.action")>=0) {
			//如果登录放行
			return true;
		}
		//判断session
		HttpSession session=request.getSession();
		//从session中取出身份信息
		String username=(String)session.getAttribute("username");
		if(username!=null) {
			return true;
		}
		
		request.getRequestDispatcher("/login.jsp ").forward(request, response);
		return false;
	}

6.4.5、配置拦截器
在这里插入图片描述

测试:当没有登陆时想要进入查询页面会直接跳到登录页面
在这里插入图片描述

登陆成功后:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值