百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

SpringMVC学习笔记文本版(四)-完结篇

toyiye 2024-06-21 12:17 10 浏览 0 评论

接上期《SpringMVC学习笔记文本版(三)》

17.4.10.7 异常处理

17.4.10.7.1.异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,预期异常通过捕获异常从而获取异常信息,

运行时异常RuntimeException主要通过规范代码开发、测试通过手段较少运行时异常发生。

系统的dao、service、controller出现通过throws Exception向上抛出,最后由前端控制器交由异常处理器进行异常处理。

总体思路:springmvc提供全局的异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

17.4.10.7.2.自定义异常类

对不同的异常类型定义异常类,继承Exception。

package org.hxweb.web.ssm.exception;

/**

* @see 自定义异常:针对预期异常类,需要在系统中抛出此类异常提示信息

* @author Administrator

*

*/

public class CustomException extends Exception{

//异常提示信息

public String messge;

public CustomException(String message){

super(message);

this.messge = message;

}

public String getMessge() {

return messge;

}

public void setMessge(String messge) {

this.messge = messge;

}

}

17.4.10.7.3.全局异常处理器

思路:

系统遇到异常,在程序中手动抛出,dao抛给service,service抛给controller,controller抛给前段控制器,前端控制器调用全局异常处理器。

全局异常处理器处理思路:

解析出异常类型

如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面显示。

如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)。

springmvc提供一个HandlerExceptionResolver接口:

package org.hxweb.web.ssm.exception;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;

import org.springframework.web.servlet.HandlerExceptionResolver;

import org.springframework.web.servlet.ModelAndView;

/**

* @see 全局异常处理器

* @author Administrator

*

*/

public class CustomExceptionResolver implements HandlerExceptionResolver{

/**

* @see 全局异常处理

* Handler:就是处理器适配器要执行的Handler对象(只有一个method方法)

* ex:就是系统抛出的异常

*/

@Override

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,

Exception ex) {

//Handler:就是处理器适配器要执行的Handler对象(只有一个method方法)

//ex:就是系统抛出的异常

//解析出异常类型

//异常信息

/* String message=null;

//如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面显示。

if(ex instanceof CustomException){

message = ((CustomException)ex).getMessge();

} else {

//如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)。

message = "未知错误";

}

*/

CustomException customException = null;

//如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面显示。

if(ex instanceof CustomException){

customException = (CustomException)ex;

} else {

//如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)。

customException = new CustomException("未知错误");

}

//异常提示信息

String message = customException.getMessge();

ModelAndView modelAndView = new ModelAndView();

//将异常提示信息传到页面

modelAndView.addObject("message", message);

//指向错误页面

modelAndView.setViewName("error");

return modelAndView;

}

}

17.4.10.7.4.异常提示页面(error.jsp):

<%@ 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>异常提示</title>

</head>

<body>

<font color="red">

${message }

</font>

</body>

</html>

17.4.10.7.5.在springmvc.xml中配置全局异常处理器

<!-- 全局异常处理器

只要实现了HandlerExceptionResolver接口,只要配置bean 就会起作用

-->

<bean class="org.hxweb.web.ssm.exception.CustomExceptionResolver"></bean>

17.4.10.7.6.测试异常

在controller、service、dao中任意一处手动抛出异常。

如果异常是程序中手动抛出的,则在异常信息提示页面抛出自定义的异常信息,

如果异常不是手动抛出,则说明是运行时异常,在异常信息提示页面只显示"未知错误.".

在商品修改的 controller 方法中手动抛出异常:

// 商品信息修改页面显示(展示)。

// @RequestMapping("/editItems")

// 限制 http 请求的方法 为post和get

@RequestMapping(value = "/editItems", method = { RequestMethod.POST, RequestMethod.GET })

// @RequestParam里边指定request传入参数名称和形参进行绑定。

// 通过required属性指定参数是否必须要传入

// 通过defaultValue可以设置默认值,如果id参数没有传入,将默认值和形参绑定。

public String editItems(Model model, @RequestParam(value = "id", required = true) Integer items_id)

