代码规范(武立松)

Java规范

命名规范

(一)命名风格:

  • 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 反例:name / __name / $name / name / name$ /
  • 所有编程相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。 说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,纯拼音命名方式更要避免采用。 正例:ali / alibaba / taobao / cainiao/ aliyun/ youku / hangzhou 等国际通用的名称,可视同英文。 反例:DaZhePromotion [打折] / getPingfenByName() [评分] / String fw[福娃] / int 某变量 = 3

  • 代码和注释中都要避免使用任何语言的种族歧视性词语。 正例:日本人 / 印度人 / blockList / allowList / secondary 反例:RIBENGUIZI / Asan / blackList / whiteList / slave

(二)常量命名:

  • 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。 正例:SYSTEM_CODE_NUM / INDEXEXECTYPE_RULE 反例:System_Code / INDEXEXECTYPE
  • 在常量与变量的命名时,表示类型的名词放在词尾,以提升辨识度。 正例:startTime / workQueue / nameList / TERMINATED_THREAD_COUNT 反例:startedAt / QueueOfWork / listName / COUNT_TERMINATED_THREAD

(三)类命名:

  • 类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等 正例:ForceCode / UserDO / HtmlDTO / TbCmnApproveJurisdictionService/ TcpUdpDeal / BusiCodeController 反例:forcecode / UserDo / HTMLDto / TBCMNApproveJurisdictionService/ TCPUDPDeal / BUSICodeController

(四)方法、参数、成员变量、局部变量命名:

  • 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格。 正例: localValue / getBusiCode() /userId

(五)接口:

  • 类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,确定与接口方法相关,并且是整个应用的基础常量。

正例:void delUserPost(PageData pd)throws Exception;

  • 接口基础常量 String COMPANY = “alibaba”; 反例:接口方法定义 public void f(); 说明:JDK8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默认实现
  • 接口和实现类的命名有两套规则: 对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。 正例:WorkFlowServiceImpl实现 WorkFlowService接口。

如果是形容能力的接口名称,取对应的形容词为接口名(通常是–able 的形容词)。 正例:AbstractTranslator 实现 Translatable 接口。

(六)枚举: 枚举类名带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。 说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。 正例:枚举名字为 SystemEnum

(七) 项目各层规范 :

Controller:功能模块名称+Controller,例如:PositionController Service:功能模块名称+Service,例如:PositionService Service.Impl:Service名称+Impl,例如:PositionServiceImpl Core :功能模块名称+Core,例如:PostitionCore Core.Impl:Core名称+Impl,例如:PostitionCoreImpl 所有类名采用驼峰格式

异常日志

错误码

  1. 【强制】错误码的制定原则:快速溯源、沟通标准化。 说明: 错误码想得过于完美和复杂,就像康熙字典中的生僻字一样,用词似乎精准,但是字典不容易随身携带并且简单易懂。 正例:错误码回答的问题是谁的错?错在哪? 1)错误码必须能够快速知晓错误来源,可快速判断是谁的问题。 2)错误码必须能够进行清晰地比对(代码中容易 equals)。 3)错误码有利于团队快速对错误原因达到一致认知. 例如:CSM_ERR_0001("CSM-ERR-0001", "财报平衡校验失败!", ""),SYS_ERR_0004("SYS-ERR-0004", "返回值不能为空,请联系管理员!", "")

  2. 【强制】错误码不体现版本号和错误等级信息。 说明:错误码以不断追加的方式进行兼容。错误等级由日志和错误码本身的释义来决定。

  3. 【强制】全部正常,但不得不填充错误码时返回五个零:00000。
  4. 【强制】错误码为字符串类型,共 5 位,分成两个部分:错误产生来源+四位数字编号。 说明:错误产生来源分为 A/B/C,A 表示错误来源于用户,比如参数错误,用户安装版本过低,用户支付 超时等问题;B 表示错误来源于当前系统,往往是业务逻辑出错,或程序健壮性差等问题;C 表示错误来源 于第三方服务,比如 CDN 服务出错,消息投递超时等问题;四位数字编号从 0001 到 9999,大类之间的步长间距预留 100
  5. 【强制】编号不与公司业务架构,更不与组织架构挂钩,以先到先得的原则在统一平台上进行,审批生效,编号即被永久固定。
  6. 【强制】错误码使用者避免随意定义新的错误码。 说明:尽可能在原有错误码附表中找到语义相同或者相近的错误码在代码中使用即可。
  7. 【强制】错误码不能直接输出给用户作为提示信息使用。 说明:堆栈(stack_trace)、错误信息(error_message)、错误码(error_code)、提示信息(user_tip) 是一个有效关联并互相转义的和谐整体,但是请勿互相越俎代庖。
  8. 【推荐】错误码之外的业务独特信息由 error_message 来承载,而不是让错误码本身涵盖过 多具体业务属性。
  9. 【推荐】在获取第三方服务错误码时,向上抛出允许本系统转义,由 C 转为 B,并且在错误信 息上带上原有的第三方错误码。

