spring boot 提供了统一的异常处理机制,@ControllerAdvice, @ExceptionHandler两个注解,可以处理controller里抛出的异常,不要对每个controller方法进行try catch,如果你使用json或者返回固定的错误页面作为传输数据格式,普通的使用方法即可解决,由于我们服务端使用protobuf与客户端进行交互,每个controller方法的返回类型的泛型都是不固定的,于是做了一定的扩展,以适应每个controller的返回:
/** * 全局异常处理 * Created by mxl on 2016/9/2. */ @ControllerAdvice public class GlobalExceptionHandler { private static volatile Map<String, HandlerMapping> matchingBeans = null; private static volatile ApplicationContext context = null; private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 获取map * @return */ public static Map<String, HandlerMapping> getMatchingBeans (HttpServletRequest request) { if (matchingBeans != null) { return matchingBeans; } synchronized (GlobalExceptionHandler.class) { if (matchingBeans == null) { ApplicationContext context = getContext(request); matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); } return matchingBeans; } } /** * 获取context * @param request * @return */ public static ApplicationContext getContext (HttpServletRequest request) { if (context != null) { return context; } synchronized (GlobalExceptionHandler.class) { if (context == null) { context = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext()); } return context; } } @ExceptionHandler(value = GenericException.class) public ResponseEntity<?> GenericExceptionHandler(HttpServletRequest request, GenericException genericException) { try { HandlerMethod handlerMethod = null; //根据request请求解析出目标方法 Map<String, HandlerMapping> matchingBeans = getMatchingBeans(request); for (HandlerMapping hm : matchingBeans.values()) { HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { handlerMethod = (HandlerMethod)handler.getHandler(); break; } } //根据目标方法,根据反射,获取controller方法返回的protobuf对应的builder,并填装固定的异常返回格式 MessageOrBuilder builder = getBuilder(getReturnType(handlerMethod)); if (builder == null) { return null; } return createResult(builder, genericException); } catch (Exception ee) { ee.printStackTrace(); } return null; } @ExceptionHandler(value = Exception.class) public ResponseEntity<?> defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception { try { HandlerMethod handlerMethod = null; //根据request请求解析出目标方法 Map<String, HandlerMapping> matchingBeans = getMatchingBeans(request); for (HandlerMapping hm : matchingBeans.values()) { HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { handlerMethod = (HandlerMethod)handler.getHandler(); break; } } //根据目标方法,根据反射,获取controller方法返回的protobuf对应的builder,并填装固定的异常返回格式 MessageOrBuilder builder = getBuilder(getReturnType(handlerMethod)); return createResult(builder, new OperateFailureException("系统异常", Constants.Code.SERVER_ERROR)); } catch (Exception ee) { ee.printStackTrace(); logger.error(ee.getMessage()); } return null; } //利用反射获取填充builder private ResponseEntity<?> createResult (MessageOrBuilder messageOrBuilder, GenericException e) { try { Method successMethod = messageOrBuilder.getClass().getDeclaredMethod("setSuccess", boolean.class); successMethod.invoke(messageOrBuilder, false); Method msgMethod = messageOrBuilder.getClass().getDeclaredMethod("setMsg", String.class); msgMethod.invoke(messageOrBuilder, e.getMessage()); Method codeMethod = messageOrBuilder.getClass().getDeclaredMethod("setCode", int.class); codeMethod.invoke(messageOrBuilder, e.getErrorCode()); Method builderMethod = messageOrBuilder.getClass().getDeclaredMethod("build"); return ResponseEntity.ok(builderMethod.invoke(messageOrBuilder)); } catch (Exception ee) { e.printStackTrace(); logger.error(ee.getMessage()); } return null; } /** * 获取builder * @param returnType * @return */ public static MessageOrBuilder getBuilder (Type returnType) { try { Class returnClass = Class.forName(returnType.getTypeName()); Method builderMethod = returnClass.getDeclaredMethod("newBuilder"); return (MessageOrBuilder)builderMethod.invoke(returnClass); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 返回类型 * @param handlerMethod * @return */ public static Type getReturnType (HandlerMethod handlerMethod) { Type type = handlerMethod.getMethod().getAnnotatedReturnType().getType(); if (type instanceof ParameterizedType)/* 如果是泛型类型 */{ Type[] types = ((ParameterizedType) type) .getActualTypeArguments();// 泛型类型列表 return types[0]; } return null; } }
我们controller里是这样做返回的:
@RequestMapping(value = "creative/list", method = RequestMethod.POST) public ResponseEntity<FeedResponse> listCreative(RequestEntity<FeedRequest> requestEntity) { FeedResponse.Builder builder = FeedResponse.newBuilder(); FeedRequest feed = requestEntity.getBody(); PaginationParam paginationParam = new PaginationParam(feed.getStartCount(), feed.getMaxCount() + 1); SortParam sortParam; if (feed.hasOrderColumn() && feed.hasSort()) { sortParam = PagiSortUtils.createSortParam(feed.getOrderColumn(), feed.getSort()); } else { sortParam = new SortParam("update_time", "desc"); } List<Creative> creativeList = creativeService.findByUser(feed.getUid(), sortParam, paginationParam, PubStatus.DELETE.value); builder.addAllDataList( convertCreativeFeedList(creativeList.subList(0, Math.min(creativeList.size(), feed.getMaxCount())), true, null)); builder.setSuccess(true).setCode(Constants.Code.OK).setHasMore(creativeList.size() > feed.getMaxCount()); return ResponseEntity.ok(builder.build()); }
扩展的具体思路是, 异常捕捉方法中暴露了两个参数request, exception,扩展点在于如何获取每个controller方法返回值的泛型,以创建具体的protobuf返回到客户端, spring boot有一个SimpleMappingExceptionResolver可以扩展,重新此方法, 此方法暴露了HandlerMethod,但是返回格式固定为ModelAndView了,不符合我们的要求;使用主机的方式,去解析request,获取目标方法handlerMethod, 然后利用反射获取目标方法的返回值类型,然后创建返回值类型,做出返回值构建,返回
相关推荐
Spring Boot统一异常处理类,BaseResponse类就两个字段code和message。经测试,可以捕获所以异常,并返回指定json数据
spring boot 异常处理方案,github地址:https://github.com/chanjarster/spring-mvc-error-handling-example
Spring Boot 提供了统一的异常处理机制,通过使用 @ControllerAdvice 和 @ExceptionHandler 注解,可以实现对控制器层、Service 层、Dao 层以及 Spring 系统内定义的部分异常的统一处理。 在 Spring Boot 中,可以...
spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决...
Spring Boot 统一返回结果集,内容包括在了 spring aop、spring boot 全局异常处理、自定义异常、注解开发
获取Spring Boot 2微框架的可重用代码配方和代码段 了解Spring Boot 2如何与其他Spring API,工具和框架集成 访问Spring MVC和新的Spring Web Sockets,以实现更简单的Web开发 使用微服务进行Web服务开发并与Spring ...
Spring Boot自定义异常内容代码,用来自定义异常展示信息,添加需要展示的信息等,并满足自适应显示。浏览器访问出现异常返回 Hmtl页面,客户端访问出现异常返回 Json 数据。该 Demo 仅用作备份
主要介绍了Spring Boot异常处理静止trace,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Beginning Spring Boot 2 Beginning Spring Boot 2 Beginning Spring Boot 2
基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring ...
介绍一个基于Spring Boot 3.0、Spring Cloud 2022 & Alibaba的微服务RBAC权限管理系统。该系统可以实现微服务RBAC权限管理,通过RBAC权限管理机制对用户访问系统的权限进行限制,从而提高系统的安全性和可用性。同时...
Spring Cloud Gateway的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@...需要对异常信息进行处理,返回JSON格式的数据给客户端。下面先看实现的代码,后面再跟大家讲下需要注意的地方。
基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 ...
This book will help you understand what Spring Boot is, how Spring Boot helps you build Spring-based applications quickly and easily, and the inner workings of Spring Boot using easy-to-follow ...
Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...
Pro Spring Boot 2: An Authoritative Guide to Building Microservices, Web and Enterprise Applications, and Best Practices Quickly and productively develop complex Spring applications and microservices...
Spring Boot视频教程大合集,完美帮助你学习Spring Boot,内部有3套Spring Boot学习视频教程,另附一篇Security Oauth2.0认证授权视频教程
基于spring boot + maven + opencv 实现的图像深度学习Demo项目,包含车牌识别、人脸识别、证件识别等功能,贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点。 基于spring boot + maven + opencv ...
Spring boot使用的各种示例,以最简单、最实用为标准 spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-...