throws Exception {

/*

* 调用service来查找根据商品id从 数据库查询对应商品的信息

*/

ItemsCustom itemsCustom = itemsService.findItemsById(items_id);

//判断商品是否为空,根据id没有查询到商品,抛出异常,提示用户商品信息不存在。

if (itemsCustom == null) {

throw new CustomException("修改的商品信息不存在!");

}

// 为返回ModelAndView填充数据和指定视图

// ModelAndView modelAndView = new ModelAndView();

// 相当于request.setAtttibute,在jsp页面可以通过items获取商品修改信息展示

// modelAndView.addObject("itemsCustom", itemsCustom);

// 指定返回视图

// modelAndView.setViewName("/WEB-INF/jsp/items/editItems.jsp");

// modelAndView.setViewName("items/editItems");

// 通过形参中model将model数据传到页面

// 相当于modelAndView.addObject方法

model.addAttribute("itemsCustom", itemsCustom);

return "items/editItems";

}

在service中手动抛出异常:

@Override

public ItemsCustom findItemsById(Integer id) throws Exception {

//利用ItemsMapper查询数据库

Items items = ItemsMapper.selectByPrimaryKey(id);

//判断商品是否为空,根据id没有查询到商品,抛出异常,提示用户商品信息不存在。

if (items == null) {

throw new CustomException("修改的商品信息不存在!");

}

如果与业务功能相关的异常,建议在 service 中手动抛出异常。

如果与业务功能无关的异常,建议在 controller 中手动抛出异常。

商品修改功能的异常抛出,建议在 service 中手动抛出异常。

判断商品是否为空,根据id没有查询到商品,抛出异常,提示用户商品信息不存在。

17.4.10.7.7. 上传图片

17.4.10.7.7.1 需求

在修改商品页面,添加上传商品图片功能。

17.4.10.7.7.2 springmvc中对多部件类型的解析

1.在页面form提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析。

2.在springmvc.xml中配置multipart类型解析器

<!-- 文件上传 -->

<bean id="multipartResolver"

class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<!-- 设置上传文件的最大尺寸为5MB -->

<property name="maxUploadSize">

<value>5242880</value>

</property>

</bean>

3.加入上传图片的jar包,这里通过maven依赖加入

<!-- 上传组件包 -->

<dependency>

<groupId>commons-fileupload</groupId>

<artifactId>commons-fileupload</artifactId>

<version>1.3.1</version>

</dependency>

<dependency>

<groupId>commons-io</groupId>

<artifactId>commons-io</artifactId>

<version>2.4</version>

</dependency>

<dependency>

<groupId>commons-codec</groupId>

<artifactId>commons-codec</artifactId>

<version>1.9</version>

</dependency>

<dependency>

<groupId>org.codehaus.jackson</groupId>

<artifactId>jackson-core-asl</artifactId>

<version>1.9.13</version>

</dependency>

<dependency>

<groupId>org.apache.bval</groupId>

<artifactId>bval-jsr</artifactId>

<version>1.1.1</version>

</dependency>

17.4.10.7.7.3 创建图片虚拟目录 存储图片

1.图片配置

2.修改tomcat conf/service.xml文件 添加如下内容

<Context docBase="F:\workspaces\Neon\ssmhxweb\src\main\webapp\upload\temp" path="/pic" reloadable="true"/></Host>

注意:在图片虚拟目录中,一定要将图片目录分级创建(提高I/O性能),一般采用按日期(年、月、日)进行分级创建。

17.4.10.7.7.4 上传代码:

1.修改 controller 商品修改方法代码:

// 商品信息修改提交。

//在需要校验的pojo前边添加 @Validated注解,在需要校验的pojo后边添加 BindingResult bindingResult接收校验出错提示信息

//注意: @Validated注解和BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)。

//value={ValidGroupEdit.class} 指定使用ValidGroupEdit分组的校验

//@ModelAttribute(value="itemsCustom") 指定pojo回显到request域中的key

@RequestMapping("/editItemsSubmit")

public String editItemsSubmit(Model model,HttpServletRequest request, Integer id,

@Validated(value={ValidGroupEdit.class}) ItemsCustom itemsCustom,

BindingResult bindingResult,

MultipartFile items_pic //接收商品图片

) throws Exception {

//获取校验错误提示信息

if(bindingResult.hasErrors()){

//输出错误提示信息

List<ObjectError> allErrors = bindingResult.getAllErrors();

for(ObjectError objectError:allErrors){

System.out.println(objectError.getDefaultMessage());

}

//错误提示信息传到页面

model.addAttribute("allErrors",allErrors);

//可以直接使用Model将回显的pojo直接回显到页面,key值与页面中的变量名称一致

model.addAttribute("itemsCustom", itemsCustom);

//简单数据类型直接使用model

//model.addAttribute("id", id);

//校验不通过跳转到当前页面(重新到商品修改页面)

return "items/editItems";

}

//上传图片

if (items_pic != null && items_pic.getOriginalFilename() != null && items_pic.getOriginalFilename().length()>0) {

//存储图片的物理路径

String picPath ="F:\\workspaces\\Neon\\ssmhxweb\\src\\main\\webapp\\upload\\temp\\";

//获取图片的原始文件名

String picOriginalFilename = items_pic.getOriginalFilename();

//新的图片名称: UUID随机串+原始图片的扩展名

String picNewFilename = UUID.randomUUID()+picOriginalFilename.substring(picOriginalFilename.lastIndexOf("."));

//图片新文件=存储图片的物理路径+新的图片名称

File picNewFile = new File(picPath+picNewFilename);

//将内存中的图片数据写入到磁盘

items_pic.transferTo(picNewFile);

//将新的商品图片名称写到itemsCustom中

itemsCustom.setPic(picNewFilename);

}

/*

* 调用service来根据商品id更新数据库对应商品的信息

*/

itemsService.updateItems(id, itemsCustom);

// 重定向到商品查询列表

// return "redirect:queryItems.action";

// 转发到商品查询列表

return "forward:queryItems.action";

}

2.图片展示设上传页面代码:

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

<input type="hidden" name="id" value="${itemsCustom.id }"/>

<input type="hidden" name="pic" value="${itemsCustom.pic }"/>

修改商品信息:

<table width="100%" border=1>

<tr>

<td>商品名称</td>

<td><input type="text" name="name" value="${itemsCustom.name }"/></td>

</tr>

<tr>

<td>商品价格</td>

<td><input type="text" name="price" value="${itemsCustom.price }"/></td>

</tr>

<tr>

<td>商品生产日期</td>

<td><input type="text" name="createtime" value="<fmt:formatDate value="${itemsCustom.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>

</tr>

<tr>

<td>商品图片</td>

<td>

<c:if test="${itemsCustom.pic != null}">

<img src="/pic/${itemsCustom.pic}" width=100 height=100/>

<br/>

</c:if>

<input type="file" name="items_pic" />

</td>

</tr>

<tr>

<td>商品简介</td>

<td>

<textarea rows="3" cols="30" name="detail">${itemsCustom.detail }</textarea>

</td>

</tr>

<tr>

<td colspan="2" align="center"><input type="submit" value="提交"/>

</td>

</tr>

</table>

</form>

17.4.10.7.8 json数据交互

8.1 为什么叫进行json数据交互

json数据格式在接口调用中、html页面中教常用,json格式比较简单,解析比较方便。

比如:webservice接口,传输json数据。

8.2 springmvc进行json交互

1.流程:客户端请求的是json串(contentType=application/json),springmvc需要通过 @RequestBody 注解 将json串转成java对象,需要通过 @Response 注解 将java对象转成json串输

出。

客户端请求的是key/value串(contentType=application/x-www-form-urlen:默认的,不用指定),springmvc不需要通过 @RequestBody 注解 将json串转成java对象,需要通过

@Response 注解 将java对象转成json串输出。

最终都输出json数据,为了在前端页面方便对请求结果进行解析。

2.请求json,输出json,要求请求是json串,所以在前端页面需要将请求的内容转成json,不太方便。

3.请求key/value,输出json。次方法比较常用。

8.3 环境准备

8.3.1 springmvc 默认用 MappingJacksonHttpMessageConvertor 对 json数据进行转换, 通过 @RequestBody 注解 @Response 注解来进行json转换 ,

需要导入 jackson有关的jar包,通过maven依赖导入:

<!-- json jar 包 -->

<dependency>

<groupId>org.codehaus.jackson</groupId>

<artifactId>jackson-core-asl</artifactId>

<version>1.9.13</version>

</dependency>

<dependency>

<groupId>org.codehaus.jackson</groupId>

<artifactId>jackson-mapper-asl</artifactId>

<version>1.9.13</version>

</dependency>

8.3.2 配置json转换器

使用了<mvc:annotation-driven />,就不用单独配置json转换器。

8.4 json测试

8.4.1 输入的是json串,输出的是json串。

jsp页面:

使用jquery的ajax提交json串,对输出的json结果进行解析。

<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>

<script type="text/javascript">

//请求json,输出是json

function requestJson(){

$.ajax({

type:'post',

url:'${pageContext.request.contextPath }/requestJson.action',

contentType:'application/json;charset=utf-8',

//数据格式是json串,商品信息

data:'{"name":"手机","price":999}',

success:function(data){//返回json结果

alert(data);

}

});

}

controller 方法:

/**

* @see 请求json(商品信息),输出json(商品信息)

* @return

*/

@RequestMapping("/requestJson")

//@RequestBody将商品信息请求json串转成itemsCustom对象

//@ResponseBody将itemsCustom转成json输出

public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){

//@ResponseBody将itemsCustom转成json输出

return itemsCustom;

}

8.4.2 输入的是key/value 输出的是json串。

jsp页面:

使用jquery的ajax提交key/value串,对输出的json结果进行解析。

//请求key/value,输出是json

function responseJson(){

$.ajax({

type:'post',

url:'${pageContext.request.contextPath }/responseJson.action',

//请求是key/value这里不需要指定contentType,因为默认就 是key/value类型

//contentType:'application/json;charset=utf-8',

//数据格式是json串,商品信息

data:'name=手机&price=999',

success:function(data){//返回json结果

alert(data.name);

}

});

}

controller 方法:

/**

* @see 请求key/value,输出json

* @return

*/

@RequestMapping("/responseJson")

//@ResponseBody将itemsCustom转成json输出

public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){

//@ResponseBody将itemsCustom转成json输出

return itemsCustom;

}