异常处理

1.【强制】Java 类库中定义的可以通过预检查方式规避的 RuntimeException 异常不应该通过 catch 的方式来处理,比如:NullPointerException,IndexOutOfBoundsException 等等。 说明:无法通过预检查的异常除外,比如,在解析字符串形式的数字时,可能存在数字格式错误,不得不通过 catchNumberFormatException 来实现。

正例:

  1. if (obj != null) {...}

反例:

  1. try { obj.method(); } catch (NullPointerException e) {…}

2.【强制】异常捕获后不要用来做流程控制,条件控制。 说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

3.【强制】catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。 对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。 说明:对大段代码进行 try-catch,使程序无法根据不同的异常做出正确的应激反应,也不利于定位问题, 这是一种不负责任的表现。 正例:用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于简单,在程 序上作出分门别类的判断,并提示给用户。

4.【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请 将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的 内容。

5.【强制】事务场景中,抛出异常被 catch 后,如果需要回滚,一定要注意手动回滚事务。

6.【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。 说明:如果 JDK7 及以上,可以使用 try-with-resources 方式。

7.【强制】不要在 finally 块中使用 return。 说明:try 块中的 return 语句执行成功后,并不马上返回,而是继续执行 finally 块中的语句,如果此处存 在 return 语句,则在此直接返回,无情丢弃掉 try 块中的返回点。 反例:

  1. private int x = 0;
  2. public int checkReturn() {
  3. try {
  4. // x 等于 1,此处不返回
  5. return ++x;
  6. } finally {
  7. // 返回的结果是 2
  8. return ++x;
  9. }
  10. }

8.【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。 说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。

9.【推荐】方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回 null 值。 说明:即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败、序列化失败、运行时异常等场景返回 null 的情况。

10.【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:

1) 返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE(NullPointerException)。 反例:public int f() { return Integer 对象}, 如果为 null,自动解箱抛 NPE。

2) 数据库的查询结果可能为 null。

3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。

4) 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。

5) 对于 Session 中获取的数据,建议进行 NPE 检查,避免空指针。

6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。 正例:使用 JDK8 的 Optional 类来防止 NPE 问题。

11.【推荐】定义时区分 unchecked / checked 异常,避免直接抛出 new RuntimeException(), 更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定 义过的自定义异常,如:DAOException / ServiceException 等。 本项目BussinessException ControllException等

