SpringMVC
三层架构和 MVC
- 三层架构
- 表现层: 也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求 web 层,web 需要接收 http 请求,完成 http 响应。
- 业务层: 也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。
- 持久层: 也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层。
- MVC
- 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。
- Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
- View(视图): 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
- Controller(控制器): 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
SpringMVC 概述
- SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 表现层框架
SpringMVC的入门
需求:点击超链接发送一个请求,跳转页面
步骤:
创建maven web工程,导入依赖(ioc,web,webmvc,servletapi,jspapi)
<!-- 版本锁定 --> <properties> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies>
配置核心的控制器(配置DispatcherServlet)
在web.xml配置文件 <!-- SpringMVC的核心控制器 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 配置servlet启动时加载对象 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
编写springmvc.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置spring创建容器时要扫描的包 --> <context:component-scan base-package="com.itheima"></context:component-scan> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 配置spring开启注解mvc的支持 --> <mvc:annotation-driven></mvc:annotation-driven> </beans>
编写index.jsp和HelloController控制器类
入门案例
入门案例
/** 控制器 */
@Controller
public class HelloController {
/**
* 接收请求
*/
//请求映射
@RequestMapping(path="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
return "success"; }
}
在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
入门成功!!
启动Tomcat服务器,进行测试
执行过程分析
1. 入门案例的执行流程
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会**加载springmvc.xml配置文件 **
- 开启了注解扫描,那么HelloController对象就会被创建
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 **找到执行的具体方法 **
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下**查找指定名称的JSP文件 **
- Tomcat服务器渲染页面,做出响应
原理(运行机制)
客户端发送请求到DispacherServlet(分发器)
由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller
Controller调用业务逻辑处理后,返回ModelAndView
DispacherServlet查询视图解析器,找到ModelAndView指定的视图
视图负责将结果显示到客户端
2. 入门案例中涉及的组件
DispatcherServlet:前端控制器
- 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
- 负责根据用户请求找到 sayhello 即处理器
Handler:处理器 (方法)
- 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。
HandlAdapter:处理器适配器
- 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,不同的处理器都可以通过适配器执行
View Resolver:视图解析器 (根据方法执行的结果找到对应的页面)
- View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
View:视图
< mvc:annotation-driven>说明
- 在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
- 开启mvc注解支持代表自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ),同时集成了json转换工具
- 明确: 我们只需要编写处理具体业务的控制器(方法)以及视图(页面)。
请求参数的绑定
请求参数的绑定说明
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
基本数据类型和字符串类型
- 提交表单的name和参数的名称是相同的
- 区分大小写
实体类型(JavaBean)
- 提交表单的name和JavaBean中的属性名称需要一致,方法参数写实体对象,可自动封装
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
给数组属性数据封装
- 提交表单的name和方法参数的数组对象名称需要一致
给集合属性数据封装
创建Vo对象,属性包含实体类集合,方法参数是vo,表单如下
- JSP页面编写方式:list[0].实体类属性
- Map:map[‘one’].属性
请求参数中文乱码的解决
在web.xml中配置Spring提供的过滤器类
<!-- 配置过滤器,解决中文乱码的问题 --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filterclass> <!-- 指定字符集 --> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
自定义类型转换器
接收到的数据都是字符串类型,springMVC里面有配置好的类型转换器进行转换为其他类型,有特殊需求可以自己加类型转换器
步骤:
写一个自定义类型转换器的类,实现Converter的接口
/** 把字符串转换成日期的转换器 */ public class StringToDateConverter implements Converter<String, Date>{ /** * 进行类型转换的方法 */ public Date convert(String source) { // 判断 if(source == null) { throw new RuntimeException("参数不能为空"); } try { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); // 字符串转换日期 Date date = df.parse(source); return date; } catch (Exception e) { throw new RuntimeException("类型转换错误"); } } }
注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 注册自定义类型转换器 --> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <!--注入自定义的转换器--> <property name="converters"> <set> <bean class="cn.itcast.utils.StringToDateConverter"/> </set> </property> </bean> <!-- 开启Spring对MVC注解的支持 --> <mvc:annotation-driven conversion-service="conversionService"/>
在控制器中使用原生的ServletAPI对象
- 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象
常用的注解
RequestMapping 注解
- 作用: 用于建立请求 URL 和处理请求方法之间的对应关系
- 出现位置:
- 类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 它出现的目的是为了使我们的 URL 可以按照模块化管理
- 方法上: 请求 URL 的第二级访问目录。
- 属性:
- value:用于指定请求的 URL。它和 path 属性的作用是一样的。
- method:用于指定请求的方式。 post/get
- params:用于指定限制请求参数的条件。要求请求参数的 key 和 value 必须和 配置的一模一样。
- 例如:params = {“accountName”} params = {“accountName=hehe”}
- headers:用于指定限制请求消息头的条件。
@WebServlet、@WebFilter、@Weblistener
- 作用:加在类上,表示该类是一个三大组件
- 属性
- value:url路径 如: /hello
RequestParam注解 (解决参数名称和传递参数名称不一致)
- 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
- 属性
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认值是true,必须提供
<input type="text" name="username">
public String sayHello(@RequestParam(value="username",required=false)String name) {
RequestBody注解
- 作用:用于获取请求体的内容(注意:get方法不可以)
- 属性
- required:是否必须有请求体,默认值是true
public String sayHello(@RequestBody String body) {
ResponseBody注解
- 作用:用在方法上,不进行页面跳转,直接回写数据
RequestHeader注解
- 作用:获取指定请求头的值
- 属性
- value:请求头的名称
@RequestMapping(path="/hello")
public String sayHello(@RequestHeader(value="Accept") String header) {
CookieValue注解
- 作用:用于获取指定cookie的名称的值
- 属性
- value:cookie的名称
@RequestMapping(path="/hello")
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
PathVariable注解
- 作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
- 属性
- value:指定url中的占位符名称
- Restful风格的URL
- 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
- restful风格的URL优点 1. 结构清晰 2. 符合标准 3. 易于理解 4. 扩展方便
@RequestMapping(path="/hello/{id}")
public String sayHello(@PathVariable(value="id") String id) {
ModelAttribute注解
作用
出现在方法上:表示当前方法会在控制器方法执行前先执行。
出现在参数上:获取指定的数据给参数赋值。
应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
运行流程:
- 执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放到model/map当中
- SpringMVC从model/map取出对象,把表单的请求参数给该对象的对应属性
- springMVC把上述对象传入目标方法的参数
注意:在@ModelAttribute修饰的方法中,放入到Map时的键和目标方法的参数类型的第一个字符小写的字符串一致
修饰方法有返回值
/**
* 作用在方法,先执行
* 有返回值,方法控制器获取的值就有修饰方法返回的值
*/
@ModelAttribute
public User showUser(String name) {
System.out.println("showUser执行了...");
// 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
return user; }
/**
* 修改用户的方法
*/
@RequestMapping(path="/updateUser")
public String updateUser(User user) {
System.out.println(user);
return "success"; }
修饰方法无返回值
/**
* 作用在方法,先执行
* 无返回值会将值存到map中,方法控制器使用注解会从map中取
*/
@ModelAttribute
public void showUser(String name,Map<String, User> map) {
System.out.println("showUser执行了...");
// 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
map.put("abc", user); }
/**
* 修改用户的方法
*/
@RequestMapping(path="/updateUser")
public String updateUser(@ModelAttribute(value="abc") User user) { System.out.println(user);
return "success"; }
SessionAttributes注解 (存到session域中)
- 作用:用于多次执行控制器方法间的参数共享
- 属性
- value:指定存入属性的名称
- types:指定类型,存入属性
@Controller
@RequestMapping(path="/user")
@SessionAttributes(value= {"username","password","age"},types={String.class})
// 把数据存入到session域对象中
public class HelloController {
/**
* 向session中存入值
*/
@RequestMapping(path="/save")
public String save(Model model) {
//将数据存储到model中,底层实际上是存储到了request域中
System.out.println("向session域中保存数据");
model.addAttribute("username", "root");
model.addAttribute("password", "123");
model.addAttribute("age", 20);
User user = new User("tom",11);
model.addAttribute("user",user);
return "success"; }
/**
* 从session中获取值
*/
@RequestMapping(path="/find")
public String find(ModelMap modelMap) {
//ModelMap是model的实现类,能够获取存储在model中的值
String username = (String) modelMap.get("username");
String password = (String) modelMap.get("password");
Integer age = (Integer) modelMap.get("age");
System.out.println(username + " : "+password +" : "+age);
return "success"; }
/**
* 清除值
*/
@RequestMapping(path="/delete")
public String delete(SessionStatus status) {
//SessionStatus会话状态,将会话完成,即删除session域中的值,
status.setComplete();
return "success"; }
}
响应数据和结果视图
Model,ModelAndView
底层实际上是存储到了request域中
Map
map.put()方法也会存入到request域中
返回值分类
返回字符串:根据视图解析器为物理视图的地址。
返回值是void :
- 可使用 request 转向页面
- 也可以通过 response 页面重定向
- 也可以通过 response 指定响应结果
@RequestMapping(value="/initAdd") public void initAdd(HttpServletRequest request,HttpServletResponse response) throws Exception { System.out.println("请求转发或者重定向"); // 请求转发 request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request, response); // 重定向 response.sendRedirect(request.getContextPath()+"/add2.jsp"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // 直接响应数据 response.getWriter().print("你好"); return; }
返回值是ModelAndView对象 :类似返回字符串,调用视图解析器跳转到具体的JSP视图
/** * 返回ModelAndView对象 * 可以传入视图的名称(即跳转的页面),还可以传入对象。 */ @RequestMapping(value="/findAll") public ModelAndView findAll() throws Exception { ModelAndView mv = new ModelAndView(); // 跳转到list.jsp的页面 mv.setViewName("list"); // 模拟从数据库中查询所有的用户信息 List<User> users = new ArrayList<>(); User user1 = new User(); user1.setUsername("张三"); user1.setPassword("123"); // 添加对象 mv.addObject("users", users); return mv; } 也可以ModelAndView作为参数,SpringMVC会自动创建 public ModelAndView findAll(ModelAndView modelAndView){ modelAndView.setViewName("list"); }
返回值是字符串,参数是model:用于携带数据
@RequestMapping("/quick4")
public String sayHello4(Model model){
System.out.println("Hello SpringMVC!!");
model.addAttribute("username","zhaowu");
return "success";
}
- 使用@ResponseBody回写字符串
@RequestMapping("/quick5")
@ResponseBody
public String sayHello4(){
return "hello success";
}
SpringMVC框架提供的转发和重定向
forward请求转发
@RequestMapping("/delete") public String delete() throws Exception { System.out.println("delete方法执行了..."); return "forward:/WEB-INF/pages/success.jsp"; }
redirect重定向
@RequestMapping("/count") public String count() throws Exception { System.out.println("count方法执行了..."); //不需要写项目名request.getContextPath(),底层已经写好了 return "redirect:/add.jsp"; }
ResponseBody响应json数据
第一种方式:开启mvc注解驱动,导入jar包,使用@ResponseBody,直接返回对象,回写json数据
@RequestMapping("/quick") @ResponseBody public User count() throws Exception { User user = new User(); user.setName("zhangsan"); return user; }
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,
<!-- 设置静态资源不过滤 1. location元素表示webapp目录下的包下的所有文件 2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b --> <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 --> <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 --> <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript --> 也可以使用,效果一样 <mvc:default-servlet-handler></mvc:default-servlet-handler>
使用@RequestBody获取请求体数据
//使用Ajax需要提前导入jquery的js文件 // 页面加载 $(function(){ // 绑定点击事件 $("#btn").click(function(){ $.ajax({ url:"user/testJson", contentType:"application/json;charset=UTF-8", data:'{"addressName":"aa","addressNum":100}', dataType:"json", type:"post", success:function(data){ alert(data); alert(data.addressName); } }); }); }); /* 获取请求体数据 */ @RequestMapping("/testJson") public void testJson(@RequestBody String body) { System.out.println(body); }
json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
使用@RequestBody注解把json的字符串自动转换成JavaBean的对象
@RequestMapping("/testJson") public void testJson(@RequestBody Address address) { System.out.println(address); }
使用@ResponseBody注解把JavaBean对象自动转换成json字符串,直接响应 ,前提开启了mvc注解驱动
//ajax的回调函数 success:function(data){ alert(data); alert(data.addressName); } @RequestMapping("/testJson") public @ResponseBody Address testJson(@RequestBody Address address) { System.out.println(address); address.setAddressName("上海"); return address; }
SpringMVC实现文件上传
SpringMVC传统方式文件上传(省去了解析request域获取上传文件项的过程,直接获得文件项)
导入文件上传的jar包
<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>
编写文件上传的JSP页面
- SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同
文件上传
配置文件解析器对象
<!-- 在springMVC.xml中配置文件解析器对象,要求id名称必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--配置文件上传大小为10M--> <property name="maxUploadSize" value="10485760"/> </bean>
编写文件上传的方法
/** * SpringMVC方式的文件上传 */ @RequestMapping(value="/fileupload2") public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception { System.out.println("SpringMVC方式的文件上传..."); // 先获取到要上传的文件目录 String path = request.getSession().getServletContext().getRealPath("/uploads"); // 创建File对象,一会向该路径下上传文件 File file = new File(path); // 判断路径是否存在,如果不存在,创建该路径 if(!file.exists()) { file.mkdirs(); } // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); //创建随机序列号 String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称唯一化 filename = uuid+"_"+filename; // 上传文件 upload.transferTo(new File(file,filename)); return "success"; }
SpringMVC跨服务器方式文件上传
bug1:403错误
原因:tomcat权限不够
改为:修改tomcat的web.xml
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
位置:<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
bug2:409错误
原因:没有该文件夹
改为:在部署的目录中创建该文件夹
E:\Java\springMVC_day02_image\target\springMVC_day02_image\uploads
搭建图片服务器
导入开发需要的jar包
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.18.1</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency>
编写文件上传的JSP页面
编写控制器
@RequestMapping(value="/fileupload3") public String fileupload3(MultipartFile upload) throws Exception { System.out.println("SpringMVC跨服务器方式的文件上传..."); // 定义图片服务器的请求路径 String path = "http://localhost:9090/day02_springmvc5_02image/uploads/"; // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称唯一化 filename = uuid+"_"+filename; // 向图片服务器上传文件 // 创建客户端对象 Client client = Client.create(); // 连接图片服务器 WebResource webResource = client.resource(path+filename); // 上传文件 webResource.put(upload.getBytes()); return "success"; }
SpringMVC的异常处理
异常处理思路 :Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理
前提:程序的异常必须抓并抛自己定义的异常
步骤(简单异常处理器):
遇到异常,只能跳转到指定的页面。不能增加其他逻辑
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="error"></property><!--没有匹配到的异常跳转到这个,error,因为配置了视图解析器,所以直接输入error即可跳转error.jsp--> <property name="exceptionMappings"> <map> <entry key="java.lang.ClassCastException" value="error2"></entry> <entry key="com.jm.MyException" value="error3"></entry> </map> </property> </bean>
步骤(自定义异常):
自定义异常类
//继承Exception类 public class SysException extends Exception{ // 异常提示信息 private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public SysException(String message) { this.message = message; } }
自定义异常处理器
/** * 异常处理器 :实现HandlerExceptionResolver */ public class SysExceptionResolver implements HandlerExceptionResolver{ /** * 跳转到具体的错误页面的方法 ex:程序执行时抛出的异常(前提:程序的异常必须抓并抛自己定义的异常) */ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) { ex.printStackTrace(); SysException e = null; // 获取到异常对象 if(ex instanceof SysException) { //是自己定义的异常类对象 e = (SysException) ex; }else { //不是自己定义的异常 e = new SysException("请联系管理员"); } ModelAndView mv = new ModelAndView(); // 存入错误的提示信息 mv.addObject("message", e.getMessage()); // 跳转的Jsp页面 mv.setViewName("error"); return mv; } }
配置异常处理器
<!-- 配置异常处理器 正常配bean就行--> <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
SpringMVC框架中的拦截器
概述:用于对处理器进行预处理和后处理的技术
拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
想要自定义拦截器,需要实现HandlerInterceptor接口
步骤:
创建拦截器类,实现接口(接口内部已经实现了方法,需要自己重载)
public class MyInterceptor1 implements HandlerInterceptor{ /** * controller方法执行前,进行拦截的方法 * return true放行 * return false拦截 * 可以使用转发或者重定向直接跳转到指定的页面。 */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { System.out.println("拦截器执行了..."); return true; } }
在springmvc.xml中配置拦截器类
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 哪些方法进行拦截 --> <mvc:mapping path="/user/*"/> <!-- 哪些方法不进行拦截 <mvc:exclude-mapping path=""/> --> <!-- 注册拦截器对象 --> <bean class="cn.itcast.demo1.MyInterceptor1"/> </mvc:interceptor> <!--第二个拦截器也是要全部配置mvc:interceptor,且拦截顺序按配置的顺序执行,12方法21--> </mvc:interceptors>
HandlerInterceptor接口中的方法
preHandle方法:控制器方法执行前拦截
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
postHandle方法是controller方法执行后拦截
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示,但输出控制台的仍然会执行。
- 参数ModelAndView可以将参数修改
afterCompletion方法是在页面加载后执行
- request或者response不能再跳转页面了