黑马程序员springmvc教程第二天:数据回显和异常处理
数据回显
什么数据回显
提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。
pojo数据回显方法
1、springmvc默认对pojo数据进行回显。
pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)
使用@ModelAttribute指定pojo回显到页面在request中的key
2、@ModelAttribute还可以将方法的返回值传到页面
在商品查询列表页面,通过商品类型查询商品信息。
在controller中定义商品类型查询方法,最终将商品类型传到页面。
页面上可以得到itemTypes数据。
3、使用最简单方法使用model,可以不用@ModelAttribute
简单类型数据回显
使用最简单方法使用model。
model.addAttribute("id", id);
异常处理
异常处理思路
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,
最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
黑马程序员springmvc教程第二天:springmvc校验
springmvc校验校验理解项目中,通常使用较多是前端的校验,比如页面中js校验。
对于安全要求较高点建议在服务端进行校验。
服务端校验:控制层conroller:校验页面请求的参数的合法性。
在服务端控制层conroller 校验,不区分客户端类型(浏览器、手机客户端、远程调用)业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
持久层dao:一般是不校验的。
springmvc校验需求springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。
校验思路:页面提交请求的参数,请求到controller方法中,使用validation进行校验。
如果校验出错,将错误信息展示到页面。
具体需求:商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。
环境准备hibernate的校验框架validation所需要jar包:配置校验器校验器注入到处理器适配器中在pojo中添加校验规则在ItemsCustom.java中添加校验规则:CustomValidationMessages.propert ies在CustomValidationMessages.properties配置校验错误信息:捕获校验错误信息//在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息//注意:@Validated和BindingResult bindingResult是配对出现,并且形参顺序是固定的(一前一后)。
在页面显示校验错误信息在controller中将错误信息传到页面即可。
页面显示错误信息:分组校验需求在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。
SpringMVC异常处理详解
SpringMVC异常处理详解Spring MVC中异常处理的类体系结构下图中,我画出了Spring MVC中,跟异常处理相关的主要类和接⼝。
在Spring MVC中,所有⽤于处理在请求映射和请求处理过程中抛出的异常的类,都要实现HandlerExceptionResolver接⼝。
AbstractHandlerExceptionResolver实现该接⼝和Orderd接⼝,是HandlerExceptionResolver类的实现的基类。
ResponseStatusExceptionResolver等具体的异常处理类均在AbstractHandlerExceptionResolver之上,实现了具体的异常处理⽅式。
⼀个基于Spring MVC的Web应⽤程序中,可以存在多个实现了HandlerExceptionResolver的异常处理类,他们的执⾏顺序,由其order属性决定, order值越⼩,越是优先执⾏, 在执⾏到第⼀个返回不是null的ModelAndView的Resolver时,不再执⾏后续的尚未执⾏的Resolver的异常处理⽅法。
下⾯我逐个介绍⼀下SpringMVC提供的这些异常处理类的功能。
DefaultHandlerExceptionResolverHandlerExceptionResolver接⼝的默认实现,基本上是Spring MVC内部使⽤,⽤来处理Spring定义的各种标准异常,将其转化为相对应的HTTP Status Code。
其处理的异常类型有:handleNoSuchRequestHandlingMethodhandleHttpRequestMethodNotSupportedhandleHttpMediaTypeNotSupportedhandleMissingServletRequestParameterhandleServletRequestBindingExceptionhandleTypeMismatchhandleHttpMessageNotReadablehandleHttpMessageNotWritablehandleMethodArgumentNotValidExceptionhandleMissingServletRequestParameterhandleMissingServletRequestPartExceptionhandleBindExceptionResponseStatusExceptionResolver⽤来⽀持ResponseStatus的使⽤,处理使⽤了ResponseStatus注解的异常,根据注解的内容,返回相应的HTTP Status Code和内容给客户端。
【SpringBoot】统一返回对象和统一异常处理
【SpringBoot】统⼀返回对象和统⼀异常处理为什么要统⼀异常Java异常分为unchecked和checked,对于unchecked的那些异常⼀般都是代码写的有问题,⽐如你没有处理null对象,直接就⽤这个对象的⽅法或者属性了(NullPointException),或者是除0(ArithmeticException),或者是数组下标越界了(ArrayIndexOutOfBoundsException),这种的你要是能意识到try或者throw,那肯定不可能写错了。
但是对于checked,就是java要求我们处理的异常了,⽐如说SQLException , IOException,ClassNotFoundException,如果我们不做统⼀处理,那前端收到的会是⼀坨异常调⽤栈,⾮常恐怖,⽽且花样繁多,⽐如hibernate-validator的异常栈....还有就是业务异常,这种的都是⾃定义的异常,⼀般都是基于RuntimeException改的。
所以,为了把这些乱七⼋糟的都统⼀起来,按照与前端约定好的格式返回,统⼀异常⾮常有必要。
为什么要统⼀返回值不统⼀的话,返回值会五花⼋门,对于前端来说⽆法做⼀些统⼀处理,⽐如说统⼀通过状态为快速判断接⼝调⽤情况,接⼝调⽤失败原因获取每个接⼝都要⾃定义⼀个。
如果统⼀了,则前端可以写⼀个调⽤回调解析⽅法,就能快速获取接⼝调⽤情况了,⼗分便捷。
如下代码:{"state": false,"code": "-1","data": "数据库中未查询到该学⽣","timestamp": 1640142947034}前端可以通过code直接判断接⼝调⽤情况,通过data获取异常信息,或者是需要查询的数据。
如何实现统⼀异常Spring为我们提供了⼀个注解:@ControllerAdvice@ControllerAdvice@Slf4jpublic class GlobalExceptionHandler {/*** 处理⾃定义的业务异常* @param e* @return*/@ExceptionHandler(value = BusinessException.class)@ResponseBodypublic ResponseEntity businessExceptionHandler(BusinessException e){log.error("发⽣业务异常!原因是:{}",e.getMessage());return ResponseHelper.failed(e.getMessage());}}我们只需要在@ExceptionHandler这⾥写上想拦截处理的异常,就可以了,在该⽅法中,你可以把关于这个异常的信息获取出来⾃由拼接,然后通过统⼀返回格式返回给前端,⽅便前端处理展⽰。
黑马程序员springmvc教程第二天:拦截器(1)
拦截器拦截定义定义拦截器,实现HandlerInterceptor接口。
接口中提供三个方法。
publicclass HandlerInterceptor1implements HandlerInterceptor { //进入 Handler方法之前执行//用于身份认证、身份授权//比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行@Overridepublicboolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {//return false表示拦截,不向下执行//return true表示放行returnfalse;}//进入Handler方法之后,返回modelAndView之前执行//应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图@Overridepublicvoid postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception { }//执行Handler完成执行此方法//应用场景:统一异常处理,统一日志处理@Overridepublicvoid afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {}}拦截器配置针对HandlerMapping配置springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该 HandlerMapping映射成功的handler最终使用该拦截器。
SpringMVC处理方法返回值过程解析
SpringMVC处理⽅法返回值过程解析这篇⽂章主要介绍了Spring MVC处理⽅法返回值过程解析,⽂中通过⽰例代码介绍的⾮常详细,对⼤家的学习或者⼯作具有⼀定的参考学习价值,需要的朋友可以参考下对于Spring MVC处理⽅法⽀持⽀持⼀系列的返回⽅式:(1)ModelAndView(2)Model(3)ModelMap(4)Map(5)View(6)String(7)Void(8)Object⼀,ModelAndView@RequestMapping("/threadRequest*")public ModelAndView threadRequest(){ModelAndView mv=new ModelAndView();mv.setViewName("index");mv.addObject("user","王五");return mv;}通过ModelAndView构造⽅法可以指定返回的页⾯名称,也可以通过setViewName()⽅法跳转到指定的页⾯ ,使⽤addObject()设置需要返回的值,addObject()有⼏个不同参数的⽅法,可以默认和指定返回对象的名字。
调⽤addObject()⽅法将值设置到⼀个名为ModelMap的类属性,ModelMap是LinkedHashMap的⼦类,⼆,ModelModel是⼀个接⼝,其实现类为ExtendedModelMap,继承了ModelMap类。
model.addAttribute("pojo", pojo);三,ModelMapModel 是⼀个接⼝,其实现类为ExtendedModelMap,继承了ModelMap类。
四,Map@RequestMapping("/show")public Map<String, String> getMap() {Map<String, String> map = new HashMap<String, String>();map.put("key1", "value-1");map.put("key2", "value-2");return map;}五,View可以返回pdf excel六,String@RequestMapping("/RequestMethod")public String index(Model model) {String retVal = "user/index";List<User> users = userService.getUsers();model.addAttribute("users", users);return retVal;}1、如果返回值为null,那么以请求名作为视图名进⾏跳转2、如果指定返回值,那么按照指定返回值作为视图名进⾏跳转,可以通过model,modeMap携带数据。
springmvc-机制(拦截器、aop、异常)
◆Spring-mvc知识➢概念Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
图1 Spring Web MVC核心架构图理解这张图之前我们得先知道以下的几个名词:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器(Validator)、命令对象(Command 请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)步骤解析:核心架构的具体流程步骤如下:1、首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;2、DispatcherServlet——>HandlerMapping,HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;3、DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;4、HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);5、ModelAndView的逻辑视图名——> ViewResolver,ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;6、View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
springmvc请求参数异常统一处理
springmvc请求参数异常统⼀处理 1、ExceptionHandlerControllerpackage com.oy.controller;import java.text.MessageFormat;import org.springframework.beans.TypeMismatchException;import org.springframework.http.HttpStatus;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.web.HttpRequestMethodNotSupportedException;import org.springframework.web.bind.MissingServletRequestParameterException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.ResponseStatus;import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;import com.alibaba.fastjson.JSONObject;import com.oy.exception.ForbiddenException;import com.oy.utils.UtilFunctions;@ControllerAdvicepublic class ExceptionHandlerController {@ExceptionHandler(RuntimeException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic JSONObject runtimeExceptionHandler(RuntimeException ex) {UtilFunctions.log.error("runtimeExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();response.put("message", "Internal Server Error");return response;}@ExceptionHandler(NullPointerException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic JSONObject nullPointerExceptionHandler(NullPointerException ex) {UtilFunctions.log.error("nullPointerExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();response.put("message", "Internal Server Error");return response;}/*----- REQUEST ERROR -----*/@ExceptionHandler({ ForbiddenException.class })@ResponseStatus(HttpStatus.FORBIDDEN)@ResponseBodypublic JSONObject requestForbidden(ForbiddenException ex) {UtilFunctions.log.error("ForbiddenExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();response.put("message", ex.getMessage());return response;}@ExceptionHandler({ TypeMismatchException.class })@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic JSONObject requestTypeMismatch(TypeMismatchException ex) {UtilFunctions.log.error("TypeMismatchExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();// response.put("message", "Bad Request");// response.put("message", "Bad Request, parameter type of " + ex.getPropertyName() + " need be " + ex.getRequiredType());if (Double.class.equals(ex.getRequiredType()) || Integer.class.equals(ex.getRequiredType())) {response.put("message", "Bad Request, " + ex.getValue() + " not a number");} else {String strTemplate = "Bad Request, {0} is invalid, a type of {1} is needed";response.put("message", MessageFormat.format(strTemplate, ex.getValue(), ex.getRequiredType().getName()));}return response;}@ExceptionHandler({ MissingServletRequestParameterException.class })@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic JSONObject requestMissingServletRequest(MissingServletRequestParameterException ex) {UtilFunctions.log.error("MissingServletRequestParameterExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();// response.put("message", "Bad Request");String strTemplate = "Bad Request, param:{0} is required, type:{1}";response.put("message", MessageFormat.format(strTemplate, ex.getParameterName(), ex.getParameterType()));return response;}@ExceptionHandler({ NoSuchRequestHandlingMethodException.class })@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic JSONObject NoSuchRequestHandlingMethodExceptionHandler(NoSuchRequestHandlingMethodException ex) { UtilFunctions.log.error("NoSuchRequestHandlingMethodExceptionHandler, msg:{}, exception:{}", ex.toString(), ex); JSONObject response = new JSONObject();response.put("message", "Not Found");return response;}/*----- REQUEST ERROR -----*/@ExceptionHandler({ HttpMessageNotReadableException.class })@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic JSONObject requestNotReadable(HttpMessageNotReadableException ex) {UtilFunctions.log.error("HttpMessageNotReadableExceptionHandler, msg:{}, exception:{}", ex.toString(), ex);JSONObject response = new JSONObject();response.put("message", "Bad Request");return response;}@ExceptionHandler({ HttpRequestMethodNotSupportedException.class })@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)@ResponseBodypublic JSONObject request405(HttpRequestMethodNotSupportedException ex) {UtilFunctions.log.error("HttpRequestMethodNotSupportedExceptionHandler, msg:{}, exception:{}", ex.toString(), ex); JSONObject response = new JSONObject();// response.put("message", "Method Not Allowed");response.put("message", ex.getMessage());return response;}}2、postman测试3、异常增强类型: NullPointerException,RunTimeException,ClassCastException, NoSuchMethodException,IOException,IndexOutOfBoundsException 以及springmvc⾃定义异常等,如下: SpringMVC⾃定义异常对应的status codeException HTTP Status CodeConversionNotSupportedException 500 (Internal Server Error)HttpMessageNotWritableException 500 (Internal Server Error)HttpMediaTypeNotSupportedException 415 (Unsupported Media Type) HttpMediaTypeNotAcceptableException 406 (Not Acceptable) HttpRequestMethodNotSupportedException 405 (Method Not Allowed) NoSuchRequestHandlingMethodException 404 (Not Found)TypeMismatchException 400 (Bad Request)HttpMessageNotReadableException 400 (Bad Request)MissingServletRequestParameterException 400 (Bad Request)参考资料: (1) (2) (3)。
springmvc-机制(拦截器、aop、异常)
◆Spring-mvc知识概念Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
图1 Spring Web MVC核心架构图理解这张图之前我们得先知道以下的几个名词:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器( Validator)、命令对象(Command 请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)步骤解析:核心架构的具体流程步骤如下:1、首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
SpringMVC统一异常处理三种方法详解
SpringMVC统⼀异常处理三种⽅法详解这篇⽂章主要介绍了SpringMVC-统⼀异常处理三种⽅法详解,⽂中通过⽰例代码介绍的⾮常详细,对⼤家的学习或者⼯作具有⼀定的参考学习价值,需要的朋友可以参考下在 Spring MVC 应⽤的开发中,不管是对底层数据库操作,还是业务层或控制层操作,都会不可避免地遇到各种可预知的、不可预知的异常需要处理。
如果每个过程都单独处理异常,那么系统的代码耦合度⾼,⼯作量⼤且不好统⼀,以后维护的⼯作量也很⼤。
如果能将所有类型的异常处理从各层中解耦出来,这样既保证了相关处理过程的功能单⼀,⼜实现了异常信息的统⼀处理和维护。
幸运的是,Spring MVC 框架⽀持这样的实现。
Spring MVC 统⼀异常处理有以下 3 种⽅式:使⽤ Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver。
实现 Spring 的异常处理接⼝ HandlerExceptionResolver ⾃定义⾃⼰的异常处理器。
使⽤ @ExceptionHandler 注解实现异常处理本节主要根据这 3 种处理⽅式讲解 Spring MVC 应⽤的异常统⼀处理。
Spring MVC使⽤SimpleMappingExceptionResolver类异常处理<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring⼀beans.xsd/schema/context/schema/context/spring-context.xsd"><!-- 使⽤扫描机制扫描包 --><context:component-scan base-package="controller" /><context:component-scan base-package="service" /><context:component-scan base-package="dao" /><!-- 配置视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!--前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean><!--SimpleMappingExceptionResolver(异常类与 View 的对应关系) --><beanclass="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><!-- 定义默认的异常处理页⾯,当该异常类型注册时使⽤ --><property name="defaultErrorView" value="error"></property><!-- 定义异常处理页⾯⽤来获取异常信息的变量名,默认名为exception --><property name="exceptionAttribute" value="ex"></property><!-- 定义需要特殊处理的异常,⽤类名或完全路径名作为key,异常页名作为值 --><property name="exceptionMappings"><props><prop key="exception.MyException">my-error</prop><prop key="java.sql.SQLException">sql-error</prop><!-- 在这⾥还可以继续扩展对不同异常类型的处理 --></props></property></bean></beans>Spring MVC使⽤HandlerExceptionResolver接⼝异常处理package exception;import java.sql.SQLException;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerExceptionResolver;import org.springframework.web.servlet.ModelAndView;public class MyExceptionHandler implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest arg0,HttpServletResponse arg1, Object arg2, Exception arg3) {Map<String, Object> model = new HashMap<String, Object>();model.put("ex", arg3);// 根据不同错误转向不同页⾯(统⼀处理),即异常与View的对应关系if (arg3 instanceof MyException) {return new ModelAndView("my-error", model);} else if (arg3 instanceof SQLException) {return new ModelAndView("sql-error", model);} else {return new ModelAndView("error", model);}}}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring⼀beans.xsd/schema/context/schema/context/spring-context.xsd"><!-- 使⽤扫描机制扫描包 --><context:component-scan base-package="controller" /><context:component-scan base-package="service" /><context:component-scan base-package="dao" /><!-- 配置视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"><!--前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean><!--托管MyExceptionHandler--><bean class="exception.MyExceptionHandler"/></beans>Spring MVC使⽤@ExceptionHandler注解异常处理package controller;import java.sql.SQLException;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.ExceptionHandler;import exception.MyException;public class BaseController {/** 基于@ExceptionHandler异常处理 */@ExceptionHandlerpublic String exception(HttpServletRequest request, Exception ex) {request.setAttribute("ex", ex);// 根据不同错误转向不同页⾯,即异常与view的对应关系if (ex instanceof SQLException) {return "sql-error";} else if (ex instanceof MyException) {return "my-error";} else {return "error";}}}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring⼀beans.xsd/schema/context/schema/context/spring-context.xsd"><!-- 使⽤扫描机制扫描包 --><context:component-scan base-package="controller" /><context:component-scan base-package="service" /><context:component-scan base-package="dao" /><!-- 配置视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!--前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean></beans>以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
SpringBoot中如何统一接口返回与全局异常处理详解
SpringBoot中如何统⼀接⼝返回与全局异常处理详解⽬录背景统⼀接⼝返回定义API返回码枚举类定义正常响应的API统⼀返回体定义异常响应的API统⼀返回体编写包装返回结果的⾃定义注解定义返回结果拦截器WebMvc配置类拦截器注册者添加返回结果拦截器编写响应体处理器接⼝调⽤测试结果全局异常处理编写⾃定义异常基类编写⾃定义业务异常类定义全局异常处理类接⼝调⽤测试结果总结背景在分布式、微服务盛⾏的今天,绝⼤部分项⽬都采⽤的微服务框架,前后端分离⽅式。
前端和后端进⾏交互,前端按照约定请求URL路径,并传⼊相关参数,后端服务器接收请求,进⾏业务处理,返回数据给前端。
维护⼀套完善且规范的接⼝是⾮常有必要的,这样不仅能够提⾼对接效率,也可以让我的代码看起来更加简洁优雅。
使⽤统⼀返回结果时,还有⼀种情况,就是程序的报错是由于运⾏时异常导致的结果,有些异常是我们在业务中抛出的,有些是⽆法提前预知。
因此,我们需要定义⼀个统⼀的全局异常,在Controller捕获所有异常,并且做适当处理,并作为⼀种结果返回。
统⼀接⼝返回定义API返回码枚举类public enum ResultCode {/* 成功状态码 */SUCCESS(200, "成功"),/* 错误状态码 */NOT_FOUND(404, "请求的资源不存在"),INTERNAL_ERROR(500, "服务器内部错误"),PARAMETER_EXCEPTION(501, "请求参数校验异常"),/* 业务状态码 */USER_NOT_EXIST_ERROR(10001, "⽤户不存在"),;private Integer code;private String message;public Integer code() {return this.code;}public String message() {return this.message;}ResultCode(Integer code, String message) {this.code = code;this.message = message;}}定义正常响应的API统⼀返回体@Datapublic class Result<T> implements Serializable {private Integer code;private String message;private boolean success = true;private T data;@JsonIgnoreprivate ResultCode resultCode;private Result() {}public void setResultCode(ResultCode resultCode) {this.resultCode = resultCode;this.code = resultCode.code();this.message = resultCode.message();}public Result(ResultCode resultCode, T data) {this.code = resultCode.code();this.message = resultCode.message();this.data = data;}public static <T> Result<T> success() {Result<T> result = new Result<>();result.setResultCode(ResultCode.SUCCESS);return result;}public static <T> Result<T> success(T data) {Result<T> result = new Result<>();result.setResultCode(ResultCode.SUCCESS);result.setData(data);return result;}}定义异常响应的API统⼀返回体@Datapublic class ErrorResult implements Serializable {private boolean success = false;@JsonIgnoreprivate ResultCode resultCode;public static ErrorResult error() {ErrorResult result = new ErrorResult();result.setResultCode(ResultCode.INTERNAL_ERROR);return result;}public static ErrorResult error(String message) {ErrorResult result = new ErrorResult();result.setCode(ResultCode.INTERNAL_ERROR.code());result.setMessage(message);return result;}public static ErrorResult error(Integer code, String message) {ErrorResult result = new ErrorResult();result.setCode(code);result.setMessage(message);return result;}public static ErrorResult error(ResultCode resultCode, String message) {ErrorResult result = new ErrorResult();result.setResultCode(resultCode);result.setMessage(message)return result;}}编写包装返回结果的⾃定义注解@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD}) //作⽤于⽅法和类(接⼝)上@Documentedpublic @interface ResponseResult {}定义返回结果拦截器@Componentpublic class ResponseResultInterceptor implements HandlerInterceptor {/* 使⽤统⼀返回体的标识 */private static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE-RESULT-ANNOTATION";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 正在处理请求的⽅法beanif (handler instanceof HandlerMethod) {final HandlerMethod handlerMethod = (HandlerMethod) handler;// 获取当前类final Class<?> clazz = handlerMethod.getBeanType();// 获取当前⽅法final Method method = handlerMethod.getMethod();// 判断是否在类对象上加了注解if (clazz.isAnnotationPresent(ResponseResult.class)) {// 设置该请求返回体,需要包装,往下传递,在ResponseBodyAdvice接⼝进⾏判断request.setAttribute(RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(ResponseResult.class));}// 判断是否在⽅法上加了注解else if (method.isAnnotationPresent(ResponseResult.class)) {// 设置该请求返回体,需要包装,往下传递,在ResponseBodyAdvice接⼝进⾏判断request.setAttribute(RESPONSE_RESULT_ANNOTATION, method.getAnnotation(ResponseResult.class));}}return true;}}WebMvc配置类拦截器注册者添加返回结果拦截器@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {/*** 添加⾃定义拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new ResponseResultInterceptor()).addPathPatterns("/**");}}编写响应体处理器/*** 统⼀处理响应体,⽤Result.success静态⽅法包装,* 在API接⼝使⽤时就可以直接返回原始类型*/@RestControllerAdvicepublic class ResponseResultHandler implements ResponseBodyAdvice<Object> {/* 使⽤统⼀返回体的标识 */private static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE-RESULT-ANNOTATION";@Overridepublic boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = Objects.requireNonNull(sra).getRequest();ResponseResult responseResult = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANNOTATION);// 判断返回体是否需要处理return responseResult != null;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { // 异常响应体则直接返回code+message的消息体if (body instanceof ErrorResult) {return body;}// 正常响应体则返回Result包装的code+message+data的消息体return Result.success(body);}}接⼝调⽤@Api("⽤户管理")@ResponseResult // 作⽤于类上,对所有接⼝有效public class UserController {@Autowiredprivate UserService userService;@ResponseResult // 作⽤于⽅法上@ApiOperation("根据ID查询⽤户")@GetMapping("one")public User selectOne(Long id) {// 由于在ResponseResultHandler中已经统⼀将返回数据⽤Result.success包装了,// 直接返回原始类型即可,代码更简洁return erService.queryById(id);}@ResponseResult@ApiOperation("查询所有⽤户")@GetMapping("all")public List<User> selectAll(Page page) {// 由于在ResponseResultHandler中已经统⼀将返回数据⽤Result.success包装了,// 直接返回原始类型即可,代码更简洁return erService.queryAllByLimit(page);}}测试结果全局异常处理编写⾃定义异常基类@Datapublic class BaseException extends RuntimeException {private static final int BASE_EXCEPTION_CODE = ResultCode.INTERNAL_ERROR.code();private static final String BASE_EXCEPTION_MESSAGE = ResultCode.INTERNAL_ERROR.message(); private Integer code;private String message;public BaseException() {super(BASE_EXCEPTION_MESSAGE);this.code = BASE_EXCEPTION_CODE;this.message = BASE_EXCEPTION_MESSAGE;}public BaseException(String message) {super(message);this.code = BASE_EXCEPTION_CODE;this.message = message;}public BaseException(ResultCode resultCode) {super(resultCode.message());this.code = resultCode.code();this.message = resultCode.message();}public BaseException(Throwable cause) {super(cause);this.code = BASE_EXCEPTION_CODE;this.message = BASE_EXCEPTION_MESSAGE;}public BaseException(String message, Throwable cause) {super(message, cause);this.code = BASE_EXCEPTION_CODE;this.message = message;}public BaseException(Integer code, String message) {super(message);this.code = code;this.message = message;}public BaseException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;this.message = message;}}编写⾃定义业务异常类public class BizException extends BaseException {public BizException(ResultCode resultCode) {super(resultCode);}}定义全局异常处理类通过@ExceptionHandler注解来统⼀处理某⼀类异常@Slf4j@RestControllerAdvicepublic class GlobalExceptionHandler {/*** 统⼀处理⾃定义基础异常*/@ExceptionHandler(BaseException.class)public ErrorResult baseException(BaseException e) {if (StringUtils.isEmpty(e.getCode())) {return ErrorResult.error(e.getMessage());}return ErrorResult.error(e.getCode(), e.getMessage());}/*** 统⼀处理⾃定义业务异常*/@ExceptionHandler(BizException.class)public ErrorResult bizException(BizException e) {return ErrorResult.error(e.getCode(), e.getMessage());}/*** 统⼀处理⾮⾃定义异常外的所有异常*/@ExceptionHandler(Exception.class)public ErrorResult handleException(Exception e) {log.error(e.getMessage(), e);return ErrorResult.error(e.getMessage());}/*** 兼容Validation校验框架:忽略参数异常处理器*/@ExceptionHandler(MissingServletRequestParameterException.class)public ApiResult<String> parameterMissingExceptionHandler(MissingServletRequestParameterException e) {log.error(e.getMessage(), e);return ErrorResult.error(PARAMETER_EXCEPTION, "请求参数 " + e.getParameterName() + " 不能为空");}/*** 兼容Validation校验框架:缺少请求体异常处理器*/@ExceptionHandler(HttpMessageNotReadableException.class)public ErrorResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {log.error(e.getMessage(), e);return ErrorResult.error(PARAMETER_EXCEPTION, "参数体不能为空");}/*** 兼容Validation校验框架:参数效验异常处理器*/@ExceptionHandler(MethodArgumentNotValidException.class)public ErrorResult parameterExceptionHandler(MethodArgumentNotValidException e) {log.error(e.getMessage(), e);// 获取异常信息BindingResult exceptions = e.getBindingResult();// 判断异常中是否有错误信息,如果存在就使⽤异常中的消息,否则使⽤默认消息if (exceptions.hasErrors()) {List<ObjectError> errors = exceptions.getAllErrors();if (!errors.isEmpty()) {// 这⾥列出了全部错误参数,按正常逻辑,只需要第⼀条错误即可FieldError fieldError = (FieldError) errors.get(0);return ErrorResult.error(PARAMETER_EXCEPTION, fieldError.getDefaultMessage());}}return ErrorResult.error(PARAMETER_EXCEPTION, "请求参数校验异常");}}接⼝调⽤@ResponseResult@GetMappingpublic User update() {// ⾮⾃定义的运⾏时异常long id = 10 / 0;return userService.queryById(id);}@ResponseResult@PostMappingpublic User insert() {// 抛出⾃定义的基础异常throw new BaseException();}@ResponseResult@DeleteMappingpublic boolean delete() {// 抛出⾃定义的业务异常throw new BizException(USER_NOT_EXIST_ERROR);}测试结果总结到此这篇关于SpringBoot中如何统⼀接⼝返回与全局异常处理的⽂章就介绍到这了,更多相关SpringBoot统⼀接⼝返回内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