日志规约

  1. 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 (SLF4J、JCL—Jakarta Commons Logging)中的 API,使用门面模式的日志框架,有利于维护和 各个类的日志处理方式统一。 说明:日志框架(SLF4J、JCL—Jakarta Commons Logging)的使用方式(推荐使用 SLF4J) 使用 SLF4J:
    1. import org.slf4j.Logger;
    2. import org.slf4j.LoggerFactory;
    3. private static final Logger logger = LoggerFactory.getLogger(Test.class);
    使用 JCL:
    1. import org.apache.commons.logging.Log;
    2. import org.apache.commons.logging.LogFactory;
    3. private static final Log log = LogFactory.getLog(Test.class);
  2. 【强制】所有日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。对于 当天日志,以“应用名.log”来保存,保存在/home/admin/应用名/logs/目录下,过往日志 格式为: {logname}.log.{保存日期},日期格式:yyyy-MM-dd 正例:以 aap 应用为例,日志保存在/home/admin/aapserver/logs/aap.log,历史日志名称为 aap.log.2016-08-01
  3. 【强制】根据国家法律,网络运行状态、网络安全事件、个人敏感信息操作等相关记录,留存 的日志不少于六个月,并且进行网络多机备份。
  4. 【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式: appName_logType_logName.log。logType:日志类型,如 stats/monitor/access 等;logName:日志描 述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查 找。 说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系 统进行及时监控。 正例:mppserver 应用中单独监控时区转换异常,如:mppserver_monitor_timeZoneConvert.log
  5. 【强制】在日志输出时,字符串变量之间的拼接使用占位符的方式。 说明:因为 String 字符串的拼接会使用 StringBuilder 的 append()方式,有一定的性能损耗。使用占位符仅 是替换动作,可以有效提升性能。 正例:
    1. logger.debug("Processing trade with id: {} and symbol: {}", id, symbol);
  6. 【强制】对于 trace/debug/info 级别的日志输出,必须进行日志级别的开关判断。 说明:虽然在 debug(参数)的方法体内第一行代码 isDisabled(Level.DEBUG_INT)为真时(Slf4j 的常见实现 Log4j 和 Logback),就直接 return,但是参数可能会进行字符串拼接运算。此外,如果 debug(getName()) 这种参数内有 getName()方法调用,无谓浪费方法调用的开销。 正例:
    1. // 如果判断为真,那么可以输出 trace 和 debug 级别的日志
    2. if (logger.isDebugEnabled()) {
    3. logger.debug("Current ID is: {} and name is: {}", id, getName());
    4. }
  7. 【强制】避免重复打印日志,浪费磁盘空间,务必在日志配置文件中设置 additivity=false。 正例:
  8. 【强制】生产环境禁止直接使用 System.out 或 System.err 输出日志或使用 e.printStackTrace()打印异常堆栈。 说明:标准日志输出与标准错误输出文件每次 Jboss 重启时才滚动,如果大量输出送往这两个文件,容易 造成文件大小超过操作系统大小限制。
  9. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过 关键字 throws 往上抛出。 正例:logger.error(“inputParams:{} and errorMessage:{}”, 各类参数或者对象 toString(), e.getMessage(), e);

  10. 【强制】日志打印时禁止直接用 JSON 工具将对象转换成 String。说明:如果对象里某些 get 方法被覆写,存在抛出异常的情况,则可能会因为打印日志而影响正常业务流 程的执行。 正例:打印日志时仅打印出业务相关属性值或者调用其对象的 toString()方法。

  11. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑 爆,并记得及时删除这些观察日志。 说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:

  12. 【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。 说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。

  13. 【推荐】尽量用英文来描述日志错误信息,如果日志中的错误信息用英文描述不清楚的话使用 中文描述即可,否则容易产生歧义。 说明:国际化团队或海外部署的服务器由于字符集问题,使用全英文来注释和描述日志错误信息。

    工程结构(武立松)

    前台工程结构

    开发规范 - 图1

    后台工程结构

    开发规范 - 图2

项目逻辑实现如上图所示 pricing目录下 分为4层, 即controller、applilcation、core、entity。

Controller层

