# springmvc基础(基于xml配置) **开发环境:IDEA** **spring版本:5.1.3.RELEASE** **本部分内容官方文档链接:[Web Servlet](https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/web.html#spring-web)** ## 一、搭建hello spring工程 ### 1.1 项目搭建 1.新建maven web工程,并引入相应的依赖 ```xml 5.1.3.RELEASE org.springframework spring-context ${spring-base-version} org.springframework spring-beans ${spring-base-version} org.springframework spring-core ${spring-base-version} org.springframework spring-web ${spring-base-version} org.springframework spring-webmvc ${spring-base-version} javax.servlet javax.servlet-api 4.0.1 provided ``` 2.配置web.xml ```xml springMvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springApplication.xml 1 springMvc / ``` 3.在resources下新建springApplication.xml文件,文件内容如下: ```xml ``` 4.在src 下新建controller用于测试 ```java package com.heibaiying.controller; import com.heibaiying.exception.NoAuthException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @author : heibaiying * @description : hello spring */ @Controller @RequestMapping("mvc") public class HelloController { @RequestMapping("hello") private String hello() { return "hello"; } } ``` 5.在WEB-INF 下新建jsp文件夹,新建hello.jsp 文件 ```jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> Title Hello Spring MVC! ``` 6.启动tomcat服务,访问localhost:8080/mvc/hello ### 1.2 相关配置讲解 **1.\** 在web.xml配置中,我们将DispatcherServlet的拦截路径设置为“\”,则spring会捕获所有web请求,包括对静态资源的请求,为了正确处理对静态资源的请求,spring提供了两种解决方案: - 配置\ : 配置后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。 - 配置\ :指定静态资源的位置和路径映射: ```xml ``` **2.\** 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,用以支持@Controllers分发请求。并提供了数据绑定、参数转换、json转换等功能,所以必须加上这个配置。 ## 二、配置自定义拦截器 1.创建自定义拦截器,实现接口HandlerInterceptor(这里我们创建两个拦截器,用于测试拦截器方法的执行顺序) ```java package com.heibaiying.interceptors; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author : heibaiying * @description : spring5 中 preHandle,postHandle,afterCompletion 在接口中被声明为默认方法 */ public class MyFirstInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("进入第一个拦截器preHandle"); return true; } // 需要注意的是,如果对应的程序报错,不一定会进入这个方法 但一定会进入afterCompletion这个方法 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("进入第一个拦截器postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("进入第一个拦截器afterCompletion"); } } ``` ```java package com.heibaiying.interceptors; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author : heibaiying * @description : spring5 中 preHandle,postHandle,afterCompletion 在接口中被声明为默认方法 */ public class MySecondInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("进入第二个拦截器preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("进入第二个拦截器postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("进入第二个拦截器afterCompletion"); } } ``` 2.在springApplication.xml中注册自定义拦截器 ```xml ``` 3.关于多个拦截器方法执行顺序的说明 拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法和afterCompletion方法却会后执行。 ## 三、全局异常处理 1.定义自定义异常 ```java package com.heibaiying.exception; /** * @author : heibaiying * @description : 自定义无权限异常 */ public class NoAuthException extends RuntimeException { public NoAuthException() { super(); } public NoAuthException(String message) { super(message); } public NoAuthException(String message, Throwable cause) { super(message, cause); } public NoAuthException(Throwable cause) { super(cause); } } ``` 2.实现自定义异常处理器 ```java package com.heibaiying.exception; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author : heibaiying * @description : 无权限异常处理机制 */ public class NoAuthExceptionResolver implements HandlerExceptionResolver { public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (ex instanceof NoAuthException && !isAjax(request)) { return new ModelAndView("NoAuthPage"); } return new ModelAndView(); } // 判断是否是Ajax请求 private boolean isAjax(HttpServletRequest request) { return "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With")); } } ``` 3.在springApplication.xml注册自定义异常处理器 ```xml ``` 4.定义测试controller,抛出自定义异常 ```java @Controller @RequestMapping("mvc") public class HelloController { @RequestMapping("hello") private String hello() { return "hello"; } @RequestMapping("auth") private void auth() { throw new NoAuthException("没有对应的访问权限!"); } } ``` 注:调用这个controller时,同时也可以验证在拦截器部分提到的:如果对应的程序报错,拦截器不一定会进入postHandle这个方法 但一定会进入afterCompletion这个方法