1. Spring MVC
-
请求处理流程分析
流程: 1.首先用户发送请求,请求被SpringMvc前端控制器(DispatherServlet)捕获; 2.前端控制器(DispatherServlet)对请求URL解析获取请求URI,根据URI,调用HandlerMapping; 3.前端控制器(DispatherServlet)获得返回的HandlerExecutionChain(包括Handler对象以及Handler对象对应的拦截器); 4.DispatcherServlet 根据获得的 HandlerExecutionChain,选择一个合适的HandlerAdapter。 (附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法); 5.HandlerAdapter根据请求的Handler适配并执行对应的Handler;HandlerAdapter(提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据配置,Spring将做一些额外的工作: HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息。 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等数据格式化:数据格式化。 如将字符串转换成格式化数字或格式化日期等。 数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中)。 6.Handler执行完毕,返回一个ModelAndView(即模型和视图)给HandlerAdaptor。 7.HandlerAdaptor适配器将执行结果ModelAndView返回给前端控制器。 8.前端控制器接收到ModelAndView后,请求对应的视图解析器。 9.视图解析器解析ModelAndView后返回对应View; 10.渲染视图并返回渲染后的视图给前端控制器。 11.最终前端控制器将渲染后的页面响应给用户或客户端。
-
优势
1.清晰的角色划分:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、 处理器或页面控制器(Controller)、验证器( Validator)、命令对象(Command 请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。 2.分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要; 3.和Spring 其他框架无缝集成,是其它Web框架所不具备的; 4.可适配,通过HandlerAdapter可以支持任意的类作为处理器; 5.可定制性,HandlerMapping、ViewResolver等能够非常简单的定制; 6.功能强大的数据验证、格式化、绑定机制; 7.利用Spring提供的Mock对象能够非常简单的进行Web层单元测试; 8.本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。 9.强大的JSP标签库,使JSP编写更容易。
-
环境搭建
1.开发环境 Idea + Maven + Jdk1.8 + Jetty 2.pom.xml坐标添加 3.配置web.xml 4.spring.xml配置 5.页面控制器的编写 6.添加视图页面(在WEB-INF下新建jsp文件夹) 7.启动jetty服务器
-
URL地址映射配置
@RequestMapping 通过注解@RequestMapping将请求地址与方法进行绑定,可以在类级别和方法级别声明。 1.映射单个URL(声明在方法上面) @RequestMapping("")或@RequestMapping(value="") @RequestMapping("/请求路径")与@RequestMapping("请求路径")均可 访问地址:http://ip:port/项目名/方法路径 如果有类路径需要写在方法路径前面 2.映射多个URL(声明在方法上面) @RequestMapping({"",""}) 或 @RequestMapping(value={"",""}) 支持一个方法绑定多个url的操作 访问地址:http://ip:port/项目名/方法路径 如果有类路径需要写在方法路径前面 3.映射URL在控制器上(声明在类上面) 表示类中的所有响应请求的方法都是以该地址作为父路径。 声明级别: 类级别 + 方法级别 (/类路径/方法路径) 访问地址:http://ip:port/项目名/类路径/方法路径 4.设置URL映射的请求方式 默认没有设置请求方式,可以通过method属性设置支持的请求方式,如method=RequestMethod.POST; 如设置多种请求方式,以大括号包围,逗号隔开即可。 访问地址:http://ip:port/项目名/类路径/方法路径(只能使用POST请求访问) 5.通过参数名称映射URL @RequestMapping(params = "") 通过参数的形式访问 访问地址:http://ip:port/项目名/url?方法路径
-
参数绑定
1.基本数据类型 参数值必须存在。如果没有指定参数值,也没有设置参数默认值,则会报500异常。 通过注解@RequestParam标记一个形参为请求参数。(注解声明在形参的前面) 可以通过注解的属性设置相关内容 。 设置参数的默认值 defaultValue 设置参数的参数名(别名) name 2.包装类型(如果数据是基本类型,建议使用包装类型) 客户端请求参数名与方法形参名保持一致,默认参数值为null。 设置参数的默认值 defaultValue 设置参数的参数名(别名) name 3.字符串类型 客户端请求参数名与方法形参名保持一致,默认参数值为null。 设置参数的默认值 defaultValue 设置参数的参数名(别名) name 4.数组类型 客户端传参形式:ids=1&ids=2&ids=3。 5.JavaBean类型 客户端请求的参数名与JavaBean对象的属性字段名保持一致。 6.List类型 User实体需要定义对应list属性。(对于集合的参数绑定,一般需要使用JavaBean对象进行包装) 7.Set类型 Set和List类似,也需要绑定在对象上,而不能直接写在Controller方法的参数中。 绑定Set数据时,必须先在Set对象中add相应的数量的模型对象。 8.Map类型 Map最为灵活,它也需要绑定在对象上,而不能直接写在Controller方法的参数中。
-
请求转发与重定向
SpringMVC默认采用服务器内部转发的形式展示页面信息。同样也支持重定向页面。1.重定向 重定向是发一个302的状态码给浏览器,浏览器自己去请求跳转的网页。地址栏会发生改变。 重定向到JSP页面: 格式:return "redirect:jsp文件名/别名?传递参数(传递中文参数会出现乱码)"; 避免中文乱码问题(使用redirectAttributes): @RequestMapping(value="/view04") public String view04(RedirectAttributes redirectAttributes){ redirectAttributes.addAttribute("uname","张三"); redirectAttributes.addAttribute("upwd","123456"); return "redirect:view.jsp"; } 重定向到Controller: 格式:return modelAndView; 返回ModelAndView对象(用来封装需要响应到页面的数据和视图名字): @RequestMapping(value="/view07") public ModelAndView view07(ModelAndView modelAndView){ modelAndView.addObject("uname","admin"); modelAndView.setViewName("redirect:test01"); return modelAndView; } 页面中获取参数值: ${param.参数名} 2.请求转发 请求转发,直接调用跳转的页面,让它返回。对于浏览器来说,它无法感觉服务器有没有forward。地址栏不发生改变。可以获取请求域中的数据。 请求转发到JSP页面: 格式:return "forward:jsp文件名/别名?传递参数"; 设置请求域(使用addAttribute): @RequestMapping("/view10") public String view10(Model model){ model.addAttribute("uname","张三"); return "forward:view.jsp"; } 默认会去指定目录下找JSP页面(配置文件中设置的):return "/../../view"; 请求转发到Controller: 格式:return modelAndView; @RequestMapping("/view13") public ModelAndView view13(ModelAndView modelAndView){ modelAndView.setViewName("forward:test01?uname=admin"); return modelAndView; } 页面中获取数据: 获取传递的参数:${param.参数名} 获取请求域的数据:${请求域中设置的名称}
-
JSON数据开发
Json在企业开发中已经作为通用的接口参数类型,在页面(客户端)解析很方便。@ResponseBody 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。 返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用(通常用于ajax请求)。 @RequestBody 该注解用于读取Request请求的body部分数据,使用系统默认配置的 HttpMessageConverter进行解析, 然后把相应的数据绑定到要返回的对象上 ,再把HttpMessageConverter返回的对象数据绑定到controller中方法的参数上。 使用配置 1.添加json相关坐标 <!-- 添加json 依赖jar包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.10.0</version> </dependency> 2.修改配置文件 <!-- mvc 请求映射 处理器与适配器配置 --> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter" /> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> </mvc:message-converters> </mvc:annotation-driven> 3.注解使用 @ResponseBody 返回的是JOSN格式的数据,返回JavaBean对象 或 返回的是JOSN格式的数据,返回集合 注解设置在方法体上 或 注解设置在方法返回对象前,修饰符之后 @RequestBody @RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded类型的内容,一般情况下来说常用其来处理application/json类型。 @RequestBody接受的是一个json格式的字符串,一定是一个字符串。 通过@RequestBody可以将请求体中的JSON字符串绑定到相应的bean上,当然,也可以将其分别绑定到对应的字符串上。 规定请求的参数是JOSN格式的字符串 注解设置在形参前面 //请求传递JSON格式的数据,返回JSON格式的数据 function fun(){ $.ajax({ //请求方式 Get|Post type:"post", //请求路径 url:"json5", //预期服务器返回的额数据类型 data:params, //设置服务器请求类型的数据类型为JSON格式 contentType:"application/json;charset=utf-8", //传递给服务器的参数 dataType:"json", //回调函数,接收服务器返回的响应的结果 (函数中的形参用来接收服务器返回的数据) success:function (data){ console.log(data); } }); }
-
拦截器
主要作用:拦截用户的请求并进行相应的处理。 定义方式: 实现接口:org.springframework.web.servlet.HandlerInterceptor 继承适配器:org.springframework.web.servlet.handler.HandlerInterceptorAdapter 1.拦截器实现: 1.实现HandlerInterceptor接口 接口实现类 实现HandlerInterceptor接口 public boolean preHandle 在目标Handler(方法)执行前 执行 返回true:执行handler方法。 返回false:阻止目标handler方法执行。 public void postHandle 在目标Handler(方法)执行后,视图生成前执行 public void afterCompletion 在目标Handler(方法)执行后,视图生成后执行 xml配置 1.使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求。 <mvc:interceptors> <bean class="com.yjxxt.springmvc.interceptor.MyInterceptor01"/> </mvc:interceptors> 2 (推荐使用).定义在mvc:interceptor下面,可以自定义需要拦截的请求 。 如果有多个拦截器满足拦截处理的要求,则依据配置的先后顺序来执行。 <mvc:interceptors> <mvc:interceptor> <!-- 通过 mvc:mapping 配置需要拦截的资源。支持通配符。可配置多个。 --> <mvc:mapping path="/**"/> <!-- "/**"表示拦截所有的请求。 --> <!-- 通过 mvc:mapping 配置不需要被拦截的资源。支持通配符。可配置多个。 --> <mvc:exclude-mapping path="/url/*"/> <!-- "/url/*"表示放行url路径下的请求。 --> <bean class="com.yjxxt.springmvc.interceptor.MyInterceptor01"/> </mvc:interceptor> </mvc:interceptors> 2.继承HandlerInterceptorAdapter(实际上最终还是HandlerInterceptor接口实现。) 子类实现类 继承HandlerInterceptorAdapter适配器 public boolean preHandle 在目标Handler(方法)执行前 执行 返回true:执行handler方法。 返回false:阻止目标handler方法执行。 public void postHandle 在目标Handler(方法)执行后,视图生成前执行 public void afterCompletion 在目标Handler(方法)执行后,视图生成后执行 xml配置 <mvc:interceptors> <mvc:interceptor> <!-- 拦截的资源 --> <mvc:mapping path="/**"/> <!-- 放行的资源 --> <mvc:exclude-mapping path="/url/test01"/> <mvc:exclude-mapping path="/url/test02"/> <bean class="com.yjxxt.springmvc.interceptor.MyInterceptor02"/> </mvc:interceptor> </mvc:interceptors> 2.多个拦截器实现 如果有多个拦截器满足拦截处理的要求,则依据配置的先后顺序来执行 先配置的拦截器的preHandle方法先执行 先配置的拦截器的postHandle、afterCompletion方法后执行 代码实现 实现HandlerInterceptor接口 或 继承HandlerInterceptorAdapter适配器 xml配置 <mvc:interceptors> <mvc:interceptor> <!-- 拦截所有请求 --> <mvc:mapping path="/**" /> <bean class="com.xxxx.springmvc.interceptor.MyInterceptor01" /> </mvc:interceptor> <mvc:interceptor> <!-- 拦截所有请求 --> <mvc:mapping path="/**" /> <bean class="com.xxxx.springmvc.interceptor.MyInterceptor02" /> </mvc:interceptor> </mvc:interceptors> 3.拦截器应用 - 非法请求拦截 使用拦截器完成用户是否登录请求验证功能 1.用户控制器 @Controller public class UserInfo { //用户登录 @RequestMapping("login") public String login(HttpSession session){ System.out.println("登录成功"); User user = new User(); user.setId(10); user.setUserName("xiaoming"); user.setUserPwd("123"); //登录成功后将用户的基本信息存入session作用域中 session.setAttribute("user",user); return "success"; } //用户添加 @RequestMapping("add") public String add(){ System.out.println("添加成功"); return "success"; } //用户修改 @RequestMapping("update") public String update(){ System.out.println("修改成功"); return "success"; } //用户删除 @RequestMapping("delete") public String delete(){ System.out.println("删除成功"); return "success"; } } 2.页面定义(success.jsp) <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h3>欢迎登录!</h3> </body> </html> 3.非法请求拦截器定义 public class LoginInterceptor implements HandlerInterceptor { //在目标方法执行之前 运行/拦截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //通过session对象获取作用域用户的状态 User user = (User) request.getSession().getAttribute("user"); //判断user数据是否存在 if(null == user){ //未登录状态 提示用户去访问登录接口 // response.sendRedirect(request.getContextPath()+"/WEB-INF/jsp/error.jsp"); //重定向 客户端行为 request.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(request,response); //请求转发 服务器端行为 //不执行目标方法 return false; } //用户已登录,执行目标方法 return true; } } 4.xml配置 <!-- 拦截所有请求 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截所有请求 --> <mvc:mapping path="/**" /> <!-- 放行用户登录请求 --> <mvc:exclude-mapping path="/userInfo/login"/> <bean class="com.xxxx.springmvc.interceptor.LoginInterceptor" /> </mvc:interceptor> </mvc:interceptors>
-
文件上传
1.环境配置 pom.xml中添加 <!-- 添加 commons-fileupload 依赖 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency> spring.xml修改 <!-- 文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 允许文件上传的最大尺寸 --> <property name="maxUploadSize"> <value>104857600</value> </property> <!--设置文件放入临时文件夹的最大大小限制。 此值是阈值,低于此值,则保存在内存中,如高于此值,则生成硬盘上的临时文件。 --> <property name="maxInMemorySize"> <value>4096</value> </property> </bean> 2.代码实现 单文件上传 页面表单 input的type设置为file form表单的method设为post, form表单的enctype设置为multipart/form-data,以二进制的形式传输数据 <form action="uploadFile" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <button type="submit"> 提交</button> </form> 代码实现 @Controller public class FileUpload { @RequestMapping("uploadFile") public void uploadFile(MultipartFile file,HttpServletRequest request){ //判断是否上传了文件 if(!file.isEmpty()){ //为上传的文件准备一个存放路径 String path = request.getServletContext().getRealPath("/"); //准备目录 File filePath = new File(path + "/upload"); //判断目录是否存在 if(!filePath.exists()){ filePath.mkdir();//创建目录 } //重新创建文件的名称 //获取文件原名称 String filename = file.getOriginalFilename(); //截取文件的后缀 从最后一个点开始 String hzName = filename.substring(filename.lastIndexOf(".")); //以时间戳为名称创建一个新的文件名字 String newFileName = System.currentTimeMillis() + hzName; try { //上传 file.transferTo(new File(filePath, newFileName)); System.out.println("上传成功"); } catch (IOException e) { e.printStackTrace(); System.out.println("上传失败"); } } } } 多文件上传 页面表单 <form action="uploadFiles" method="post" enctype="multipart/form-data"> <input type="file" name="files" /> <input type="file" name="files" /> <input type="file" name="files" /> <button type="submit"> 提交</button> </form> 代码实现 @Controller public class FileUpload { @RequestMapping("uploadFile") public void uploadFiles(@RequestParam("files") List<MultipartFile> files, HttpServletRequest request){ for(MultipartFile file:files){ uploadFile(file,request); } } public void uploadFile(MultipartFile file,HttpServletRequest request){ //判断是否上传了文件 if(!file.isEmpty()){ //为上传的文件准备一个存放路径 String path = request.getServletContext().getRealPath("/"); //准备目录 File filePath = new File(path + "/upload"); //判断目录是否存在 if(!filePath.exists()){ filePath.mkdir();//创建目录 } //重新创建文件的名称 //获取文件原名称 String filename = file.getOriginalFilename(); //截取文件的后缀 从最后一个点开始 String hzName = filename.substring(filename.lastIndexOf(".")); //以时间戳为名称创建一个新的文件名字 String newFileName = System.currentTimeMillis() + hzName; try { //上传 file.transferTo(new File(filePath, newFileName)); System.out.println("上传成功"); } catch (IOException e) { e.printStackTrace(); System.out.println("上传失败"); } } } }
-
SSM框架集成与测试
1.环境配置 配置pom.xml 修改JDK版本为11 添加坐标依赖 设置资源目录和插件 配置web.xml 配置servlet-context.xml 配置spring.xml 配置mybatis.xml 配置db.properties 添加log4j.properties 2.添加源代码 java下创建 com.xxxx.ssm.controller 添加UserController.java com.xxxx.ssm.service 添加UserService.java com.xxxx.ssm.mapper 添加UserMapper.xml映射文件 com.xxxx.ssm.dao 添加UserDao.java接口 com.xxxx.ssm.po 添加JavaBean文件User.java 添加hello.jsp视图文件,用来展示查询的用户信息
-
RestFul URL
Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。 在Restful风格中,用户请求的url使用同一个url,用请求方式: GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的方式。 POST(CREATE):在服务器端新建一个资源,调用insert操作。 PUT(UPDATE):在服务器端更新资源,调用update操作。 PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(目前jdk7未实现,tomcat7不支持)。 DELETE(DELETE):从服务器端删除资源,调用delete语句。 SpringMVC是通过@RequestMapping及@PathVariable注解提供的RestFul URL。 映射地址配置: 1.准备环境 po目录下新建Account.java实体类 dao目录下新建AccountDao.java接口类 mapper目录下新建AccountMapper.xml映射文件 service目录下新建AccountService.java 2.URL映射地址配置 get请求,执行查询操作 @GetMapping("account/{id}") @ResponseBody public Account queryAccountById(@PathVariable Integer id){ return accountService.selectById(id); } delete请求,执行删除操作 @DeleteMapping("account/{id}") @ResponseBody public Map<String,Object> deleteAccount(@PathVariable Integer id){ int result = accountService.delAccount(id); Map<String,Object> map=new HashMap<String,Object>(); if(result == 1 ){ map.put("msg","success"); map.put("code",200); } else { map.put("msg","error"); map.put("code",500); } return map; } post请求,执行添加操作 @PostMapping("account") @ResponseBody public Map<String,Object> saveAccount(@RequestBody Account account){ int result = accountService.saveAccount(account); Map<String,Object> map=new HashMap<String,Object>(); if(result == 1 ){ map.put("msg","success"); map.put("code",200); } else { map.put("msg","error"); map.put("code",500); } return map; } put请求,执行更新操作 @PutMapping("account") @ResponseBody public Map<String,Object> updateAccount(@RequestBody Account account){ int result = accountService.updateAccount(account); Map<String,Object> map=new HashMap<String,Object>(); if(result == 1 ){ map.put("msg","success"); map.put("code",200); } else { map.put("msg","error"); map.put("code",500); } return map; }
-
全局异常统一处理
由于每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。 所以通过SpringMVC提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。 全局异常处理的3种方式: 1.使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver 优点:集成简单、有良好的扩展性、对已有代码没有入侵性。 缺点:该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。 1.配置SimpleMappingExceptionResolver对象 <!-- 配置全局异常统一处理的 Bean (简单异常处理器) --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 页面在转发时出现异常,设置默认的错误页面 (error代表的是一个视图) --> <property name="defaultErrorView" value="error"></property> <!-- 异常发生时,设置异常的变量名 --> <property name="exceptionAttribute" value="ex"></property> </bean> 可以在处理异常的页面获取异常信息:${ex} 2.使用自定义异常 参数异常 public class ParamsException extends RuntimeException { private Integer code = 300; private String msg = "参数异常!"; 构造器; Get和Set方法; } 业务异常 public class BusinessException extends RuntimeException { private Integer code=400; private String msg="业务异常!"; 构造器; Get和Set方法; } 3.设置自定义异常与页面的映射 <!-- 设置自定义异常与页面的映射 --> <property name="exceptionMappings"> <props> <!-- key:自定义异常对象的路径; 标签中设置具体的处理页面的视图名--> <prop key="com.xxxx.ssm.exception.BusinessException">buss_error</prop> <prop key="com.xxxx.ssm.exception.ParamsException">params_error</prop> </props> </property> 2.实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器(推荐使用) 优点:集成简单、有良好的扩展性、对已有代码没有入侵性等, 同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。 1.实现HandlerExceptionResolver接口 @Component public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) { ModelAndView mv = new ModelAndView("error"); mv.addObject("ex","默认错误信息"); return mv; } } 2.自定义异常处理 @Component public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) { ModelAndView mv = new ModelAndView("error"); mv.addObject("ex","默认错误信息"); // 判断是否是自定义异常 if (ex instanceof ParamsException) { mv.setViewName("params_error"); ParamsException e = (ParamsException) ex; mv.addObject("ex", e.getMsg()); } if (ex instanceof BusinessException) { mv.setViewName("business_error"); BusinessException e = (BusinessException) ex; mv.addObject("ex", e.getMsg()); } return mv; } } 3.使用@ExceptionHandler注解实现异常处理 优点:集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BaseController即可)、不需要附加Spring配置。 缺点:该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于BaseController),在异常处理时不能获取除异常以外的数据。 页面处理器继承BaseController public class BaseController { @ExceptionHandler public String exc(HttpServletRequest request,HttpServletResponse response,Exception ex){ request.setAttribute("ex", ex); if(ex instanceof ParamsException){ return "error_param"; } if(ex instanceof BusinessException){ return "error_business"; } return "error"; } } 未捕获异常的处理 全面而有效的异常处理机制。 修改web.xml文件 <!-- 出错页面定义 --> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/500.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>