负责接收前台交易请求,并对其响应返回。返回格式统一为JSON。 在定义一个Rest接口时,我们通常会使用GET,POST,PUT,DELETE几种方式来完成我们所需要进行CRUD的一些操作,

  • GET:一般用于查询数据,不能对数据进行更新以及插入操作。
  • POST:一般用于数据的插入操作,也是使用最多的传输方式,
  • PUT:我们使用PUT方式来对数据进行更新操作。
  • DELETE:用于数据删除。 与之对应的就会有@GetMapping,@PostMapping,@PutMapping,
  1. @DeleteMapping
  2. Controller使用@RestController注释,具体代码如下
  3. /**
  4. * 说明:岗位管理
  5. * 创建人:
  6. * 创建时间:2019-06-22
  7. */
  8. @RestController
  9. @RequestMapping(value = "/positions")
  10. @Api(value = "岗位Controller", tags = {"岗位增删改查操作"})
  11. public class PositionController extends BaseRestController{
  12. @Autowired
  13. private PositionService ompositionService;
  14. /**
  15. * 保存岗位
  16. *
  17. * @param data 岗位数据
  18. * @throws Exception
  19. */
  20. @Override
  21. @PostMapping
  22. @ApiOperation(value = "新增岗位", notes = "新增岗位")
  23. public ResponseEntity create(
  24. @NotEmpty(message = "岗位信息不能为空")
  25. @ApiParam(name = "data", value = "岗位信息", required = true)
  26. @RequestBody PageData data) throws Exception {
  27. Responder responder = new Responder();
  28. try {
  29. logger.info("增加岗位");
  30. responder=ompositionService.save(pd);
  31. if (isError(responder)) {
  32. responder=bussError(responder.getCode(),responder.getErrorMessage(),
  33. responder.getMessage());
  34. }
  35. } catch (EasyLoanException e) {
  36. responder = bussError(e.errCode(), "", e.getMessage());
  37. } catch (Exception e) {
  38. responder = bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(),
  39. e.getMessage(), MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  40. }
  41. return ResponderEntity.returnResponder(responder);
  42. }
  43. /**
  44. * 删除岗位
  45. *
  46. * @param id 岗位编号
  47. * @throws Exception
  48. */
  49. @Override
  50. @DeleteMapping("/{id}")
  51. @ApiOperation(value = "删除岗位", notes = "根据岗位编号,删除岗位")
  52. public ResponseEntity delete(@PathVariable
  53. @NotBlank(message = "岗位编号不能为空")
  54. @ApiParam(name = "id", value = "岗位编号", required = true) String id)
  55. {
  56. Responder responder = new Responder();
  57. try {
  58. logger.info("删除岗位");
  59. responder = ompositionService.delete(pd);
  60. if (isError(responder)) {
  61. responder = bussError(responder.getCode(),responder.getErrorMessage(),
  62. responder.getMessage());
  63. }
  64. } catch (EasyLoanException e) {
  65. responder = bussError(e.errCode(), "", e.getMessage());
  66. } catch (Exception e) {
  67. responder=bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(),
  68. e.getMessage(),
  69. MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  70. }
  71. return ResponderEntity.returnResponder(responder);
  72. }
  73. /**
  74. * 修改岗位
  75. *
  76. * @param data 岗位数据
  77. * @throws Exception
  78. */
  79. @Override
  80. @PatchMapping("/{id}")
  81. @ApiOperation(value = "修改岗位", notes = "根据岗位编号,修改岗位")
  82. public ResponseEntity editPath(
  83. @NotBlank(message = "岗位编号不能为空")
  84. @RequestBody
  85. @NotEmpty(message = "待修改岗位信息不能为空")
  86. @ApiParam(name = "data", value = "待修改岗位信息", required = true)
  87. PageData data){
  88. Responder responder = new Responder();
  89. try {
  90. logger.info("修改岗位");
  91. responder=ompositionService.edit(data);
  92. if (isError(responder)) {
  93. responder=bussError(responder.getCode(),
  94. responder.getErrorMessage(), responder.getMessage());
  95. }
  96. } catch (EasyLoanException e) {
  97. responder = bussError(e.errCode(), "", e.getMessage());
  98. } catch (Exception e) {
  99. responder=bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(),
  100. e.getMessage(),
  101. MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  102. }
  103. return ResponderEntity.returnResponder(responder);
  104. }
  105. /**
  106. * 岗位查询
  107. *
  108. * @param data 查询条件
  109. * @param pageNum 页码
  110. * @return
  111. * @throws Exception
  112. */
  113. @Override
  114. @GetMapping
  115. @ResponseStatus(value = HttpStatus.OK)
  116. @ApiOperation(value = "分页获取岗位信息", notes = "分页获取岗位信息:查询条件,页面")
  117. public ResponseEntity index(
  118. @RequestParam
  119. @ApiParam(name = "data", value = "查询条件")Map<String, String> data,
  120. @RequestParam(defaultValue = "1", required = false)
  121. @Min(value = 1, message = "页码只能为正整数")
  122. @ApiParam(name = "pageNum", value = "页码") int pageNum,
  123. @RequestParam(defaultValue = "10", required = false)
  124. @Min(value = 10, message = "条数只能为正整数")
  125. @ApiParam(name = "size", value = "条数")int size)
  126. {
  127. Responder responder = new Responder();
  128. try {
  129. logger.info("岗位查询");
  130. PageData pd = new PageData();
  131. pd.putAll(data);
  132. String keywords = pd.getString("keywords");//关键词检索条件
  133. if (null != keywords && !"".equals(keywords)) {
  134. pd.put("keywords", keywords.trim());
  135. }
  136. Page page = new Page();
  137. page.setCurrentPage(pageNum);
  138. page.setPd(pd);
  139. responder=ompositionService.list(page);
  140. If (isError(responder)) {
  141. responder=bussError(responder.getCode(),responder.getErrorMessage(),
  142. responder.getMessage());
  143. }
  144. } catch (EasyLoanException e) {
  145. responder = bussError(e.errCode(), "", e.getMessage());
  146. } catch (Exception e) {
  147. responder=bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(),
  148. e.getMessage(),
  149. MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  150. }
  151. return ResponderEntity.returnResponder(responder);
  152. }
  153. /**
  154. * 批量删除
  155. *
  156. * @param ids
  157. * @return
  158. */
  159. @Override
  160. @DeleteMapping
  161. @ApiOperation(value = "批量删除岗位信息", notes = "批量删除岗位信息")
  162. public ResponseEntity batchDelete(
  163. @RequestParam
  164. @NotBlank(message = "岗位编号不能为空")
  165. @ApiParam(name = "ids", value = "主键列表")
  166. String ids){
  167. Responder responder = new Responder();
  168. try {
  169. logger.info("批量删除岗位");
  170. if (null != ids && !"".equals(ids)) {
  171. String idArray[] = ids.split(",");
  172. responder = ompositionService.deleteAll(idArray);
  173. }
  174. if (isError(responder)) {
  175. responder=bussError(responder.getCode(),responder.getErrorMessage(),
  176. responder.getMessage());
  177. }
  178. } catch (EasyLoanException e) {
  179. responder = bussError(e.errCode(), "", e.getMessage());
  180. } catch (Exception e) {
  181. responder=bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(),
  182. e.getMessage(), MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  183. }
  184. return ResponderEntity.returnResponder(responder);
  185. }
  186. }

