打造一款适合自己的快速开发框架-业务错误码规范及实践

4,066 阅读6分钟

前言

在编写业务代码的时候,时常需要定义不同的状态码来表示不同的执行结果。而一般主流的做法主要有以下两种:一、业务方法中定义统一的返回体,外层统一的返回体做全局处理;二、业务方法中抛出自定义异常, 外层做统一的异常处理。这里不对这两者进行对比,感兴趣的同学,可以去了解一下。这里主要讲的是第二种方式,也是本快速开发框架使用的方式。

错误码定义及规范

错误码枚举

仅一个错误码字段可能还不足以描述一个错误码,所以一般会单独定义枚举类来描述错误码。这里如下定义:

属性类型说明
valueint错误码值
nameString错误码名称或描述

错误码注解

错误码定义好后,需要添加自定义注解说明,方便系统启动后扫描加载到内存并提供渲染页查看。

属性类型说明
nameString模块名-英文
valueString错误码说明
bizCodeint业务码
minint最小值
maxint最大值

错误码规范

不同的业务,错误码就不一样,所以一般每做一个业务,需要提前申请或者定义一下错误码范围。在这里使用8位数字组成的错误码。如:80000001、99990401等。一般来说,建议一个业务类,对应一个错误码枚举类。不过如果需要判断的业务不多,可以一个模块中的多个业务类共用一个错误码枚举类。

返回结果样例

成功

http status: 200

{
	"code": 0,
	"data": {
	},
	"msg": "操作成功"
}

错误

http status: 200

{
  "code": 80009001,
  "msg": "用户不存在"
}

开始编码

目录结构

只罗列需要新增或修改的文件

├── mldong-admin  管理端接口
    ├── emuns
    	src/main/java
      └──com.mldong.modules.sys
        └── controller 控制层
        	└── SysUserController.java
        ├── enums
        	└── SysErrEnum.java
        └── service 服务层
        	├── impl
        		└── SysUserServiceImpl
        	└── SysUserService.java
├── mldong-common  工具类及通用代码
	├── src/main/java
	  ├── com.mldong.common.base
	  	└── CommonError.java
	  ├── com.mldong.common.base.constant
	  	└── GlobalErrEnum.java
      ├── com.mldong.common.annotation
      	└── ErrEnum.java
      └──com.mldong.common.exception
        ├── BizException.java
     	└── DefaultExceptionHandler.java
	└── pom.xml
├── mldong-generator  代码生成器
└── mldong-mapper 持久层

文件说明

  • mldong-common/com/mldong/common/base/CommonError.java
package com.mldong.common.base;
/**
 * 错误码接口-所有的错误码都要实现该接口
 * @author mldong
 *
 */
public interface CommonError {
	int getValue();
    String getName();
}

  • mldong-common/com/mldong/annotation/ErrEnum.java
package com.mldong.common.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 错误码枚举注解,方便收集错误码描述,统一查看的
 * @author mldong
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ErrEnum {
	/**
	 * 名称
	 * @return
	 */
	String name();
	/**
	 * 说明
	 * @return
	 */
	String value();
	/**
	 * 业务码
	 * @return
	 */
	int bizCode();
	/**
	 * 最小值
	 * @return
	 */
	int min();
	/**
	 * 最大值
	 * @return
	 */
	int max();
}
  • mldong-common/com/mldong/common/annotation/GlobalErrEnum.java
package com.mldong.common.base.constant;

import com.mldong.common.annotation.ErrEnum;
import com.mldong.common.base.CommonError;
/**
 * 全局错误码
 * @author mldong
 *
 */
@ErrEnum(name="global",value="全局错误码",bizCode=9999,min=0,max=1000)
public enum GlobalErrEnum implements CommonError {
	/**
	 * 参数异常
	 */
	GL99990100(99990100, "参数异常"),
	/**
	 * 无访问权限
	 */
	GL99990401(99990401, "无访问权限"),
	/**
	 * 未知异常
	 */
	GL99990500(99990500, "未知异常"),
	/**
	 * 无权访问
	 */
	GL99990403(99990403, "无权访问"),
	/**
	 * 找不到指定资源
	 */
	GL99990404(99990404, "找不到指定资源"),
	/**
	 * 注解使用错误
	 */
	GL99990001(99990001, "注解使用错误"),
	/**
	 * 微服务不在线,或者网络超时
	 */
	GL99990002(99990002, "微服务不在线,或者网络超时"),
	/**
	 * 没有数据
	 */
	GL99990003(99990003, "没有数据"),
	/**
	 * 演示账号,无写权限
	 */
	GL99990004(99990004, "演示账号,无写权限"),
	/**
	 * 数据库插入异常
	 */
	GL99990005(99990005, "数据库插入异常"),
	/**
	 * 文件后辍不允许
	 */
	GL99990006(99990006, "文件后辍不允许"),
	;
	
	private GlobalErrEnum(int value, String name){
		this.value = value;
		this.name = name;
	} 
	private String name;

	private int value;

	public int getValue() {
		return value;
	}
	public String getName() {
		return name;
	}
}
  • mldong-common/com/mldong/common/exception/BizException.java
package com.mldong.common.exception;

import com.mldong.common.base.CommonError;
/**
 * 业务错码异常类
 * @author mldong
 *
 */
public class BizException extends RuntimeException{

