SpringMVC
-
MVC开发模式:人为的将Web项目分成三层,即Model数据模型层,Controller控制器层,View视图层,分层开发的好处是可以让项目各个组件之间解耦合,便于项目的维护
-
SpringMVC是Spring家族的一款专注于解决控制器层问题的框架产品,相比于Struts2做控制器,SpringMVC的开发效率更高,与Spring框架的集成更自然,SpringMVC天生倡导注解式开发
-
控制器层解决的问题
- 接受客户端请求参数
- 进行数据类型的转换
- 调用业务功能
- 流程跳转
- 使用作用域传递和管理数据
-
Struts2和StringMVC做控制器的不同
Struts2 SpringMVC 入口不同 监听器StrutsPrepareAndExecuFilter Servlet的DispatcherServlet 返回值类型 必须为String,代表一个跳转视图 多种返回值类型,还可以书写一个跳转的视图 接收参数 成员变量接收参数 通过方法入参接收请求参数 -
SpringMVC做控制器
@Controller @RequestMapping("") //相当于namespace class XXXController{ @RequestMapping("/") //相当于actionName public String ma(方法接收请求参数){ //调用service //返回值完成视图跳转 return "index"; //index.jsp 也可以直接书写跳转视图 } }
-
SpringMVC开发控制器
-
引入依赖:在Spring之前依赖基础上加上spring-webmvc
-
引入配置文件:SpringMVC的配置文件,就是Spring的配置文件基础上引入mvc的文件头(xsd);文件名没有要求,放置位置也没有强制要求
xmlns:mvc="http://www.springframework.org/schema/mvc" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
-
初始化配置:配置一个核心入口的Servlet
-
可以手动在web.xml中配置指定的servlet在服务器启动的时候初始化,提高效率
-
一个Servlet实现类在服务器中只会创建一个对象,当请求一个Servlet的时候,服务器会检查一下看看当前内存中会否有当前请求的Servlet,如果有直接使用,没有则创建新的
//web.xml <!--配置核心入口的Servlet--> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--指定springMVC配置文件的位置,param-name为定值,value为文件位置--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <!--启动服务器创建入口Servlet 非负数,启动服务器即创建,多个servlet在启动服务器创建时可以通过设置不同的整数值设置创建的优先级,值越小越先创建--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <!--url-pattern配置为*.do:来自客户端所有的以.do结尾的请求都会先经过DispatcherServlet进行处理--> <url-pattern>*.do</url-pattern> </servlet-mapping>
-
编写控制器类
@Controller //指定当前类是一个控制器类 @RequestMapping("/hello") //相当于配置一个namespace public class HelloController { // 编写处理请求的方法 //http://localhost:8989/项目名/hello/helloWorld.do @RequestMapping("/helloWorld.do") public String helloWorld() { System.out.println("hello world"); return "index"; //index.jsp 如果仅仅以一个字符串而不是视图的路径方式跳转,需要配合视图解析器使用 } }
-
编写spring-mvc.xml
<!--开启mvc注解驱动--> <mvc:annotation-driven /> <!--开启Spring的注解扫描--> <context:component-scan base-package="com.mo.controller"></context:component-scan> <!--配置一个SpringMVC提供的视图解析器 nternalResourceViewResolver:内部资源视图解析器,主要用于匹配和解析控制方法执行完毕跳转的 视图解析器由SpringMVC调用,所以id必须是viewResolver--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver"> <!--匹配成 / index 前缀--> <property name="prefix" value="/"></property> <!--匹配成 / index .jsp 后缀--> <property name="suffix" value=".jsp"></property> </bean>
-
-
@RequestMapping注解说明
-
用在类上相当于namespace的含义,可以将不同类型的控制器进行分类管理
-
用在类上相当于namespace,用在方法上相当于actionName
-
请求方式的限定
@RequestMapping( value = "请求路径映射", method = { RequestMethod.post / RequestMethod.get }; //可以约束当前控制器只能处理什么类型的请求,可以两个都写,用逗号隔开,可以同时处理get和post;与什么都不写的区别是,什么都不写是能处理所有的请求 )
-
-
获取Servlet原生API
-
方法入参注入
@RequestMapping("/test0.do") public String test0(HttpServletRequest request){ // 获取请求参数 String name = request.getParameter("name"); System.out.println("test0"+name); // 向request作用域存数据 request.setAttribute("name",name); return "success"; }
-
成员变量自动注入
public class GetServletAPI { @Autowired private HttpServletRequest request; }
-
常用API:SpringMVC没有提供ServletContext方法入参的获取,需要手动获取
@RequestMapping("/ma.do") public String ma(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException { //使用request获取参数 String name = request.getParameter("name"); System.out.println(name); PrintWriter out = response.getWriter(); System.out.println(out); // 向session作用域存入数据 session.setAttribute("user","mo"); //SpringMVC没有提供ServletContext方法入参的获取,需要手动获取 ServletContext servletContext = session.getServletContext(); servletContext.setAttribute("nickName","hang"); //跳转 return "index"; }
-
-
SpringMVC的控制器类是单例的,开发中不允许定义保存数据状态的成员变量
SpringMVC中跳转控制
-
SpringMVC是通过控制器方法到返回值控制跳转
-
controller到jsp跳转
-
请求转发:forward:/路径/xxx.jsp(相对于项目的根目录开始)
@Controller @RequestMapping("/jump") public class JumpController { @RequestMapping("/test0.do") public String test0(){ System.out.println("test0 controller"); //转发跳转到一个jsp return "success"; } } @Controller @RequestMapping("/jump") public class JumpController { @RequestMapping("/test0.do") public String test0(){ System.out.println("test0 controller"); //转发跳转到一个jsp,不需要匹配视图解析器 return "forward:/success.jsp"; } }
-
请求重定向:redirect:/路径/xxx.jsp(相对于项目的根目录开始)
@Controller @RequestMapping("/jump") public class JumpController { @RequestMapping("/test0.do") public String test0(){ System.out.println("test0 controller"); // 重定向跳转到jsp return "redirect:/success.jsp"; } }
-
-
contorller到controller跳转
-
请求转发:forward:/包名/xxx.do
@RequestMapping("/test1.do") public String test1(){ System.out.println("test1 controller"); // 请求转发到另一个控制器 return "forward:/jump/test2.do"; //同包跳转也必须加上包名 }
-
请求重定向:redirect:/包名/xxx.do
@RequestMapping("/test1.do") public String test1(){ System.out.println("test1 controller"); // 请求重定向到另一个控制器 return "redirect:/jump/test2.do"; //同包跳转也必须加上包名 }
-
SpringMVC中的收参机制
-
通过控制器方法的入参形式接收请求参数,基本的要求是请求参数的key与方法入参的变量名一致(八种基本数据类型和字符串)
-
八种基本数据类型和字符串
-
关于接收的请求参数:
- 基本数据类型发送了对应的key,但没有赋值时为null;如果没有发送指定的请求参数,那么不管是基本数据类型还是字符串都是null;
- 发送了对应的key的请求但是没给值为空字符串
<form action="${pageContext.request.contextPath }/param/test0.do" method="post"> username:<input type="text" name="username"/><br /> password:<input type="password" name="password"/><br/> age:<input type="text" name="age"><br /> <input type="submit" value="regist" /> </form> @Controller @RequestMapping("/param") public class ParamController { //八种基本数据类型和字符串类型 @RequestMapping("/test0.do") //当jsp页面参数name不同时,用注解RequestParam赋值 public String test0(@RequestParam("username")String name, String password,Integer age) { System.out.println("name:" + name); System.out.println("password:" + password); System.out.println("age:" + age ); return "redirect:/success.jsp"; } }
-
@RequestParam注解
@RequestParam( value = "key", //请求时参数name的值 required = "true", //代表请求时参数中必须有一个参数的name为key,false时可以不传值,默认为true,此时必须传递参数name,不传参则报错 defaultValue = "mo" //默认值,当传递的请求参数为空,没有赋值或根本就没有传递对应的请求参数时,取默认值,即使required=true时,没有发送也不会报错;传值时取传过来的 )
-
-
日期类型默认接收的格式:yyyy/MM/dd
-
自定义接收日期的格式:@DateTimeFormat(pattern = “yyyy-MM-dd”)
//自定义接收日期的格式 //底层还是使用的new SimpleDateFormat("yyyy-MM-dd") @RequestMapping("/test1.do") public String test1(@DateTimeFormat(pattern = "yyyy-MM-dd")Date birthday){ System.out.println(birthday); return "redirect:/success.jsp"; }
-
-
自定义对象类型参数
public class User implements Serializable { private String username; private String password; @DateTimeFormat(pattern = "yyyy-MM-dd") //自定义对象类型日期格式需要在实体类中加注解指定接收格式,也可以使用默认yyyy/MM/dd private Date birthday; private List<String> hobby; //与前台jsp对应相同即可 } //name对应实体类属性 <form action="${pageContext.request.contextPath }/param/test2.do" method="post"> username:<input type="text" name="username"/><br /> password:<input type="password" name="password"/><br/> birthday:<input type="text" name="birthday"/><br /> hobby:<input type="checkbox" value="eat" name="hobby">吃饭 <input type="checkbox" value="sleep" name="hobby">睡觉 <input type="checkbox" value="hitBee" name="hobby"/>打豆豆 <input type="submit" value="regist" /> </form> //自定义对象类型参数接收 @RequestMapping("/test2.do") public String test2(User user,String username) { System.out.println("user:\t"+user); System.out.println("username:\t"+username); //此时都给值 return "redirect:/success.jsp"; }
-
List集合类型
-
泛型为八种基本数据类型和字符串
<form action="${pageContext.request.contextPath }/param/test3.do" method="post"> hobby: <input type="checkbox" value="eat" name="hobby">吃饭 <input type="checkbox" value="sleep" name="hobby">睡觉 <input type="checkbox" value="hitBee" name="hobby">打豆豆 <br> Id: <input type="checkbox" value="1" name="ids">吃饭 <input type="checkbox" value="2" name="ids">睡觉 <input type="checkbox" value="3" name="ids">打豆豆 <input type="submit" value="regist" /> </form> //接收List集合 @RequestMapping("/test3.do") public String test3(@RequestParam("hobby") List<String> strList, //需要通过指定@RequestParam注解,让SpringMVC可以初始化list @RequestParam List<Integer> ids){ System.out.println("=====字符串====="); if (strList!=null) { strList.forEach(s -> System.out.println(s)); } System.out.println("=====Integer类型====="); if (ids!=null) { ids.forEach(i -> System.out.println(i)); } return "redirect:/success.jsp"; }
-
泛型为自定义对象类型,用DTO封装为自定义对象类型来传参
-
DTO:data transfer object 数据传输对象
public class UserDTO { private List<User> users; } //通过下标给每个对象封装值 //成员变量名[index].集合泛型类型的属性名 <form action="${pageContext.request.contextPath }/param/test4.do" method="post"> 注册:<br/> username:<input type="text" name="users[0].username"> password:<input type="password" name="users[0].password"><br> <br> username:<input type="text" name="users[1].username"> password:<input type="password" name="users[1].password"><br> <input type="submit" /> </form> //接收泛型为自定义对象的List集合 @RequestMapping("/test4.do") public String test4(UserDTO userDTO) { userDTO.getUsers().forEach(user -> System.out.println(user)); return "redirect:/success.jsp"; }
-
处理POST请求提交的中文编码:使用SpringMVC中提供的编码过滤器
<!-- web.xml --> <!--配置SpringMVC的编码过滤器--> <filter> <filter-name>encode</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--配置初始化参数,指定编码格式--> <init-param> <!-- encoding为CharacterEncodingFilter中的一个参数名,不能更改 --> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encode</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
Spring+SpringMVC+mybatis整合
-
搭建开发环境
- 引入依赖
- 引入配置文件
- spring-core.xml
- spring-mvc.xml
- log4j.propertirs / jdbc.properties
- mapper.xml
- 初始化配置 - web.xml
- 指定Spring工厂初始化的核心配置文件位置
- 配置初始化Spring工厂的监听器
- 配置SpringMVC核心入口Servler:DispatcherServlet
- 配置编码过滤器
-
编码
-
spring-core.xml中的配置信息:
-
开启注解扫描,配置排除策略,暂时扫描除了控制器所在的包的其余全部
<context:component-scan base-package="com.mo.*"> <!--配置排除策略,spring核心配置文件不做Controller注解的扫描,由spring-mvc自己管理--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
-
引入小配置文件
-
创建数据源
-
创建SqlSessionFactory
-
创建DAO实现类的对象
-
开启事务注解驱动(DataSourceTransactionManager)
-
-
spring-mvc.xml中的配置信息
- 扫描控制器的注释
- 开启SpringMVC注释驱动
- 配置视图解析器
-
建表、封装实体类、编写DAO、编写Service、编写控制器
-
Spring和SpringMVC整合引发的事务失效
- spring-core.xml属于父容器,不能使用子容器的对象,和继承是一样的思想
- 管理dao对象
- 管理service对象
- 管理事务
- spring-mvc.xml属于子容器,可以使用父容器的对象
- 管理控制器对象
- 此时如果在spring-mvc.xml中有dao和service时,就不会去获取父类器的对象,导致创建一个没有事务额外功能的原始类对象,不去获取代理类对象,使事务失效
SpringMVC的数据管理机制
-
管理request作用域
-
Model(接口)机制:
-
model.addAttribute(String name,Object value);
-
model.addAllAttributes(Map<String,?> map); 将一个map中所有的键值对同时存入request作用域
@RequestMapping("/test1.do") public String test1(Model model) { //使用model存数据到request中 model.addAttribute("name", "yuan"); // 同时向model中添加多个键值对 Map<String, String> map = new HashMap<>(); map.put("k1", "mo"); map.put("k2", "yuan"); model.addAllAttributes(map); return "success"; }
-
model使用细节:重定向跳转时,model中的数据会自动拼接到地址栏传输
@RequestMapping("/ma.do") public String ma(Model model) { Integer id = 10; model.addAttribute("id", id); //重定向跳转时,model中的数据会自动拼接到地址栏传输 return "redirect:/emp/mb.do"; }
-
-
ModelMap(类,本质为Map)机制,中间有一个转存:
-
modelMap.addAttribute(String name,Object value);
-
modelMap.addAlllAttributes(Map<String,?> attributes); 将一个map中所有的键值对同时存入request作用域
@RequestMapping("/test2.do") public String test2(ModelMap modelMap) { //向request作用域中存入数据 modelMap.addAttribute("name", "hang"); // 同时向modelMap中添加多个键值对 Map<String, String> map = new HashMap<>(); map.put("k1", "mo"); map.put("k2", "yuan"); modelMap.addAllAttributes(map); return "success"; }
-
-
-
管理session作用域:常用原生的
-
@SessionAttributes:当次请求中model里面的命名属性,如果在@SessionAttributes里面指定了,那么会自动向session作用域存一份,此时reqeust作用域中也有
@Controller @RequestMapping("/scope1") @SessionAttributes(value = {"name1","name2"}) public class Scope1Controller { // 管理session作用域 @RequestMapping("/test4.do") public String test4(Model model){ // 向model中添加数据 model.addAttribute("name1", "mo"); model.addAttribute("name2", "yuan"); return "redirect:/success.jsp"; } //通过SessionAttributes与Model配合存入到session的数据,同包下的控制器方法中无法用invalidate或removeAttribute原生的清除,非同包可以使用invaludata或removeAttribute清除 @RequestMapping("/test5.do") public String test5(SessionStatus sessionStatus){ //session.removeAttribute(name) 移除session中的数据 //session.invalidate(); //销毁session //使用sessionStatus去清理通过@SessionAttributes存入的数据 sessionStatus.setComplete(); return "ok"; }
-
-
ModelAndView:可以同时管理数据和完成视图的跳转
@RequestMapping(value="/test0.do") //@SessionAttributes({"name"}) //此时指定的name也会将modelAndView中的相同命名属性存入session作用域中一份 public ModelAndView test0(){ ModelAndView mv = new ModelAndView(); //管理数据 mv.addObject("name", "mo"); //存入了request作用域 //设置跳转的视图 // mv.setViewName("success"); //与之前方法返回值类型为String时, mv.setViewName("redirect:/success.jsp"); //返回值的写法格式一致 return mv; }
- request:存的事一次请求需要的数据
- session:存的是一次会话需要的数据,通常只存储与用户相关的信息
SpringMVC与Ajax进行交互
-
SpringMVC天生支持jackson工具的使用
-
使用@ResponseBody注解完成响应数据的格式转换;ResponseBody注解会自动使用jackson工具,将返回的java对象转换成json
@Controller @RequestMapping("/ajax") public class AjaxController { @RequestMapping("/test0.do") @ResponseBody //解析响应体的内容,此时返回的字符串不再是跳转的视图,而是个字符串响应到客户端 public String test0(){ return "ok"; } @RequestMapping("/test1.do") //ResponseBody注解会自动使用jackson工具,将返回的java对象转换成json @ResponseBody public User test1(){ User user = new User(1, "mo", "LoveMe"); return user; //返回json } @RequestMapping("/test2.do") public @ResponseBody List<User> test2(){ List<User> users = Arrays.asList( new User(1, "mo", "LoveMe"), new User(2,"yuan","123456") ); return users; //返回json } //响应一个代表执行状态的字符串,这种方式响应结果描述性更强,可以响应回去状态码 @RequestMapping("/test3.do") public @ResponseBody Map<String,String> test3(){ Map<String,String> status = new HashMap<>(); status.put("status","ok"); return status; } }
-
@RequestBody接收json格式的数据,在参数处使用
$(function () { var jsObj = {username:'mo',password:'LoveMe'}//js对象 //将js对象转换成json字符串 var jsonStr = JSON.stringify(jsObj); $('#btn').click(function () { $.ajax({ url: '${pageContext.request.contextPath }/ajax/test4.do', type: 'post', //此时数据较多,不能用get data: jsonStr, //请求参数数据为json字符串 contentType:'application/json', //指定本次的请求参数为json字符串格式 dataType: 'json', //如果使用这个属性,则服务端响应端的结果必须是JSON字符串 success: function (result) { console.log(result); } }); }); }); //发送普通字符串,接收json $('#btn').click(function(){ $.ajax({ url:'${pageContext.request.contextPath }/ajax/test0.do', type:'get', data:'name=mo', dataType: 'json', //如果使用这个属性,则服务端响应端的结果必须是JSON字符串 success: function (result) { console.log(result); } }); }); //接收json格式数据,自动使用Java对象接收 @RequestMapping("/test4.do") @ResponseBody public String test4(@RequestBody User user){ //RequestBody System.out.println(user); return "ok"; }
-
-
文件的上传
-
编写客户端表单
post:通常数据量大 enctype:会将表单中传递的文件以二进制编码的方式发送到服务器;原始类型会以key-value字符串发送 <form action="" method="post" enctype="multipart/form-data"> <input type="file" name="upFile"> <input type="submit" value="上传"> </form>
-
服务器接收上传的文件
-
MultipartFile upFile:上传的文件,所有的内容保存的对象
@Controller @RequestMapping("file") public class FileController { /** * @param upload:获取上传文件的信息对象 * @return */ @RequestMapping("upload.do") public String upload(MultipartFile upload, HttpSession session) throws IOException { //控制台输出上传文件的几个原信息 System.out.println("上传文件名:"+upload.getOriginalFilename()); System.out.println("上传文件类型:"+upload.getContentType()); System.out.println("上传文件字节数:"+upload.getBytes()); //将上传文件保存到服务器的指定位置 //获取绝对路径 String realPath = session.getServletContext().getRealPath("/upload"); //获取文件名后缀 String extension = FilenameUtils.getExtension(upload.getOriginalFilename()); //使用uuid+后缀拼接新名字 UUID uuid = UUID.randomUUID(); String newFileName = uuid.toString() + "." + extension; upload.transferTo(new File(realPath+"/"+newFileName)); return "success"; } }
-
在spring-mvc.xml配置上传文件解析器
<!--配置上传文件的解析器 id需要让Spring获取,所有不能更改--> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"> <!--设置上传文件大小,默认值sizeMax=-1,大小不限--> <property name="maxUploadSize" value="20971520"></property> </bean>
文件的下载
-
客户端
<a href="${pageContext.request.contextPath }/file/download.do">下载</a>
-
controller
@RequestMapping("download.do") public void download(HttpServletResponse response,HttpSession session) throws IOException { //获取待下载的文件 // FileInputStream in = new FileInputStream("/Users/hang/IdeaProjects/prepare/springMVC/springMVC_day2/target/springMVC_day2/upload/5.jpg"); // 优化 String realPath = session.getServletContext().getRealPath("/upload"); FileInputStream in = new FileInputStream(realPath + "/a.jpg"); //下载 // 设置相应文件的类型 response.setHeader("context-type","image/jpg"); //设置下载文件在客户端打开的方式 /** * attachment;filename=5.jpg以附件的形式下载到客户端 * inline代表在浏览器窗口打开 */ response.setHeader("context-disposition","inline;filename=a.jpg"); OutputStream out = response.getOutputStream(); //调用工具类,把in的内容用out写出去 IOUtils.copy(in,out); }
验证码
-
判断操作的对象是否是一个真正的人
-
使用工具类生成
//用流响应结果,返回值void @RequestMapping("generate.do") public void generate(HttpSession session, HttpServletResponse response) throws IOException { // 获取验证码随机数 String securityCode = SecurityCode.getSecurityCode(); // 存入session作用域做验证使用 session.setAttribute("securityCode",securityCode); // 生成验证码图片 BufferedImage image = SecurityImage.createImage(securityCode); // 响应到客户端,专门用来处理图片的工具类 ImageIO.write(image, "png", response.getOutputStream()); }
拦截器实现
-
主要作用:在请求到达目标控制器之前执行,可以拦截请求。通常会将多个控制器中的共性冗余的代码提取到拦截器中定义,提高代码的复用性
-
实现接口HandlerInterceptor
public class MyInterceptor1 implements HandlerInterceptor { /** * @param request:请求对象 * @param response:响应对象 * @param handler:处理器对象 * @return true:继续向下执行 false:拦截住请求,不继续向下执行,可以做重定向处理 * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("从多个controller中提取到的冗余代码"); //返回值代表请求是否继续向下执行 //true:继续向下执行 false:不继续向下执行 return true; } }
-
配置spring-mvc.xml,同时排除不需要拦截的控制器(controller)
<!--配置拦截器--> <mvc:interceptors> <!--一对<mvc:interceptor>标签代表配置一个拦截器--> <mvc:interceptor> <!--拦截所有的请求--> <!--<mvc:mapping path="/**"/>--> <!--拦截指定namespace下的--> <mvc:mapping path="/target/*"/> <!--在拦截的范围中,排除指定的不拦截的--> <mvc:exclude-mapping path="/target/test0"/> <!--指定拦截器实现类--> <bean class="com.mo.inteceptor.MyInterceptor1"></bean> </mvc:interceptor> </mvc:interceptors>
-
拦截器使用技巧
-
拦截器中做重定向
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("从多个controller中提取到的冗余代码"); String name = request.getParameter("name"); if (name == null) { //进行重定向 response.sendRedirect(request.getContextPath() + "/error.jsp"); return false; } else { //返回值代表请求是否继续向下执行 //true:继续向下执行 false:不继续向下执行 return true; } }
-
全局异常的处理
-
自定义异常的实现
- 自定义非运行时异常,继承Exception
- 自定义运行时异常,继承RuntimeException
-
实现全局异常处理,把异常统一处理到一个位置,让开发人员专注业务开发
public class UsernameErrorException extends RuntimeException { public UsernameErrorException(String message) { super(message); } } //当程序中抛出异常时,会自动执行这个全局异常处理器 public class GlobalExceptionHandler implements HandlerExceptionResolver { //参数 e 为捕捉到的异常信息对象 @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView mv = new ModelAndView(); //在打印台输出,便于纠正 e.printStackTrance(); if (e instanceof UsernameErrorException) { //打印获取异常信息 //System.out.println(e.getMessage()); mv.setViewName("redirect:/error.jsp"); } else if(e instanceof Exception){ mv.setViewName("redirect:/error.jsp"); } //注意返回值 return mv; } } //spring-mvc.xml <!--配置全局异常处理的实现类--> <bean class="com.mo.exception_handler.GlobalExceptionHandler"></bean> //使用自定义异常 @RequestMapping("login.do") public String login(String username,String password){ if(!("mo".equals(username))){ throw new UsernameErrorException("用户名错误"); } return "success"; }
web.xml的第二种开发方式
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<!--匹配以 .do结尾的-->
<!--<url-pattern>*.do</url-pattern>-->
<!--匹配所有请求,处理不了html等静态资源,此时需要在配置文件中添加排除静态资源-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</servlet>
<!-- spring-mvc.xml -->
<!-- 排除静态资源不让入口Servlet处理(当路径风格为 / 时配置) -->
<mvc:default-servlet-handler />