异常、错误码、异常的设计, 脱离了UML图来说, 都是耍流氓, 因此我们依照我们的系统架构图及UML设计图进行分析设计。
因日志设计依托于系统设计层面的, 时间关系仅做简要编写。
系统架构图:
错误码设计:
我们的架构分为公共模块、后台管理模块、票务模块、订单模块、用户中心、支付中心、通知中心, 因此我们针对不同模块进行不同的错误码设计。
后台管理方面, 因为用了开源的后台管理框架, 我们不再重新设计,因此主要实现的功能为:
- 车次维护
- 车次类别维护
- 时刻表维护
- 站点维护
- 车厢维护
- 车辆维护
错误码 | 中文描述 | 说明 |
---|---|---|
00000 | 处理成功 | |
99999 | 系统异常 | 系统错误、各种异常 |
00001 | 查无记录 | |
10001 | 车次新增失败 | |
10002 | 车次修改失败 | |
10003 | 车次删除失败 | |
10011 | 车次类别新增失败 | |
10012 | 车次类别修改失败 | |
10013 | 车次类别删除失败 | |
10021 | 时刻表新增失败 | |
10022 | 时刻表修改失败 | |
10023 | 时刻表删除失败 | |
10031 | 站点新增失败 | |
10032 | 站点修改失败 | |
10033 | 站点删除失败 | |
10041 | 车厢新增失败 | |
10042 | 车厢修改失败 | |
10043 | 车厢删除失败 | |
10051 | 车辆维护新增失败 | |
10052 | 车辆维护修改失败 | |
10053 | 车辆维护删除失败 |
用户中心鉴权模块错误码定义
在用户鉴权模块, 我们主要实现的功能为: 用户注册、用户登录、登出、实名认证、用户信息维护
错误码 | 中文描述 | 说明 |
---|---|---|
20001 | 注册失败,错误消息{%s} | |
20011 | 用户登录失败, 错误信息{%s} | |
20021 | 登出失败,失败信息{%s} | |
20031 | 实名认证失败,失败信息{%s} | |
20041 | 用户信息维护查询失败 | |
20051 | 用户信息维护修改失败, 失败信息{%s} |
票务模块、订单模块、用户中心、支付中心、通知中心
票务模块实现功能: 定时车票生成, 车票查询,购票,入站, 出站。
订单模块实现:订单查询、订单支付、改签、退票
支付中心实现支付服务, 由订单模块触发调用
通知中心, 实现各种通知服务, 由订单和票务模块进行触发调用
错误码 | 中文描述 | 说明 |
---|---|---|
30001 | 无可用车次生成余票 | |
30002 | 车次余票生成失败 | |
40001 | 车票查询条件错误, 请检查输入 | |
40002 | 无票 | |
40011 | 购票超时, 请稍后查看我的订单或者重新下单 | |
40012 | 购票失败, 余票不足, 请重新查询 | |
50001 | 订单查询系统繁忙,请稍后再试 | |
50101 | 支付失败, {%s} | |
50102 | 支付超时, 请稍后查看订单状态 | |
50201 | 改签系统无响应, 请稍后查看订单状态 | |
50301 | 退票系统无响应, 请稍后查看订单状态 | |
60001 | 支付中心处理失败,{%s} | |
60002 | 支付中心处理超时 | |
70001 | 通知失败,{%s} | |
70002 | 通知处理超时,{%s} |
日志设计:
日志方面, 我们遵循日志规约:从日志的功能、时效、输出方面做出约定。日志记录使用slf4j,使用它的默认实现, 配置方面依照不同模块记录不同日志, 及不同的日志打印级别。当天日志命名以 “应用名.log"来保存,过往日志命名:以“logname.log.yyyy-mm-dd”命名。
- 公共模块
- 日志存15天
- 后台管理模块
- 日志存15天, 相关操作记录落库落表
- 票务模块
- 日志存30天
- 订单模块
- 日志存180天,日志级别为info, 需记录订单每个状态变更的日志, 记录相关的上下文信息
- 用户中心
- 日志存30天
- 支付中心
- 日志存180天,日志级别为info, 需记录订单每个状态变更的日志, 记录相关的上下文信息
- 通知中心
- 日志存30天
异常设计:
异常方面, 我们开发过程中凡是涉及IO操作, 各种转换等操作的时候, 都应做异常捕获, 并做对应处理。
异常抛出与捕获的原则:
- 非必要不使用异常
- 使用描述性消息抛出异常
- 力所能及的异常一定要处理
- 异常忽略要有理有据
在异常的处理上, 我们统一在controller层捕获并决定是抛出还是继续, 其他的service层, dao层异常抛出到controller进行处理。
定义异常处理器进行异常捕获统一处理
例如:
/**
* 异常处理器
*
* @author Mark sunlightcs@gmail.com
*/
@RestControllerAdvice
public class RRExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 处理自定义异常
*/
@ExceptionHandler(RRException.class)
public R handleRRException(RRException e){
R r = new R();
r.put("code", e.getCode());
r.put("msg", e.getMessage());
return r;
}
@ExceptionHandler(NoHandlerFoundException.class)
public R handlerNoFoundException(Exception e) {
logger.error(e.getMessage(), e);
return R.error(404, "路径不存在,请检查路径是否正确");
}
@ExceptionHandler(DuplicateKeyException.class)
public R handleDuplicateKeyException(DuplicateKeyException e){
logger.error(e.getMessage(), e);
return R.error("数据库中已存在该记录");
}
@ExceptionHandler(AuthorizationException.class)
public R handleAuthorizationException(AuthorizationException e){
logger.error(e.getMessage(), e);
return R.error("没有权限,请联系管理员授权");
}
@ExceptionHandler(Exception.class)
public R handleException(Exception e){
logger.error(e.getMessage(), e);
return R.error();
}
}
/**
* 统一异常处理
*/
@Slf4j
@RestControllerAdvice(basePackages = "com.kkb.cubemall.product.controller")
public class CubemallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handlerVaildException(MethodArgumentNotValidException e){
log.error("数据校验失败{},异常类型{}",e.getMessage(),e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String,String> map = new HashMap<>();
bindingResult.getFieldErrors().forEach((item)->{
String field = item.getField();
String message = item.getDefaultMessage();
map.put(field,message);
});
return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMessage()).put("data",map);
}
@ExceptionHandler(value = Throwable.class)
public R handlerException(Throwable throwable){
throwable.printStackTrace();;
return R.error(BizCodeEnum.UNKNONW_EXCEPTION.getCode(),BizCodeEnum.UNKNONW_EXCEPTION.getMessage());
}
}