application层

如下:PositionService,分为接口定义和具体接口的实现

  1. /**
  2. * 说明: 岗位管理接口
  3. * 创建人:
  4. * 创建时间:2019-04-22
  5. * @version
  6. */
  7. public interface PositionService {
  8. /**新增
  9. * @param pd
  10. * @throws Exception
  11. */
  12. public Responder save(PageData pd)throws Exception;
  13. /**删除
  14. * @param pd
  15. * @throws Exception
  16. */
  17. public Responder delete(PageData pd)throws Exception;
  18. /**查询
  19. * @param pd
  20. * @throws Exception
  21. */
  22. public Responder index(Page page)throws Exception;

标准的service接口定义,注意每个方法前都需要写注释,标明方法用途,参数用途。

如下图是service的实现Impl

  1. /**
  2. * 说明: 岗位管理
  3. * 创建人:
  4. * 创建时间:2019-04-22
  5. */
  6. @Service("ompositionService")
  7. public class PositionServiceImpl extends AlsBaseMessage implements PositionService {
  8. @Resource(name = "daoSupport")
  9. private DaoSupport dao;
  10. /**
  11. * 新增
  12. *
  13. * @param pd
  14. * @throws Exception
  15. */
  16. @Override
  17. public Responder save(PageData pd) throws Exception {
  18. int number=(int)dao.save("OmPositionMapper.save", pd);
  19. return success(SUCCESS_CODE, SUCCESS_MESSAGE, number);
  20. }
  21. /**
  22. * 删除
  23. *
  24. * @param pd
  25. * @throws Exception
  26. */
  27. @Override
  28. public Responder delete(PageData pd) throws Exception {
  29. int number=(int)dao.delete("OmPositionMapper.delete", pd);
  30. return success(SUCCESS_CODE, SUCCESS_MESSAGE, number);
  31. }
  32. /**
  33. * 修改
  34. *
  35. * @param pd
  36. * @throws Exception
  37. */
  38. @Override
  39. public Responder edit(PageData pd) throws Exception {
  40. int number=(int)dao.update("OmPositionMapper.edit", pd);
  41. return success(SUCCESS_CODE, SUCCESS_MESSAGE, number);
  42. }
  43. }

@Service(“xxxService”)//为定义暴露给外部调用的service名称。

@Resource(name = "daoSupport") private DaoSupport dao; 为引入的数据库操作类。单表操作可以直接在类里通过dao封装的方法直接操作数据库。 如果是多表操作,则需要调用core层的方法。 在service的实现类中会有如下类似代码,去调用core层方法

  1. @Resource(name="csmGuarGroupCore")
  2. private CsmGuarGroupCore csmGuarGroupCore;
  3. /**
  4. * 修改之后查询最新信息返回页面
  5. * @param pd
  6. * @return
  7. * @throws Exception
  8. */
  9. @Override
  10. public Responder editReturnPageData(PageData pd) throws Exception {
  11. Responder responder=csmGuarGroupCore.editReturnPageData(pd)
  12. if(isError(responder)){
  13. throw error(responder.getCode(),responder.getMessage());
  14. }
  15. return responder;
  16. }

Core层

  1. public interface CsmGuarGroupCore {
  2. /**
  3. * 保存联保小组
  4. * @param pageData
  5. * @throws Exception
  6. */
  7. public void saveCsmGuarGroup(PageData pageData) throws Exception;
  8. /**
  9. *删除联保小组
  10. * @param partyId
  11. * @throws Exception
  12. */
  13. public void deleteCsmGuarGroup(String partyId) throws Exception;
  14. /**
  15. * 查询联保小组基本信息
  16. * @return
  17. * @throws Exception
  18. */
  19. public Responder getGuarGroupBasicInfo(String partyId) throws Exception;
  20. /**
  21. * 修改之后查询最新信息返回页面
  22. *
  23. * @param pageData
  24. * @return
  25. * @throws Exception
  26. */
  27. public Responder editReturnPageData(PageData pageData) throws Exception;
  28. }

如上图所示,core也相当于一个service,是一个原子级的service,它也有它的具体实现 如下CsmGuarGroupCoreImpl @Component(“csmGuarGroupCore”):托管给spring管理装载

  1. @Component("csmGuarGroupCore")
  2. public class CsmGuarGroupCoreImpl extends BaseMessage implements CsmGuarGroupCore {
  3. @Resource(name = "daoSupport")
  4. private DaoSupport dao;
  5. /**
  6. * 保存联保小组
  7. * @param pageData
  8. * @throws Exception
  9. */
  10. @Override
  11. public void saveCsmGuarGroup(PageData pageData) throws Exception {
  12. //保存参与人表
  13. dao.save("CsmPartyMapper.save",pageData);
  14. //保存联保小组客户表
  15. dao.save("CsmGuarGroupMapper.save",pageData);
  16. //保存客户管理团队
  17. pageData.put("PARTY_ID",pageData.get("UUID"));
  18. pageData.put("UUID", KeyGenerator.get32UUID());
  19. dao.save("CsmManagementTeamMapper.save",pageData);
  20. }
  21. /**
  22. *删除联保小组
  23. * @param partyId
  24. * @throws Exception
  25. */
  26. @Override
  27. public void deleteCsmGuarGroup(String partyId) throws Exception {
  28. PageData pageData = new PageData();
  29. pageData.put("UUID",partyId);
  30. //删除参与人表
  31. dao.delete("CsmPartyMapper.delete",pageData);
  32. //删除联保小组表
  33. dao.delete("CsmGuarGroupMapper.delete",pageData);
  34. //删除管理团队表
  35. pageData.put("PARTY_ID",partyId);
  36. dao.delete("CsmManagementTeamMapper.deleteByPartyId",pageData);
  37. }
  38. /**
  39. * 查询联保小组基本信息
  40. * @return
  41. * @throws Exception
  42. */
  43. @Override
  44. public Responder getGuarGroupBasicInfo(String partyId) throws Exception {
  45. PageData pageData = new PageData();
  46. pageData.put("PARTY_ID",partyId);
  47. pageData=(PageData)dao.findForObject("CsmGuarGroupMapper.getGuarGroupBasicInfo",pageData);
  48. return success(SUCCESS_CODE,SUCCESS_MESSAGE,pageData);
  49. }
  50. /**
  51. * 修改之后查询最新信息返回页面
  52. *
  53. * @param pageData
  54. * @return
  55. * @throws Exception
  56. */
  57. @Override
  58. public Responder editReturnPageData(PageData pageData) throws Exception {
  59. // 更新
  60. dao.update("CsmGuarGroupMapper.edit", pageData);
  61. // 取得更新后的信息
  62. pageData.put("PARTY_ID", pageData.getString("UUID"));
  63. PageData dbpd= (PageData)dao.findForObject("CsmGuarGroupMapper.getGuarGroupBasicInfo",pageData);
  64. return success(SUCCESS_CODE,SUCCESS_MESSAGE,dbpd);
  65. }
  66. }

Entity层

存放一些固定的对象。

其他说明

(1)所有类前加注释

  1. /**
  2. * 说明:对本类的说明。
  3. * 创建人:XXX
  4. * 创建时间:2019年7月20日
  5. */

(2)Controller 对类增加如下注释:

  1. @RestController@RequestMapping(value = "/positions"),@Api(value = "岗位Controller", tags = {"岗位增删改查操作"})

说明: @RequestMapping:为前台请求的路径, @Api:类说明 每个方法之前也要有说明如下

  1. /**
  2. * 保存岗位
  3. *
  4. * @param data 岗位数据
  5. * @throws Exception
  6. */
  7. @PostMapping
  8. @ApiOperation(value = "新增岗位", notes = "新增岗位")
  9. public ResponseEntity create(
  10. @NotEmpty(message = "岗位信息不能为空")
  11. @ApiParam(name = "data", value = "岗位信息", required = true)
  12. PageData data) {
  13. Responder responder = new Responder();
  14. try {
  15. logger.info("新增岗位");
  16. responder= ompositionService.save(pd);
  17. if (isError(responder)) {
  18. responder=bussError(responder.getCode(),responder.getErrorMessage(), responder.getMessage());
  19. }
  20. } catch (EasyLoanException e) {
  21. responder = bussError(e.errCode(), "", e.getMessage());
  22. } catch (Exception e) {
  23. responder=bussError(MessageEnum.CALL_BACK_RETCODE_ERROR.getCode(), e.getMessage(), MessageEnum.CALL_BACK_RETCODE_ERROR.getMessage());
  24. }
  25. return ResponderEntity.returnResponder(responder);
  26. }

说明:@PostMapping:为请求的方法 @ApiOperation(value = “新增岗位”, notes = “新增岗位”):方法说明 @ApiParam(name = “data”, value = “岗位信息”, required = true):参数说明 @RequestBody PageData data:参数定义

1.Service类,和方法都加上说明

2.Service的实现 类、方法都加上说明,在类头增加@Service(“XXX”)注释,对外暴露。

3.Core、core实现、entity层,与上类似,在类和方法上都要有说明 Core实现 在类头增加@Component(“XXXX”)注释,对外暴露, 注意对外暴露的core层方法,当要调用其外的core服务可以直接调用,但是不能调用service层服务。Service可以调用多个core服务,service层不能引用别的service。Controller可以引用多个service(不能再一个事务里)。

4.sqlMapping 命名是模块名+Mapping,

5.子系统间接口调用 Springboot子系统调用使用feignClient,框架已经集成好,我们只要写service接口即可 1.创建interface

  1. @FeignClient(name="${server.name.customer}",url = "${gateway.url.customer}", configuration = FeignConfig.class)
  2. public interface FeignPostionService {
  3. /**
  4. * 列表查询岗位信息
  5. * @throws Exception
  6. */
  7. @RequestMapping(method=RequestMethod.GET,value= "/api/v1/newparameter/positions/", consumes = MediaType.APPLICATION_JSON_VALUE)
  8. @ResponseBody
  9. public List<PageData> list(@RequestParam
  10. @ApiParam(name = "page", value = "查询条件")
  11. Page page
  12. ) throws Exception;
  13. }

注意:@FeignClient: 为接口调用注释。 Name: server服务名称 Url:为网关地址,可以用变量实现 @RequestMapping:注释 Menthod:为调用目标controller方法的请求方式 Value: 为调用目标controller方法的url 服务提供方的controller内部实现了list方法的实现。

6.返回 Controller层统一返回:ResponderEntity.returnResponder(responder); 返回 Responder:封装了code,message,errorMessage,retObj Code:返回交易码,200代表成功,非200代表失败,此错误码统一使用 MessageEnum按子系统划分定义。 Message:返回客户端信息,用于给客户展示信息。 ErrorMessage:返回错误信息,用户给开发人员展示错误信息。 retObj:返回交易结果数据信息。

Service层:统一返回responder Core层:统一返回responder