17.4.10.7.9 RESTful 支持

9.1 什么是RESTful

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

RESTful(Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化")其实是一个开发理念,是对http的很好的诠释。

9.1.1 对url进行规范,写RESTful格式url

查询商品url:

非RESTful格式的url: http://.../queryItems.action?id=001&type=A001

RESTful格式url: http://../items/001

特点:url非常简洁,将参数通过url传到服务端。

9.1.2 http方法规范

不管是删除、添加、更新...使用的url是一致的,如果进行删除,需要设置http的方法为delete,添加、更新也同理。

后台 controller 方法 判断http方法,如果是delete执行删除,如果是post执行添加。

9.1.3 对http的 contentType 规范

请求时指定contentType,要json数据,设置成json格式的contentType=application/json

9.2 RESTful 案列

9.2.1 需求

查询商品信息,返回json数据。

9.2.2 controller 方法

定义方法,进行映射url时使用RESTful格式的url,将查询商品的id传到controller方法

输出json利用 @ResponseBody 注解将java对象输出json。

//RESTful格式的查询商品信息,输出json

///ItemsFind/{id}中大括号中的{id}表示将这个位置的参数传到@PathVariable指定的对应名称的参数中

@RequestMapping("/ItemsFind/{id}")

public @ResponseBody ItemsCustom ItemsFind(@PathVariable("id") Integer id) throws Exception{

ItemsCustom itemsCustom = itemsService.findItemsById(id);

return itemsCustom;

}

9.2.3 RESTful 格式的前端控制器配置

<!--RESTful风格 配置前端控制器 -->

<servlet>

<servlet-name>springmvc-rest</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!-- contextConfigLocation 1.配置springmvc需要加载的配置文件(配置处理器映射器、处理器适配器、处理器、视图解析器等)

2.如果不配置contextConfigLocation,就会默认加载/WEB-INF/servlet名称-servlet.xml (这里是springmvc-servlet.xml) -->

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:config/spring/springmvc.xml</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>springmvc-rest</servlet-name>

<!-- 多种配置方式: 第一种:*.action,*.do 访问以.action、.do为结尾的由DispatcherServlet来解析。

第二种:/ 所有访问地址都由DispatcherServlet来解析,对应静态文件需要配置不由DispatcherServlet进行解析。

使用此种方式可以实现RESTFul风格的url

第三种:/* 这种配置方式存在问题(不要用这种方式):最终转发到一个jsp页面时,

仍然会由由DispatcherServlet解析jsp页面,不能根据jsp页面找到对应的Handler,会报错。也不符合我们设计思想。

-->

<url-pattern>/</url-pattern>

</servlet-mapping>

9.3 对静态资源的解析

在springmvc中配置静态资源配置

<!-- default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,

它会对进入 DispatcherServlet 的请求进行筛查, 如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的 Servlet

处理. 如果不是静态资源的请求,才由 DispatcherServlet 继续处理 一般 WEB 应用服务器默认的 Servlet 的名称都是 default.

若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定 -->

<mvc:default-servlet-handler />

状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State

Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资

源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

综述

综合上面的解释,我们总结一下什么是RESTful架构:

(1)每一个URI代表一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

误区

RESTful架构有一些典型的设计误区。

最常见的一种设计错误,就是URI包含动词。因为"资源"表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。

举例来说,某个URI是/posts/show/1,其中show是动词,这个URI就设计错了,正确的写法应该是/posts/1,然后用GET方法表示show。

如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。比如网上汇款,从账户1向账户2汇款500元,错误的URI是:

POST /accounts/1/transfer/500/to/2

正确的写法是把动词transfer改成名词transaction,资源不能是动词,但是可以是一种服务:

POST /transaction HTTP/1.1

Host: 127.0.0.1

from=1&to=2&amount=500.00

另一个设计误区,就是在URI中加入版本号:

http://www.example.com/app/1.0/foo

http://www.example.com/app/1.1/foo

http://www.example.com/app/2.0/foo

因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个URI。版本号可以在HTTP请求头信息的Accept字段中进行区分(参见Versioning REST Services):

Accept: vnd.example-com.foo+json; version=1.0

Accept: vnd.example-com.foo+json; version=1.1

Accept: vnd.example-com.foo+json; version=2.0

17.4.10.7.10 拦截器

10.1 拦截器定义

package org.hxweb.web.ssm.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

/**

* @see 测试拦截器1

* @author Administrator

*

*/

public class HandlerInterceptor1 implements HandlerInterceptor{

/*

* (non-Javadoc)

* @see 进入Handler之前执行

* 应用场景:身份验证,身份授权(比如:用户登录、权限验证等)

* 比如身份认证,如果身份认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行,否则放行。

*/

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

// return false表示拦截,不再向下执行

// return true表示放行。

return false;

}

/*

* (non-Javadoc)

* @see 进入Handler之后,返回ModelAndView之前执行

* 应用场景从modelAndView出发:将公用的模型数据(比如菜单导航等)传到视图,也可以在这里指定统一视图

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// TODO Auto-generated method stub


}

/*

* (non-Javadoc)

* @see 执行Handler完成之后执行

* 应用场景:统一异常处理、统一日志处理

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

// TODO Auto-generated method stub

}

}

10.2 拦截器配置

10.2.1 针对HandlerMapping的拦截设置(不常用,不推荐)

springmvc拦截器是针对HandlerMapping进行拦截设置:如果在某个 HandlerMapping 中配置拦截,经过该 HandlerMapping 映射成功的 Handler 最终使用 该 拦截器。

10.2.2 类似全局拦截器配置(常用,推荐)

springmvc配置类似全局拦截器,springmvc框架将配置的类似全局拦截器注入到每个 HandlerMapping 中。

<!--拦截器 -->

<mvc:interceptors>

<!--多个拦截器,顺序执行 -->

<!-- 登陆认证拦截器 -->

<mvc:interceptor>

<mvc:mapping path="/**" />

<bean class="org.hxweb.ssm.interceptor.LoginInterceptor"></bean>

</mvc:interceptor>

<mvc:interceptor>

<!-- /** 表示所有url包括子url路径 -->

<mvc:mapping path="/**" />

<bean class="org.hxweb.ssm.interceptor.HandlerInterceptor1"></bean>

</mvc:interceptor>

<mvc:interceptor>

<mvc:mapping path="/**" />

<bean class="org.hxweb.ssm.interceptor.HandlerInterceptor2"></bean>

</mvc:interceptor>

</mvc:interceptors>

10.3 拦截器的测试

10.3.1 测试需求

测试多个拦截器各自方法执行时机。

10.3.2 定义三个对应的拦截器

10.3.2.1 HandlerInterceptor1:

package org.hxweb.web.ssm.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

/**

* @see 测试拦截器1

* @author Administrator

*

*/

public class HandlerInterceptor1 implements HandlerInterceptor{

/*

* (non-Javadoc)

* @see 进入Handler之前执行

* 应用场景:身份验证,身份授权(比如:用户登录、权限验证等)

* 比如身份认证,如果身份认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行,否则放行。

*/

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

System.out.println("HandlerInterceptor1...preHandle");


// return false表示拦截,不再向下执行

// return true表示放行。

return false;

}

/*

* (non-Javadoc)

* @see 进入Handler之后,返回ModelAndView之前执行

* 应用场景从modelAndView出发:将公用的模型数据(比如菜单导航等)传到视图,也可以在这里指定统一视图

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// TODO Auto-generated method stub

System.out.println("HandlerInterceptor1...postHandle");


}

/*

* (non-Javadoc)

* @see 执行Handler完成之后执行

* 应用场景:统一异常处理、统一日志处理

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

// TODO Auto-generated method stub

System.out.println("HandlerInterceptor1...afterCompletion");

}

}

10.3.2.2 HandlerInterceptor2:

package org.hxweb.web.ssm.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

/**

* @see 测试拦截器2

* @author Administrator

*

*/

public class HandlerInterceptor2 implements HandlerInterceptor{

/*

* (non-Javadoc)

* @see 进入Handler之前执行

* 应用场景:身份验证,身份授权(比如:用户登录、权限验证等)

* 比如身份认证,如果身份认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行,否则放行。

*/

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

System.out.println("HandlerInterceptor2...preHandle");

// return false表示拦截,不再向下执行

// return true表示放行。

return false;

}

/*

* (non-Javadoc)

* @see 进入Handler之后,返回ModelAndView之前执行

* 应用场景从modelAndView出发:将公用的模型数据(比如菜单导航等)传到视图,也可以在这里指定统一视图

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// TODO Auto-generated method stub


System.out.println("HandlerInterceptor2...postHandle");

}

/*

* (non-Javadoc)

* @see 执行Handler完成之后执行

* 应用场景:统一异常处理、统一日志处理

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

// TODO Auto-generated method stub

System.out.println("HandlerInterceptor2...afterCompletion");

}

}

10.3.2.3 LoginInterceptor:

package org.hxweb.web.ssm.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

/**

* @see 用户登录拦截器测试

* @author Administrator

*

*/

public class LoginInterceptor implements HandlerInterceptor{

/*

* (non-Javadoc)

* @see 进入Handler之前执行

* 应用场景:身份验证,身份授权(比如:用户登录、权限验证等)

* 比如身份认证,如果身份认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行,否则放行。

*/

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

//获取请求的url

String url = request.getRequestURI();

//判断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("/WEB-INF/jsp/login.jsp").forward(request, response);

// return false表示拦截,不再向下执行

// return true表示放行。

return false;

}

/*

* (non-Javadoc)

* @see 进入Handler之后,返回ModelAndView之前执行

* 应用场景从modelAndView出发:将公用的模型数据(比如菜单导航等)传到视图,也可以在这里指定统一视图

*/

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

// TODO Auto-generated method stub

System.out.println("LoginInterceptor...postHandle");

}

