`

spring boot 异常处理扩展(返回格式protofuf)

阅读更多

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统一异常处理类

    Spring Boot统一异常处理类,BaseResponse类就两个字段code和message。经测试,可以捕获所以异常,并返回指定json数据

    spring boot 异常处理方案

    spring boot 异常处理方案,github地址:https://github.com/chanjarster/spring-mvc-error-handling-example

    Java异常介绍及Spring Boot统一异常处理

    Spring Boot 提供了统一的异常处理机制,通过使用 @ControllerAdvice 和 @ExceptionHandler 注解,可以实现对控制器层、Service 层、Dao 层以及 Spring 系统内定义的部分异常的统一处理。 在 Spring Boot 中,可以...

    Spring boot 示例 官方 Demo

    spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决...

    Spring Boot Json 返回格式 + 全局异常处理 + 参数验证注解

    Spring Boot 统一返回结果集,内容包括在了 spring aop、spring boot 全局异常处理、自定义异常、注解开发

    Spring Boot 2 Recipes

    获取Spring Boot 2微框架的可重用代码配方和代码段 了解Spring Boot 2如何与其他Spring API,工具和框架集成 访问Spring MVC和新的Spring Web Sockets,以实现更简单的Web开发 使用微服务进行Web服务开发并与Spring ...

    Spring Boot自定义异常内容展示代码.zip

    Spring Boot自定义异常内容代码,用来自定义异常展示信息,添加需要展示的信息等,并满足自适应显示。浏览器访问出现异常返回 Hmtl页面,客户端访问出现异常返回 Json 数据。该 Demo 仅用作备份

    Spring Boot异常处理静止trace

    主要介绍了Spring Boot异常处理静止trace,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    Beginning Spring Boot 2

    Beginning Spring Boot 2 Beginning Spring Boot 2 Beginning Spring Boot 2

    基于 Spring Boot + MySQL 开发的博客系统源码.zip

    基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring ...

    基于Spring Boot 3.0、 Spring Cloud 2022 & Alibaba 的微服务RBAC 权限管理系统

    介绍一个基于Spring Boot 3.0、Spring Cloud 2022 & Alibaba的微服务RBAC权限管理系统。该系统可以实现微服务RBAC权限管理,通过RBAC权限管理机制对用户访问系统的权限进行限制,从而提高系统的安全性和可用性。同时...

    Spring Cloud Gateway的全局异常处理

    Spring Cloud Gateway的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@...需要对异常信息进行处理,返回JSON格式的数据给客户端。下面先看实现的代码,后面再跟大家讲下需要注意的地方。

    基于spring boot餐厅管理系统源码.zip

    基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 ...

    Beginning Spring Boot 2 Applications and Microservices with the Spring Framework

    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 cloud和Spring boot介绍

    Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...

    Pro Spring Boot 2第2版-2009-EPUB版

    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,百度网盘

    Spring Boot视频教程大合集,完美帮助你学习Spring Boot,内部有3套Spring Boot学习视频教程,另附一篇Security Oauth2.0认证授权视频教程

    基于spring boot + maven + opencv 实现的图像深度学习Demo项目.zip

    基于spring boot + maven + opencv 实现的图像深度学习Demo项目,包含车牌识别、人脸识别、证件识别等功能,贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点。 基于spring boot + maven + opencv ...

    Spring Boot Examples

    Spring boot使用的各种示例,以最简单、最实用为标准 spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-...

Global site tag (gtag.js) - Google Analytics