	private static final long serialVersionUID = -8059304617449091328L;
	/**
	 * 错误
	 */
	private CommonError error;
	public BizException(CommonError error) {
		super("[" + error.getValue() + "]" + error.getName());
		this.error = error;
	}
	public CommonError getError() {
		return error;
	}
	public void setError(CommonError error) {
		this.error = error;
	}
}
  • mldong-common/com/mldong/common/exception/DefaultExceptionHandler.java

新增BizException异常处理

package com.mldong.common.exception;

import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.mldong.common.base.CommonError;
import com.mldong.common.base.CommonResult;
 /**
  * 全局异常处理类
  * @author mldong
  *
  */
@ControllerAdvice
public class DefaultExceptionHandler {
 
    private static Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);  
    /**
     * 服务层异常
     * @param e
     * @return
     */
    @ExceptionHandler(BizException.class)
    @ResponseBody
    public CommonResult<CommonError> serviceExceptionHandler(BizException e) {
    	log.error("服务层异常:", e);
    	return CommonResult.fail(e.getError());
    }

    /**
     * 控制层参数校验异常
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class) 
    @ResponseBody
    public CommonResult<?> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
    	log.error("参数校验异常:{}", e.getMessage());
    	;
    	String errorMsg = String.join(",", e.getBindingResult().getAllErrors().stream().map(item->{
    		return item.getDefaultMessage();
    	}).collect(Collectors.toList()));
    	return CommonResult.fail(errorMsg, e.getBindingResult());
    }
    /**
     * 其他异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class) 
    @ResponseBody
    public CommonResult<?> excetionHandler(Exception e){
    	log.error("未捕获异常:", e);
    	return CommonResult.fail(e.getMessage(), null);
    }
}

  • mldong-admin/com/mldong/modules/sys/emuns/SysErrEnum.java
package com.mldong.modules.sys.enums;

import com.mldong.common.annotation.ErrEnum;
import com.mldong.common.base.CommonError;
/**
 * 8000 9001-9999
 * sys模块错误码定义
 * @author mldong
 *
 */
@ErrEnum(name="sys",value="系统管理",bizCode=8000,min=9001,max=9999)
public enum SysErrEnum implements CommonError {
	/**
	 * 用户不存在
	 */
	SYS80000001(80009001, "用户不存在"),
	/**
	 * 用户名或者密码错误
	 */
	SYS80000002(80009002, "用户名或者密码错误"),
	/**
	 * 登录次数太多
	 */
	SYS80000003(80009003, "登录次数太多"),
	/**
	 * 用户已被锁定
	 */
	SYS80000004(80009004, "用户已被锁定"),
	/**
	 * 两密码不一致
	 */
	SYS80000005(80009005,"两密码不一致"),
	/**
	 * 旧密码错误
	 */
	SYS80000006(80009006,"旧密码错误"),
	/**
	 * 用户名已存在
	 */
	SYS80000007(80009007, "用户名已存在")
	;
	public final int value;
	public final String name;
	SysErrEnum(int value,String name) {
		this.value = value;
		this.name = name;
	}
	@Override
	public int getValue() {
		return this.value;
	}
	@Override
	public String getName() {
		return this.name;
	}
}
  • mldong-admin/com/mldong/modules/sys/service/impl/SysUserServiceImpl.java

业务层使用样例

package com.mldong.modules.sys.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mldong.common.base.CommonPage;
import com.mldong.common.exception.BizException;
import com.mldong.modules.sys.entity.SysUser;
import com.mldong.modules.sys.enums.SysErrEnum;
import com.mldong.modules.sys.mapper.SysUserMapper;
import com.mldong.modules.sys.service.SysUserService;
@Service
public class SysUserServiceImpl implements SysUserService{
	@Autowired
	private SysUserMapper sysUserMapper;
	@Override
	public int save(SysUser param) {
		SysUser q = new SysUser();
		q.setUserName(param.getUserName());
		SysUser user = sysUserMapper.selectOne(q);
		if(null!=user) {
			// 用户已存在
			throw new BizException(SysErrEnum.SYS80000007);
		}
		return sysUserMapper.insertSelective(param);
	}
	@Override
	public int update(SysUser param) {
		return sysUserMapper.updateByPrimaryKeySelective(param);
	}

	@Override
	public int delete(Long id) {
		return sysUserMapper.deleteByPrimaryKey(id);
	}

	@Override
	public SysUser get(Long id) {
		return sysUserMapper.selectByPrimaryKey(id);
	}

	@Override
	public CommonPage<SysUser> list(SysUser t, int pageNum, int pageSize) {
		Page<SysUser> page = PageHelper.startPage(pageNum, pageSize,true);
		sysUserMapper.select(t);
		return CommonPage.toPage(page);
	}
}

启动运行项目

MldongAdminApplication.java

右键->Run As -> Java Application

访问演示

项目源码地址

  • 后端

gitee.com/mldong/mldo…

  • 前端

gitee.com/mldong/mldo…

相关文章

打造一款适合自己的快速开发框架-先导篇

打造一款适合自己的快速开发框架-后端脚手架搭建

打造一款适合自己的快速开发框架-集成mapper

打造一款适合自己的快速开发框架-集成swaggerui和knife4j

打造一款适合自己的快速开发框架-通用类封装之统一结果返回、统一异常处理