/*

* (non-Javadoc)

* @see 执行Handler完成之后执行

* 应用场景:统一异常处理、统一日志处理

*/

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

throws Exception {

// TODO Auto-generated method stub

System.out.println("LoginInterceptor...afterCompletion");

}

}

10.3.3 测试结果:

10.3.3.1 拦截器1和拦截器2都放行

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle

HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion

HandlerInterceptor1...afterCompletion

总结:

preHandle方法按照拦截器配置顺序执行。

postHandle和afterCompletion按照拦截器配置顺序的逆向顺序执行。

10.3.3.2 拦截器1放行和拦截器2不放行

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor1...afterCompletion

总结:

拦截器1的preHandle方法放行,拦截器2的preHandle方法才能执行。

拦截器2的preHandle方法不放行,拦截器2的postHandle和afterCompletion方法都不执行。

只要有一个拦截器的preHandle方法不放行,拦截器的postHandle方法都不执行。

注意:统一日志处理拦截器,日志拦截器必须配置在第一的位置,且日志拦截器的preHandle方法必须放行。

10.3.3.3 拦截器1不放行、拦截器2也不放行

HandlerInterceptor1...preHandle

总结:

拦截器1的preHandle方法不放行,拦截器1的postHandle和afterCompletion方法都不执行。

拦截器1的preHandle方法不放行,拦截器2也不会执行。

10.3.4 小结

根据测试结果,对拦截器应用。

比如:统一日志处理拦截器,需要 该 拦截器的preHandle方法必须放行,且必须将它放在拦截器链接第一个的位置。

比如:登录认证拦截器,它必须放在拦截器链接中统一日志处理拦截器后的第一个的位置。

比如:权限校验拦截器,它必须放在拦截器链接中登录认证拦截器后的第一个的位置(登录认证通过后才会进行权限校验)。

10.3.5 拦截器应用(实现登录认证):

10.3.5.1 需求

1.用户请求url

2.拦截器进行拦截校验

如果请求的url是公开地址(不要用登录即可访问的url),就放行。

如果用户session不存在,跳转到登录页面。

如果用户session存在,继续操作。

10.3.5.2 登录 controller 方法

10.3.5.3 登录认证拦截器实现

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码