美文网首页javaWeb学习springSpring Cloud
SpringCloud微服务实战——搭建企业级开发框架(七):自

SpringCloud微服务实战——搭建企业级开发框架(七):自

作者: 全栈程序猿 | 来源:发表于2020-11-11 08:55 被阅读0次

      平时开发过程中,无可避免我们需要处理各类异常,所以这里我们在公共模块中自定义统一异常,Spring Boot 提供 @RestControllerAdvice 注解统一异常处理,我们在GitEgg_Platform中新建gitegg-platform-boot子工程,此工程主要用于Spring Boot相关功能的自定义及扩展。
    1、修改gitegg-platform-boot的pom.xml,添加spring-boot-starter-web和swagger依赖,设置optional为true,让这个包在项目之间依赖不传递。

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>com.gitegg.platform</groupId>
                <artifactId>gitegg-platform-swagger</artifactId>
                <optional>true</optional>
            </dependency>
    

    2、自定义通用响应消息类,Result和PageResult,一个是普通响应消息,一个是分页响应消息。
    Result类:

    package com.gitegg.platform.boot.common.base;
    
    import com.gitegg.platform.boot.common.enums.ResultCodeEnum;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.*;
    
    /**
     * @ClassName: Result
     * @Description: 自定义通用响应类
     * @author GitEgg
     * @date 2020年09月19日 下午9:24:50
     */
    @ApiModel(description = "通用响应类")
    @Getter
    @ToString
    public class Result<T> {
    
        @ApiModelProperty(value = "是否成功", required = true)
        private boolean success;
        
        @ApiModelProperty(value ="响应代码", required = true)
        private int code;
    
        @ApiModelProperty(value ="提示信息", required = true)
        private String msg;
    
        @ApiModelProperty(value ="响应数据")
        private T data;
        
        /**
         * 
         * @param code
         * @param data
         * @param msg
         */
        private Result(int code, T data, String msg) {
            this.success = ResultCodeEnum.SUCCESS.code == code;
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    
        /**
         * 
         * @param resultCodeEnum
         */
        private Result(ResultCodeEnum resultCodeEnum ) {
            this(resultCodeEnum.code, null, resultCodeEnum.msg);
        }
    
        /**
         * 
         * @param resultCodeEnum
         * @param msg
         */
        private Result(ResultCodeEnum resultCodeEnum , String msg) {
            this(resultCodeEnum, null, msg);
        }
    
        /**
         * 
         * @param resultCodeEnum
         * @param data
         */
        private Result(ResultCodeEnum resultCodeEnum , T data) {
            this(resultCodeEnum, data, resultCodeEnum.msg);
        }
    
        /**
         * 
         * @param resultCodeEnum
         * @param data
         * @param msg
         */
        private Result(ResultCodeEnum resultCodeEnum , T data, String msg) {
            this(resultCodeEnum.code, data, msg);
        }
    
        /**
         * 
         *
         * @param data 数据
         * @param <T>  T 响应数据
         * @
         */
        public static <T> Result<T> data(T data) {
            return data(data, ResultCodeEnum.SUCCESS.msg);
        }
    
        /**
         * 
         *
         * @param data 数据
         * @param msg  消息
         * @param <T>  T 响应数据
         * @
         */
        public static <T> Result<T> data(T data, String msg) {
            return data(ResultCodeEnum.SUCCESS.code, data, msg);
        }
    
        /**
         * 
         *
         * @param code 状态码
         * @param data 数据
         * @param msg  消息
         * @param <T>  T 响应数据
         * @
         */
        public static <T> Result<T> data(int code, T data, String msg) {
            return new Result<>(code, data, msg);
        }
    
        /**
         * 返回Result
         *
         * @param 
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> success() {
            return new Result<>(ResultCodeEnum.SUCCESS);
        }
        
        /**
         * 返回Result
         *
         * @param msg 消息
         * @param <T> T 响应数据
         * @返回Result
         */
        public static <T> Result<T> success(String msg) {
            return new Result<>(ResultCodeEnum.SUCCESS, msg);
        }
    
        /**
         * 返回Result
         *
         * @param 
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> success(ResultCodeEnum resultCodeEnum ) {
            return new Result<>(resultCodeEnum);
        }
    
        /**
         * 返回Result
         *
         * @param 
         * @param msg   提示信息
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> success(ResultCodeEnum resultCodeEnum , String msg) {
            return new Result<>(resultCodeEnum, msg);
        }
        
        /**
         * 返回Result
         *
         * @param <T> T 响应数据
         * @返回Result
         */
        public static <T> Result<T> error() {
            return new Result<>(ResultCodeEnum.ERROR, ResultCodeEnum.ERROR.msg);
        }
    
        /**
         * 返回Result
         *
         * @param msg 消息
         * @param <T> T 响应数据
         * @返回Result
         */
        public static <T> Result<T> error(String msg) {
            return new Result<>(ResultCodeEnum.ERROR, msg);
        }
    
    
        /**
         * 返回Result
         *
         * @param code 状态码
         * @param msg  消息
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> error(int code, String msg) {
            return new Result<>(code, null, msg);
        }
    
        /**
         * 返回Result
         *
         * @param 
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> error(ResultCodeEnum resultCodeEnum ) {
            return new Result<>(resultCodeEnum);
        }
    
        /**
         * 返回Result
         *
         * @param 
         * @param msg   提示信息
         * @param <T>  T 响应数据
         * @返回Result
         */
        public static <T> Result<T> error(ResultCodeEnum resultCodeEnum , String msg) {
            return new Result<>(resultCodeEnum, msg);
        }
        
        /**
         * 
         * @param <T>
         * @param flag
         * @return
         */
        public static <T> Result<T> result(boolean flag) {
            return flag ? Result.success("操作成功") : Result.error("操作失败");
        }
    
    }
    

    PageResult类:

    package com.gitegg.platform.boot.common.base;
    
    import java.util.List;
    
    import com.gitegg.platform.boot.common.enums.ResultCodeEnum;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    /**
     * @ClassName: PageResult
     * @Description: 通用分页返回
     * @author GitEgg
     * @date
     * @param <T>
     */
    @Data
    @ApiModel("通用分页响应类")
    public class PageResult<T> {
    
        @ApiModelProperty(value = "是否成功", required = true)
        private boolean success;
    
        @ApiModelProperty(value ="响应代码", required = true)
        private int code;
    
        @ApiModelProperty(value ="提示信息", required = true)
        private String msg;
    
        @ApiModelProperty(value ="总数量", required = true)
        private long count;
    
        @ApiModelProperty(value ="分页数据")
        private List<T> data;
    
        public PageResult(long total, List<T> rows) {
            this.count = total;
            this.data = rows;
            this.code = ResultCodeEnum.SUCCESS.code;
            this.msg = ResultCodeEnum.SUCCESS.msg;
        }
    }
    
    

    3、自定义通用响应消息枚举类ResultCodeEnum。

    package com.gitegg.platform.boot.common.enums;
    
    
    /**
     * @ClassName: ResultCodeEnum
     * @Description: 自定义返回码枚举
     * @author GitEgg
     * @date 2020年09月19日 下午11:49:45
     */
    public enum ResultCodeEnum {
    
        /**
         * 成功
         */
        SUCCESS(200, "操作成功"),
    
        /**
         * 系统错误
         */
        ERROR(500, "系统错误"),
    
        /**
         * 操作失败
         */
        FAILED(101, "操作失败"),
    
        /**
         * 未登录/登录超时
         */
        UNAUTHORIZED(102, "登录超时"),
    
        /**
         * 参数错误
         */
        PARAM_ERROR(103, "参数错误"),
    
        /**
         * 参数错误-已存在
         */
        INVALID_PARAM_EXIST(104, "请求参数已存在"),
    
        /**
         * 参数错误
         */
        INVALID_PARAM_EMPTY(105, "请求参数为空"),
    
        /**
         * 参数错误
         */
        PARAM_TYPE_MISMATCH(106, "参数类型不匹配"),
    
        /**
         * 参数错误
         */
        PARAM_VALID_ERROR(107, "参数校验失败"),
    
        /**
         * 参数错误
         */
        ILLEGAL_REQUEST(108, "非法请求"),
    
        /**
         * 验证码错误
         */
        INVALID_VCODE(204, "验证码错误"),
    
        /**
         * 用户名或密码错误
         */
        INVALID_USERNAME_PASSWORD(205, "账号或密码错误"),
    
        /**
         *
         */
        INVALID_RE_PASSWORD(206, "两次输入密码不一致"),
    
        /**
         * 用户名或密码错误
         */
        INVALID_OLD_PASSWORD(207, "旧密码错误"),
    
        /**
         * 用户名重复
         */
        USERNAME_ALREADY_IN(208, "用户名已存在"),
    
        /**
         * 用户不存在
         */
        INVALID_USERNAME(209, "用户名不存在"),
    
        /**
         * 角色不存在
         */
        INVALID_ROLE(210, "角色不存在"),
    
        /**
         * 角色不存在
         */
        ROLE_USED(211, "角色使用中,不可删除"),
    
        /**
         * 没有权限
         */
        NO_PERMISSION(403, "当前用户无该接口权限");
    
        public int code;
    
        public String msg;
    
        ResultCodeEnum(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    

    4、自定义异常类BusinessException和SystemException

    package com.gitegg.platform.boot.common.exception;
    
    import com.gitegg.platform.boot.common.enums.ResultCodeEnum;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.Getter;
    import lombok.Setter;
    
    /**
     * @ClassName: BusinessException
     * @Description: 业务处理异常
     * @author GitEgg
     * @date
     */
    @Getter
    @Setter
    public class BusinessException extends RuntimeException {
    
        private int code;
    
        private String msg;
    
        public BusinessException() {
            this.code = ResultCodeEnum.FAILED.code;
            this.msg = ResultCodeEnum.FAILED.msg;
        }
    
        public BusinessException(String message) {
            this.code = ResultCodeEnum.FAILED.code;
            this.msg = message;
        }
    
        public BusinessException(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public BusinessException(Throwable cause) {
            super(cause);
        }
    
        public BusinessException(String message, Throwable cause) {
            super(message, cause);
        }
    
    }
    
    package com.gitegg.platform.boot.common.exception;
    
    import com.gitegg.platform.boot.common.enums.ResultCodeEnum;
    import lombok.Getter;
    
    /**
     * @ClassName: SystemException
     * @Description: 系统处理异常
     * @author GitEgg
     * @date
     */
    @Getter
    public class SystemException extends RuntimeException {
    
        private int code;
    
        private String msg;
    
        public SystemException() {
            this.code = ResultCodeEnum.ERROR.code;
            this.msg = ResultCodeEnum.ERROR.msg;
        }
    
        public SystemException(String message) {
            this.code = ResultCodeEnum.ERROR.code;
            this.msg = message;
        }
    
        public SystemException(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public SystemException(Throwable cause) {
            super(cause);
        }
    
        public SystemException(String message, Throwable cause) {
            super(message, cause);
        }
    
    }
    

    5、自定义统一异常处理类GitEggControllerAdvice.java

    package com.gitegg.platform.boot.common.advice;
    
    import com.gitegg.platform.boot.common.base.Result;
    import com.gitegg.platform.boot.common.enums.ResultCodeEnum;
    import com.gitegg.platform.boot.common.exception.BusinessException;
    import com.gitegg.platform.boot.common.exception.SystemException;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.ui.Model;
    import org.springframework.web.HttpMediaTypeNotAcceptableException;
    import org.springframework.web.HttpMediaTypeNotSupportedException;
    import org.springframework.web.HttpRequestMethodNotSupportedException;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.MissingPathVariableException;
    import org.springframework.web.bind.MissingServletRequestParameterException;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.InitBinder;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
    import org.springframework.web.servlet.NoHandlerFoundException;
    
    import javax.annotation.PostConstruct;
    import javax.servlet.http.HttpServletRequest;
    import javax.validation.ConstraintViolationException;
    
    @Slf4j
    @RestControllerAdvice
    public class GitEggControllerAdvice {
    
        /**
         * 服务名
         */
        @Value("${spring.application.name}")
        private String serverName;
    
        /**
         * 微服务系统标识
         */
        private String errorSystem;
    
        @PostConstruct
        public void init() {
            this.errorSystem = new StringBuffer()
                    .append(this.serverName)
                    .append(": ").toString();
        }
    
        /**
         * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
         */
        @InitBinder
        public void initBinder(WebDataBinder binder) {
    
        }
    
        /**
         * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
         */
        @ModelAttribute
        public void addAttributes(Model model) {
    
        }
    
        /**
         * 全局异常捕捉处理
         */
        @ExceptionHandler(value = {Exception.class})
        public Result handlerException(Exception exception, HttpServletRequest request) {
            log.error("请求路径uri={},系统内部出现异常:{}", request.getRequestURI(), exception);
            Result result = Result.error(ResultCodeEnum.ERROR, errorSystem + exception.toString());
            return result;
        }
    
        /**
         * 非法请求异常
         */
        @ExceptionHandler(value = {
                HttpMediaTypeNotAcceptableException.class,
                HttpMediaTypeNotSupportedException.class,
                HttpRequestMethodNotSupportedException.class,
                MissingServletRequestParameterException.class,
                NoHandlerFoundException.class,
                MissingPathVariableException.class,
                HttpMessageNotReadableException.class
        })
        public Result handlerSpringAOPException(Exception exception) {
            Result result = Result.error(ResultCodeEnum.ILLEGAL_REQUEST, errorSystem + exception.getMessage());
            return result;
        }
    
        /**
         * 非法请求异常-参数类型不匹配
         */
        @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
        public Result handlerSpringAOPException(MethodArgumentTypeMismatchException exception) {
            Result result = Result.error(ResultCodeEnum.PARAM_TYPE_MISMATCH, errorSystem + exception.getMessage());
            return result;
        }
    
        /**
         * 非法请求-参数校验
         */
        @ExceptionHandler(value = {MethodArgumentNotValidException.class})
        public Result handlerMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
            //获取异常字段及对应的异常信息
            StringBuffer stringBuffer = new StringBuffer();
            methodArgumentNotValidException.getBindingResult().getFieldErrors().stream()
                    .map(t -> t.getField()+"=>"+t.getDefaultMessage()+" ")
                    .forEach(e -> stringBuffer.append(e));
            String errorMessage = stringBuffer.toString();
            Result result = Result.error(ResultCodeEnum.PARAM_VALID_ERROR, errorSystem + errorMessage);
            return result;
        }
    
        /**
         * 非法请求异常-参数校验
         */
        @ExceptionHandler(value = {ConstraintViolationException.class})
        public Result handlerConstraintViolationException(ConstraintViolationException constraintViolationException) {
            String errorMessage = constraintViolationException.getLocalizedMessage();
            Result result = Result.error(ResultCodeEnum.PARAM_VALID_ERROR, errorSystem + errorMessage);
            return result;
        }
    
        /**
         * 自定义业务异常-BusinessException
         */
        @ExceptionHandler(value = {BusinessException.class})
        public Result handlerCustomException(BusinessException exception) {
            String errorMessage = exception.getMsg();
            Result result = Result.error(exception.getCode(), errorSystem + errorMessage);
            return result;
        }
    
        /**
         * 自定义系统异常-SystemException
         */
        @ExceptionHandler(value = {SystemException.class})
        public Result handlerCustomException(SystemException exception) {
            String errorMessage = exception.getMsg();
            Result result = Result.error(exception.getCode(), errorSystem + errorMessage);
            return result;
        }
    
    }
    
    

    6、重新将GitEgg-Platform进行install,在GitEgg-Cloud中的gitegg-service引入gitegg-platform-boot

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>GitEgg-Cloud</artifactId>
            <groupId>com.gitegg.cloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>gitegg-service</artifactId>
        <packaging>pom</packaging>
        <modules>
            <module>gitegg-service-base</module>
            <module>gitegg-service-bigdata</module>
            <module>gitegg-service-system</module>
        </modules>
    
        <dependencies>
            <!-- gitegg Spring Boot自定义及扩展 -->
            <dependency>
                <groupId>com.gitegg.platform</groupId>
                <artifactId>gitegg-platform-boot</artifactId>
            </dependency>
            <!-- gitegg数据库驱动及连接池 -->
            <dependency>
                <groupId>com.gitegg.platform</groupId>
                <artifactId>gitegg-platform-db</artifactId>
            </dependency>
            <!-- gitegg mybatis-plus -->
            <dependency>
                <groupId>com.gitegg.platform</groupId>
                <artifactId>gitegg-platform-mybatis</artifactId>
            </dependency>
            <!-- gitegg swagger2-knife4j -->
            <dependency>
                <groupId>com.gitegg.platform</groupId>
                <artifactId>gitegg-platform-swagger</artifactId>
            </dependency>
            <!-- spring boot web核心包 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- spring boot 健康监控 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    

    7、修改SystemController.java、ISystemService.java和SystemServiceImpl.java增加异常处理的测试代码

    SystemController.java:

    package com.gitegg.service.system.controller;
    
    import com.gitegg.platform.boot.common.base.Result;
    import com.gitegg.platform.boot.common.exception.BusinessException;
    import com.gitegg.service.system.service.ISystemService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.AllArgsConstructor;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "system")
    @AllArgsConstructor
    @Api(tags = "gitegg-system")
    public class SystemController {
    
        private final ISystemService systemService;
    
        @GetMapping(value = "list")
        @ApiOperation(value = "system list接口")
        public Object list() {
            return systemService.list();
        }
    
    
        @GetMapping(value = "page")
        @ApiOperation(value = "system page接口")
        public Object page() {
            return systemService.page();
        }
    
        @GetMapping(value = "exception")
        @ApiOperation(value = "自定义异常及返回测试接口")
        public Result<String> exception() {
            return Result.data(systemService.exception());
        }
    }
    
    

    ISystemService.java:

    package com.gitegg.service.system.service;
    
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.gitegg.service.system.entity.SystemTable;
    
    import java.util.List;
    
    public interface ISystemService {
    
        List<SystemTable> list();
    
        Page<SystemTable> page();
    
        String exception();
    }
    
    

    SystemServiceImpl.java:

    package com.gitegg.service.system.service.impl;
    
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.gitegg.platform.boot.common.exception.BusinessException;
    import com.gitegg.service.system.entity.SystemTable;
    import com.gitegg.service.system.mapper.SystemTableMapper;
    import com.gitegg.service.system.service.ISystemService;
    import lombok.AllArgsConstructor;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     *
     */
    @Service
    @AllArgsConstructor
    public class SystemServiceImpl implements ISystemService {
    
        private final SystemTableMapper systemTableMapper;
    
        @Override
        public List<SystemTable> list() {
            return systemTableMapper.list();
        }
    
        @Override
        public Page<SystemTable> page() {
            Page<SystemTable> page = new Page<>(1, 10);
            List<SystemTable> records = systemTableMapper.page(page);
            page.setRecords(records);
            return page;
        }
    
        @Override
        public String exception() {
            throw new BusinessException("自定义异常");
    //        return "成功获得数据";
        }
    }
    
    

    8、运行GitEggSystemApplication,打开浏览器访问:http://127.0.0.1:8001/doc.html,然后点击左侧的异常处理接口,使用Swagger2进行测试,即可看到结果

    image.png

    本文源码在https://gitee.com/wmz1930/GitEgg 的chapter-07分支。

    GitEgg-Cloud是一款基于SpringCloud整合搭建的企业级微服务应用开发框架,开源项目地址:

    Gitee: https://gitee.com/wmz1930/GitEgg
    GitHub: https://github.com/wmz1930/GitEgg

    欢迎感兴趣的小伙伴Star支持一下。

    相关文章

      网友评论

        本文标题:SpringCloud微服务实战——搭建企业级开发框架(七):自

        本文链接:https://www.haomeiwen.com/subject/ffhrsktx.html