做为一个程序员,虽然技术不厉害,可是都有一个向上的心,原来一直负责业务开发,梳理业务、设计流程、开发代码,最近开始接触一些架构类的设计和思路java
全国医改在即,项目组接了一个医疗改革相关的供应商项目,主要是针对物流方向的。程序员
技术架构:领导要求用springcloud可是新来的成员都没有相关开发经验,项目负责人直接在网上扒了一套微服务的代码(我的感受不太成熟),好多东西不太全,web
因此须要从新整理,因为项目负责人比较忙,本身有迫切的想要了解一些东西,因此针对架构层次的代码学习了一下,spring
本身原来只作业务,从不关心架构的设计是否合理优美,甚至在业务方向已经作到管理层次,后来跳槽离职后才发现本身技术的短板,因此一直在补充学习segmentfault
其实只须要架构师搭建微服务架构便可,项目组成员仍是针对不一样的功能模块进行业务开发,和原来的SSM没有本质区别,只是增长了一些新的注解,和组件的使用后端
这里就不对微服务的组件进行介绍了,只是针对本身部署的异常处理进行记录——只是我的理解,若有好的设计欢迎指正架构
问题描述app
技术架构是先后端分离,想着统一返处理回值(包括正常结果和异常结果),可是架构代码只是作了一个本身的返回类Map类型,以下前后端分离
package com.bootdo.clouddocommon.utils; import java.util.HashMap; import java.util.Map; public class R extends HashMap<String, Object> { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "操做成功"); } public static R error() { return error(500, "操做失败"); } public static R operate(boolean b){ if(b){ return R.ok(); } return R.error(); } public static R error(String msg) { return error(500, msg); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } public static R error401() { return error(401, "你尚未登陆"); } public static R error403() { return error(403, "你没有访问权限"); } public static R data(Object data){ return R.ok().put("data",data); } public static R page(Object page){ return R.ok().put("page",page); } @Override public R put(String key, Object value) { super.put(key, value); return this; } }
这种这种类封装方式很好的处理的全部Controller类的返回结果 例如;dom
@Log("停用记录") @ApiOperation(value = "停用信息记录") @PutMapping("/stop") R stop(@RequestBody List<Long> idList) { return R.operate(consumeMaterialService.stop(idList,getUser()) > 0); }
@Log("获取耗材信息列表(无分页)") @ApiOperation(value = "获取耗材信息列表(无分页)") @ApiImplicitParam(name = "params", value = "map参数集合(基础的参数格式——可在结构内增长其余过滤条件字段)", example = "{consumeName:10}") @GetMapping("/allList") R list(@RequestParam Map<String, Object> params) { List<ConsumeMaterialDO> list = consumeMaterialService.list(params); return R.data(list); }
这种方式特色
一、很好的统一了Controller层的返回结果
二、没有一套错误编码和对应的信息,须要硬编码的形式在代码提现,例如:(该问题能够经过增长一个错误信息的枚举类来解决——下文中会说明)
R findMaterialBySupplierIdNotAddList(@RequestParam Map<String, Object> params){ if(params.isEmpty()){ return R.error("30032",”"医院ID和供应商ID不能为空");//能够只写错误信息,也能够加上编码 }else{ Long id=new Long(params.get("hospitalId").toString()); if(id==null||id==0){ return R.error("医院ID不能为空"); } Long sid=new Long(params.get("supplierId").toString()); if(sid==null||sid==0){ return R.error("供应商ID不能为空"); } } //查询列表数据 Query query = new Query(params); List<ConsumeMaterialDO> materialList = supplierService.findMaterialBySupplierIdNotAddList(query); int total = supplierService.findMaterialBySupplierIdNotAddCount(query); PageUtils pageUtils = new PageUtils(materialList, total); //返回状态字典 List<SysDictDO> statusList = initDataService.getSysDictByType("status"); //返回耗材状态 List<SysDictDO> measurementStatusList = initDataService.getSysDictByType("unit"); return R.ok().put("page",pageUtils).put("suppliermaterialstatusoptions",statusList).put("measurementstatusoptions",measurementStatusList); }
三、没有办法处理service层的异常返回,由于service 层返回的都是具体的实体或者整数
由于原来作过的项目中有过相关的异常处理——记得是定义一个统一的异常接收类对返回值结构进行处理,其余地方直接抛出异常便可,固然须要定义一套错误信息枚举类,用于统一返回信息内容
随意根据本身的理解和经验,查找相关代码作了一套异常处理的代码,代码和原理很简单
参考连接:http://www.javashuo.com/article/p-rqbccjeg-hx.html
一、首先在原来的基础上增长一个错误信息的枚举类——代码比较多删减了一部分,能够根据本身的需求添加
package com.bootdo.clouddocommon.constants; /** * 异常处理状态码 */ public enum ResultCode { SUCCESS(0, "请求成功"), Unknown_Exception(-1, "未知异常"), USER_NOT_FOUND(10001, "没有找到此用户"), USERNAME_NOT_BLANK(10002, "用户名不能为空"), USERNAME_EXIST(10003, "用户名已经存在"), USERTYPE_ERROR(100031, "用户类型不正确"), DEVICE_ID_EMPTY(10052,"设备ID:deviceId不能为空"), DELETE_CONNECT_ERROR(10053,"删除connect出错"); private int code; private String message; ResultCode(int code, String message) { this.code = code; this.message = message; } public int getCode() { return code; } public String getMessage() { return message; } }
二、添加一个自定义的异常类用于抛出:主要是将本身的错误编码和信息整合进去——原生的异常类也是能够的,只是好像没有自定的编码返回(自定义的异常类也须要集成原生的异常类——红色部分——有兴趣的同窗能够看一下源码)
package com.bootdo.clouddoadmin.config; import com.bootdo.clouddocommon.constants.ResultCode; /** * 功能描述: <br> * 〈异常类封装——定义抛出的异常类〉 * @return: * @since: 1.0.0 * @Author: * @Date: */ public class DomainException extends RuntimeException { private int errCode = ResultCode.Unknown_Exception.getCode(); public DomainException() { super(ResultCode.Unknown_Exception.getMessage()); } public DomainException(ResultCode resultCode) { super(resultCode.getMessage()); this.errCode = resultCode.getCode(); } public int getErrCode() { return errCode; } public void setErrCode(int errCode) { this.errCode = errCode; } }
三、添加统一的异常返回处理——RestControllerAdvice(ControllerAdvice)拦截异常并统一处理
package com.bootdo.clouddoadmin.config; import com.bootdo.clouddocommon.utils.R; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; /** * 功能描述: <br> * 〈统一异常处理返回〉 * @return: * @since: 1.0.0 * @Author: * @Date: */ @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = DomainException.class) public R domainExceptionHandler(HttpServletRequest req, DomainException e) throws Exception { e.printStackTrace(); return R.error(e.getErrCode(), e.getMessage()); } }
这样总体就设计完了,不管是在service或者controller中均可以抛出异常,而后通过处理成为统一格式的返回值
例如:
throw new DomainException(ResultCode.CODE_EMPTY);
经测试是有效的——结果截图就再也不展现了