如何写出高质量代码,大佬10板斧经验分享!!!

墨蓝 2023-02-17 05:26 90阅读 0赞

这几天开发遇到了很多坑,大部分坑都是自己前期没规划好,后期因为业务已经开发完了,如果要进行大修改,又要回归测试所有的功能,最后只能不了了之。入坑后出坑的代价太大了,所以想分享一些日常开发心得,也希望童鞋们不要走我的老路。好了废话不多说,开始今天入坑血泪史介绍。

一、请使用对象参数

为什么方法参数最好用对象呢,核心原因就是为了好扩展,特别是service服务,每一个方法可能都会有很多地方引用,如果方法参数发生变动,那意味着所有调用这个方法的地方,都得进行修改,这个工作量可想而知。

下面我们来举一个例子:

  1. public class PersonService {
  2. public int getTreasureIndicator(int age) {
  3. if (age < 20) {
  4. return 5;
  5. } else {
  6. return 10;
  7. }
  8. }
  9. }
  10. public class Child {
  11. public int getTreasureIndicator() {
  12. PersonService personService = new PersonService();
  13. return personService.getTreasureIndicator(10);
  14. }
  15. }
  16. public class Old {
  17. public int getTreasureIndicator() {
  18. PersonService personService = new PersonService();
  19. return personService.getTreasureIndicator(50);
  20. }
  21. }
  22. public class Test {
  23. public static void main(String[] args) {
  24. Child child = new Child();
  25. Old old = new Old();
  26. System.out.println("child:" + child.getTreasureIndicator());
  27. System.out.println("old:" + old.getTreasureIndicator());
  28. }
  29. }
  30. child:5
  31. old:10

咋一看好像没什么问题,但是后续需求如果修改成,小孩指标计算不变,但是老人的指标需要加上性别这个字段呢?理想状态是只要修改老人的请求参数和服务类就可以了,但是现在因为只有一个参数,如果加上另外一个参数,就意味着所有的引用到这个方法的地方都需要修改。这还是两个,要是10个呢?瞬间想死的心都有了。

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. if (personDto.getAge() >= 20 && personDto.getSex()==1) {
  4. return 8;
  5. } else if(personDto.getAge() >= 20 && personDto.getSex()==2){
  6. return 10;
  7. }else {
  8. return 5;
  9. }
  10. }
  11. }
  12. public class Child {
  13. public int getTreasureIndicator() {
  14. PersonService personService = new PersonService();
  15. PersonDto personDto = new PersonDto();
  16. personDto.setAge(10);
  17. return personService.getTreasureIndicator(personDto);
  18. }
  19. }
  20. public class Old {
  21. public int getTreasureIndicator() {
  22. PersonService personService = new PersonService();
  23. PersonDto personDto = new PersonDto();
  24. personDto.setAge(50);
  25. personDto.setSex(1);
  26. return personService.getTreasureIndicator(personDto);
  27. }
  28. }
  29. public class Test {
  30. public static void main(String[] args) {
  31. Child child = new Child();
  32. Old old = new Old();
  33. System.out.println("child:" + child.getTreasureIndicator());
  34. System.out.println("old:" + old.getTreasureIndicator());
  35. }
  36. }
  37. child:5
  38. old:8

如果我们用对象作为接口的参数,就可以很大程度上,避免这个问题,就算需要添加新的判断类型,只要在对象中新增一个字段,然后修改各自的代码即可。

二、常量请使用枚举:

上面的代码有一个性别这个字段,如果我对这个字段没有添加任何注解,大家是不是都不知道这个字段的含义,一方面是可读性太差,另一方面因为没有做限制,客户端就是随意设置值,安全方面也有很大的隐患。

如果我们修改为用枚举来标识性别呢?大家来看一下代码:

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. if (personDto.getAge() >= 20 && personDto.getSex()==SexEnum.SEX_GIRL.getSex()) {
  4. return 8;
  5. } else if(personDto.getAge() >= 20 && personDto.getSex()==SexEnum.SEX_BOY.getSex()){
  6. return 10;
  7. }else {
  8. return 5;
  9. }
  10. }
  11. }
  12. public class Old {
  13. public int getTreasureIndicator() {
  14. PersonService personService = new PersonService();
  15. PersonDto personDto = new PersonDto();
  16. personDto.setAge(50);
  17. personDto.setSex(SexEnum.SEX_GIRL.getSex());
  18. return personService.getTreasureIndicator(personDto);
  19. }
  20. }
  21. public enum SexEnum {
  22. SEX_GIRL(1), SEX_BOY(2);
  23. /**
  24. * 性别
  25. */
  26. private int sex;
  27. SexEnum(int sex) {
  28. this.sex = sex;
  29. }
  30. public int getSex() {
  31. return sex;
  32. }
  33. public void setSex(int sex) {
  34. this.sex = sex;
  35. }
  36. }

从枚举的英文单词中就可以马上读懂性别是什么,而且设置值的时候也不需要判断1、2到底是什么性别了,直接设置对应的英文名称即可,安全又可读。

三、请不要让方法吃成胖子

很多人开发的时候很喜欢,把一整个业务写一个方法里面,导致方法的代码又多又长,过一段时间,自己修改都有吐血的冲动,下面我们来看看这种神级代码。

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. int result = 0;
  4. // 计算年龄得分
  5. if (personDto.getAge() < 20) {
  6. result += 5;
  7. } else if (personDto.getAge() >= 20) {
  8. result += 10;
  9. }
  10. // 计算性别得分
  11. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  12. result += 5;
  13. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  14. result += 10;
  15. }
  16. // 计算家庭得分
  17. if (personDto.getFamilyMembers() < 5) {
  18. result += 5;
  19. } else if (personDto.getFamilyMembers() >= 5) {
  20. result += 10;
  21. }
  22. // 计算颜值得分
  23. if (personDto.getFaceScore() < 5) {
  24. result += 5;
  25. } else if (personDto.getFaceScore() >= 5) {
  26. result += 10;
  27. }
  28. // 计算身高得分
  29. if (personDto.getHeight() < 170) {
  30. result += 5;
  31. } else if (personDto.getHeight() >= 170) {
  32. result += 10;
  33. }
  34. return result;
  35. }
  36. }

就比如上面的例子,如果财富的计算方式很复杂的化,所有的计算逻辑全部写在一个方法里面,就会显得方法很臃肿,代码可读性差不说,如果没有相关的注解,修改都不知道从何入手。我们将上面的计算公式拆分为一个个函数,来看看会不会有什么改变。

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. int result = 0;
  4. result += getAgeScore(personDto);
  5. result += getSexScore(personDto);
  6. result += getFamilyMembersScore(personDto);
  7. result += getFaceScore(personDto);
  8. result += getHeightScore(personDto);
  9. return result;
  10. }
  11. private int getAgeScore(PersonDto personDto){
  12. int result = 0;
  13. if (personDto.getAge() < 20) {
  14. result += 5;
  15. } else if (personDto.getAge() >= 20) {
  16. result += 10;
  17. }
  18. return result;
  19. }
  20. private int getSexScore(PersonDto personDto){
  21. int result = 0;
  22. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  23. result += 5;
  24. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  25. result += 10;
  26. }
  27. return result;
  28. }
  29. private int getFamilyMembersScore(PersonDto personDto){
  30. int result = 0;
  31. if (personDto.getFamilyMembers() < 5) {
  32. result += 5;
  33. } else if (personDto.getFamilyMembers() >= 5) {
  34. result += 10;
  35. }
  36. return result;
  37. }
  38. private int getFaceScore(PersonDto personDto){
  39. int result = 0;
  40. if (personDto.getFaceScore() < 5) {
  41. result += 5;
  42. } else if (personDto.getFaceScore() >= 5) {
  43. result += 10;
  44. }
  45. return result;
  46. }
  47. private int getHeightScore(PersonDto personDto){
  48. int result = 0;
  49. if (personDto.getHeight() < 170) {
  50. result += 5;
  51. } else if (personDto.getHeight() >= 170) {
  52. result += 10;
  53. }
  54. return result;
  55. }
  56. }

如果将各个计算方式细分之后,就算我们不添加任何的注解,也可以明显看出计算公式是由什么组成的,每个公式的计算细节是什么。代码的可读性和可维护性大大增强了。

四、请不要一层层嵌套if-else

祖传老代码中,很多都有非常多的if-else嵌套,跳来跳去,这也是为什么祖传代码几乎修改不了的一个很大原因,比如上述财富值计算是各个维护分开的,如果是各个维度相互关联的呢,直接实现会变成什么样子呢?

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. int result = 0;
  4. if (personDto.getAge() < 20) {
  5. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  6. if (personDto.getFamilyMembers() < 5) {
  7. if (personDto.getFaceScore() < 5) {
  8. if (personDto.getHeight() < 170) {
  9. result += 5;
  10. } else if (personDto.getHeight() >= 170) {
  11. result += 10;
  12. }
  13. } else if (personDto.getFaceScore() >= 5) {
  14. if (personDto.getHeight() < 170) {
  15. result += 5;
  16. } else if (personDto.getHeight() >= 170) {
  17. result += 10;
  18. }
  19. }
  20. } else if (personDto.getFamilyMembers() >= 5) {
  21. if (personDto.getFaceScore() < 5) {
  22. if (personDto.getHeight() < 170) {
  23. result += 5;
  24. } else if (personDto.getHeight() >= 170) {
  25. result += 10;
  26. }
  27. } else if (personDto.getFaceScore() >= 5) {
  28. if (personDto.getHeight() < 170) {
  29. result += 5;
  30. } else if (personDto.getHeight() >= 170) {
  31. result += 10;
  32. }
  33. }
  34. }
  35. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  36. if (personDto.getFamilyMembers() < 5) {
  37. if (personDto.getFaceScore() < 5) {
  38. if (personDto.getHeight() < 170) {
  39. result += 5;
  40. } else if (personDto.getFaceScore() >= 170) {
  41. result += 10;
  42. }
  43. } else if (personDto.getFaceScore() >= 5) {
  44. if (personDto.getHeight() < 170) {
  45. result += 5;
  46. } else if (personDto.getFaceScore() >= 170) {
  47. result += 10;
  48. }
  49. }
  50. } else if (personDto.getFamilyMembers() >= 5) {
  51. if (personDto.getFaceScore() < 5) {
  52. if (personDto.getHeight() < 170) {
  53. result += 5;
  54. } else if (personDto.getHeight() >= 170) {
  55. result += 10;
  56. }
  57. } else if (personDto.getFaceScore() >= 5) {
  58. if (personDto.getHeight() < 170) {
  59. result += 5;
  60. } else if (personDto.getHeight() >= 170) {
  61. result += 10;
  62. }
  63. }
  64. }
  65. }
  66. } else if (personDto.getAge() >= 20) {
  67. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  68. if (personDto.getFamilyMembers() < 5) {
  69. if (personDto.getFaceScore() < 5) {
  70. if (personDto.getHeight() < 170) {
  71. result += 5;
  72. } else if (personDto.getHeight() >= 170) {
  73. result += 10;
  74. }
  75. } else if (personDto.getFaceScore() >= 5) {
  76. if (personDto.getHeight() < 170) {
  77. result += 5;
  78. } else if (personDto.getHeight() >= 170) {
  79. result += 10;
  80. }
  81. }
  82. } else if (personDto.getFamilyMembers() >= 5) {
  83. if (personDto.getFaceScore() < 5) {
  84. if (personDto.getHeight() < 170) {
  85. result += 5;
  86. } else if (personDto.getHeight() >= 170) {
  87. result += 10;
  88. }
  89. } else if (personDto.getFaceScore() >= 5) {
  90. if (personDto.getHeight() < 170) {
  91. result += 5;
  92. } else if (personDto.getHeight() >= 170) {
  93. result += 10;
  94. }
  95. }
  96. }
  97. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  98. if (personDto.getFamilyMembers() < 5) {
  99. if (personDto.getFaceScore() < 5) {
  100. if (personDto.getHeight() < 170) {
  101. result += 5;
  102. } else if (personDto.getHeight() >= 170) {
  103. result += 10;
  104. }
  105. } else if (personDto.getFaceScore() >= 5) {
  106. if (personDto.getHeight() < 170) {
  107. if (personDto.getHeight() < 170) {
  108. result += 5;
  109. } else if (personDto.getHeight() >= 170) {
  110. result += 10;
  111. }
  112. } else if (personDto.getFaceScore() >= 170) {
  113. if (personDto.getHeight() < 170) {
  114. result += 5;
  115. } else if (personDto.getHeight() >= 170) {
  116. result += 10;
  117. }
  118. }
  119. }
  120. } else if (personDto.getFamilyMembers() >= 5) {
  121. if (personDto.getFaceScore() < 5) {
  122. if (personDto.getHeight() < 170) {
  123. result += 5;
  124. } else if (personDto.getHeight() >= 170) {
  125. result += 10;
  126. }
  127. } else if (personDto.getFaceScore() >= 5) {
  128. if (personDto.getHeight() < 170) {
  129. result += 5;
  130. } else if (personDto.getHeight() >= 170) {
  131. result += 10;
  132. }
  133. }
  134. }
  135. }
  136. }
  137. return result;
  138. }
  139. }

看到这样的代码就问你绝望不,一般来说,我们的if-else结构最好不要超过三层,因为如果超过三层的话,代码可读性已经变动特别差了。if-else的优化,网上有很多方法,博主这边就不多做介绍了,最有效的就是将if-else进行拆分,由各个函数自己去实现,这样就可以最大程度避免多层嵌套了。

五、请不要在一个服务中做太多事情

博主遇到过很多之前定义了一个服务类,然后之后和这个服务类相关的业务,就全部写到这个服务类中,最后导致服务类代码超过3000行,改也改不动,因为引用的地方实在是太多了,根本没办法知道这个服务类到底做了哪些事情,跟黑盒一样。就比如我们上面的服务类,如果新加一个健康指标计算的方法,我相信很多人会直接在PersonService中直接添加,例如:

  1. public class PersonService {
  2. public int getTreasureIndicator(PersonDto personDto) {
  3. int result = 0;
  4. result += getAgeScore(personDto);
  5. result += getSexScore(personDto);
  6. result += getFamilyMembersScore(personDto);
  7. result += getFaceScore(personDto);
  8. result += getHeightScore(personDto);
  9. return result;
  10. }
  11. public int getHealthIndicator(PersonDto personDto) {
  12. int result = 0;
  13. result += getAgeScore(personDto);
  14. result += getSexScore(personDto);
  15. result += getFamilyMembersScore(personDto);
  16. result += getFaceScore(personDto);
  17. result += getHeightScore(personDto);
  18. return result;
  19. }
  20. private int getAgeScore(PersonDto personDto){
  21. int result = 0;
  22. if (personDto.getAge() < 20) {
  23. result += 5;
  24. } else if (personDto.getAge() >= 20) {
  25. result += 10;
  26. }
  27. return result;
  28. }
  29. private int getSexScore(PersonDto personDto){
  30. int result = 0;
  31. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  32. result += 5;
  33. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  34. result += 10;
  35. }
  36. return result;
  37. }
  38. private int getFamilyMembersScore(PersonDto personDto){
  39. int result = 0;
  40. if (personDto.getFamilyMembers() < 5) {
  41. result += 5;
  42. } else if (personDto.getFamilyMembers() >= 5) {
  43. result += 10;
  44. }
  45. return result;
  46. }
  47. private int getFaceScore(PersonDto personDto){
  48. int result = 0;
  49. if (personDto.getFaceScore() < 5) {
  50. result += 5;
  51. } else if (personDto.getFaceScore() >= 5) {
  52. result += 10;
  53. }
  54. return result;
  55. }
  56. private int getHeightScore(PersonDto personDto){
  57. int result = 0;
  58. if (personDto.getHeight() < 170) {
  59. result += 5;
  60. } else if (personDto.getHeight() >= 170) {
  61. result += 10;
  62. }
  63. return result;
  64. }
  65. }
  66. public class Child {
  67. public int getTreasureIndicator() {
  68. PersonService personService = new PersonService();
  69. PersonDto personDto = new PersonDto();
  70. personDto.setAge(10);
  71. return personService.getTreasureIndicator(personDto);
  72. }
  73. public int getHealthIndicator() {
  74. PersonService personService = new PersonService();
  75. PersonDto personDto = new PersonDto();
  76. personDto.setAge(10);
  77. return personService.getHealthIndicator(personDto);
  78. }
  79. }
  80. public class Old {
  81. public int getTreasureIndicator() {
  82. PersonService personService = new PersonService();
  83. PersonDto personDto = new PersonDto();
  84. personDto.setAge(50);
  85. personDto.setSex(SexEnum.SEX_GIRL.getSex());
  86. return personService.getTreasureIndicator(personDto);
  87. }
  88. public int getHealthIndicator() {
  89. PersonService personService = new PersonService();
  90. PersonDto personDto = new PersonDto();
  91. personDto.setAge(10);
  92. return personService.getHealthIndicator(personDto);
  93. }
  94. }
  95. public class Test {
  96. public static void main(String[] args) {
  97. Child child = new Child();
  98. Old old = new Old();
  99. System.out.println("child-treasure:" + child.getTreasureIndicator());
  100. System.out.println("child-health:" + child.getHealthIndicator());
  101. System.out.println("old-treasure:" + old.getTreasureIndicator());
  102. System.out.println("old-health:" + old.getHealthIndicator());
  103. }
  104. }
  105. child-treasure:20
  106. child-health:20
  107. old-treasure:30
  108. old-health:20

然后相关需求一来,又要加一种类型,就会导致这个服务越来越大,大到最后你不可维护,变成传说中的祖传代码,如果是如上这种情况,博主建议大家可以新建一个服务类,让各个服务类的职责单一(单一指责原则)。

  1. public class PersonService {
  2. protected int getAgeScore(PersonDto personDto){
  3. int result = 0;
  4. if (personDto.getAge() < 20) {
  5. result += 5;
  6. } else if (personDto.getAge() >= 20) {
  7. result += 10;
  8. }
  9. return result;
  10. }
  11. protected int getSexScore(PersonDto personDto){
  12. int result = 0;
  13. if (personDto.getSex() == SexEnum.SEX_GIRL.getSex()) {
  14. result += 5;
  15. } else if (personDto.getSex() == SexEnum.SEX_BOY.getSex()) {
  16. result += 10;
  17. }
  18. return result;
  19. }
  20. protected int getFamilyMembersScore(PersonDto personDto){
  21. int result = 0;
  22. if (personDto.getFamilyMembers() < 5) {
  23. result += 5;
  24. } else if (personDto.getFamilyMembers() >= 5) {
  25. result += 10;
  26. }
  27. return result;
  28. }
  29. protected int getFaceScore(PersonDto personDto){
  30. int result = 0;
  31. if (personDto.getFaceScore() < 5) {
  32. result += 5;
  33. } else if (personDto.getFaceScore() >= 5) {
  34. result += 10;
  35. }
  36. return result;
  37. }
  38. protected int getHeightScore(PersonDto personDto){
  39. int result = 0;
  40. if (personDto.getHeight() < 170) {
  41. result += 5;
  42. } else if (personDto.getHeight() >= 170) {
  43. result += 10;
  44. }
  45. return result;
  46. }
  47. }
  48. public class PersonHealthService extends PersonService{
  49. public int getHealthIndicator(PersonDto personDto) {
  50. int result = 0;
  51. result += getAgeScore(personDto);
  52. result += getSexScore(personDto);
  53. result += getFamilyMembersScore(personDto);
  54. result += getFaceScore(personDto);
  55. result += getHeightScore(personDto);
  56. return result;
  57. }
  58. }
  59. public class PersonTreasureService extends PersonService{
  60. public int getTreasureIndicator(PersonDto personDto) {
  61. int result = 0;
  62. result += getAgeScore(personDto);
  63. result += getSexScore(personDto);
  64. result += getFamilyMembersScore(personDto);
  65. result += getFaceScore(personDto);
  66. result += getHeightScore(personDto);
  67. return result;
  68. }
  69. }

因为两个服务有很多的共性代码,所以直接抽出来作为他们的父类,所以也就有上面的代码了,这样以后有新的业务进来,只需要创建对应的服务类就可以了(开闭原则)。

六、请规范好请求参数

在写接口的时候,很多人会遇到该用基础类型的字段呢(int、String之类)还是使用对象来接收呢,如果用对象来接收,大家就会倾向于,后续相关的接口还是直接用这个对象来接收,这就会导致对象的字段越来越多,最后造成前端每次都会过来问,这个接口应该传哪些字段。。。

分层领域模型规约:

  1. DO(Data Object):与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。(Entity)
  2. DTO(Data Transfer Object):数据传输对象,Service 和 Manager 向外传输的对象。
  3. BO(Business Object):业务对象。可以由 Service 层输出的封装业务逻辑的对象。
  4. QUERY:数据查询对象,各层接收上层的查询请求。注:超过 2 个参数的查询封装,禁止 使用 Map 类来传输。
  5. VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。

接口的请求参数要准确,前端不需要传的字段,最好不要暴露出去,这样也会减少双方的沟通成本,而且后续升级接口的时候,也可以确定参数的各自含义。

  1. @Controller
  2. @RequestMapping("/api/person")
  3. @Slf4j
  4. public class PersonController {
  5. @ResponseBody
  6. @PostMapping("/getChildHealthIndicator")
  7. public int getChildHealthIndicator(@RequestBody PersonDto personDto) {
  8. Child child = new Child();
  9. return child.getHealthIndicator(personDto.getAge());
  10. }
  11. }

就比如getChildHealthIndicator接口只需要age值,但是前端那边看到却是personDto对象,这样就会对剩余的参数产生困扰。

  1. @Controller
  2. @RequestMapping("/api/person")
  3. @Slf4j
  4. public class PersonController {
  5. @ResponseBody
  6. @PostMapping("/getChildHealthIndicator")
  7. public int getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
  8. Child child = new Child();
  9. return child.getHealthIndicator(childHealthIndicatorQuery.getAge());
  10. }
  11. }
  12. @Data
  13. public class ChildHealthIndicatorQuery {
  14. private int age;
  15. }

如果用ChildHealthIndicatorQuery来代替PersonDto,这样前端看到的就只有age这个字段,可以无歧义的进行传参。当然正常开发过程中,肯定不会设计的这么细,不然会产生大量的pojo对象,要根据实际项目来设计。

七、entity中请不要做参数校验

我以前遇到同事,直接在entity(数据库表映射类)里面做判断,然后另外一个同事,因为数据库新增了字段,所以又重新生成了一遍entity类(mybatis插件生成),写完业务代码后发布,最后结果可想而知。

对于entity类,是绝对禁止任何层面的判断修改的,因为这个类随时都有可能被覆盖。

八、http返回码请不要直接返回一个字段

很多童鞋刚开始写代码的时候,很喜欢接口业务需要返回什么内容,就直接返回数据,例如上面的案例就是直接返回一个int值。

  1. @Controller
  2. @RequestMapping("/api/person")
  3. @Slf4j
  4. public class PersonController {
  5. @ResponseBody
  6. @PostMapping("/getChildHealthIndicator")
  7. public int getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
  8. Child child = new Child();
  9. return child.getHealthIndicator(childHealthIndicatorQuery.getAge());
  10. }
  11. }

但是大家要知道,任何的接口都有出问题的可能性,而且问题还不止一种,可能是五花八门,前端可能需要根据不同的错误进行相应的提示,所以直接返回一个字段数据肯定是不合理的。一般来说,至少需要返回三个字段:code(状态码)、msg(状态码对应的说明)、data(接口的业务数据),我们将上面的接口修改一下。

  1. @Controller
  2. @RequestMapping("/api/person")
  3. @Slf4j
  4. public class PersonController {
  5. @ResponseBody
  6. @PostMapping("/getChildHealthIndicator")
  7. public CustResponse getChildHealthIndicator(@RequestBody ChildHealthIndicatorQuery childHealthIndicatorQuery) {
  8. Child child = new Child();
  9. CustResponse custResponse = new CustResponse();
  10. try{
  11. int result = child.getHealthIndicator(childHealthIndicatorQuery.getAge());
  12. custResponse.setCode(200);
  13. custResponse.setMsg("success");
  14. custResponse.setDetails(result);
  15. }catch (Exception e){
  16. custResponse.setCode(500);
  17. custResponse.setMsg(e.getMessage());
  18. }
  19. return custResponse;
  20. }
  21. }
  22. @Data
  23. @ApiModel
  24. public class CustResponse {
  25. /**
  26. * 200 成功
  27. * 500 失败
  28. */
  29. @ApiModelProperty(value = "状态码,200 = '成功',500 = '失败'")
  30. private Integer code;
  31. @ApiModelProperty(value = "返回消息")
  32. private String msg;
  33. @ApiModelProperty(value = "返回实体")
  34. private Object details;
  35. public CustResponse() {
  36. super();
  37. }
  38. /**
  39. * @param code
  40. * @param msg
  41. */
  42. public CustResponse(Integer code, String msg) {
  43. super();
  44. this.code = code;
  45. this.msg = msg;
  46. }
  47. /**
  48. * @param code
  49. * @param details
  50. */
  51. public CustResponse(Integer code, Object details) {
  52. super();
  53. this.code = code;
  54. this.details = details;
  55. }
  56. }

九、请定义好异常的状态码

很多童靴抛异常,很喜欢直接抛出RuntimeException异常,然后就一串异常信息,想看这个异常是属于哪一个服务,哪一块业务,核心参数等,都没有。。。排查问题难度直线上升。

所以定义异常的时候一般需要定义code+msg(可以根据自己需求添加),例如:

  1. /**
  2. * 基础异常类
  3. * 用途:用于在处理业务时,向框架抛出异常,框架将该异常作为错误信息进行输出。<br>
  4. * 使用场景:比如在深层业务代码判断参数无正确,就可以直接抛出该异常。<br>
  5. * <pre>
  6. * code rule:{2}{2}{4}
  7. * | | |
  8. * sys | |
  9. * module|
  10. * error
  11. * 如:[10020001]前四位数为系统+模块编号,后4位为错误代码
  12. *
  13. * @Author: linzhiqiang
  14. */
  15. @Data
  16. public class BaseException extends RuntimeException implements Serializable {
  17. private static final long serialVersionUID = -5196111058043675557L;
  18. /**
  19. * 参数不能为空
  20. **/
  21. public static final BaseException PARAMS_NOT_NULL = new BaseException(10000000, "参数{0}不能为空");
  22. /**
  23. * 参数非法
  24. **/
  25. public static final BaseException PARAMS_IS_ILLICIT = new BaseException(10000001, "参数{0}非法");
  26. private Integer code;
  27. private String msg;
  28. public BaseException() {
  29. super();
  30. }
  31. public BaseException(String msg) {
  32. super(msg);
  33. this.msg = msg == null ? "" : msg;
  34. }
  35. public BaseException(Integer code, String msg) {
  36. super(msg);
  37. this.code = code;
  38. this.msg = msg == null ? "" : msg;
  39. }
  40. public BaseException(Integer code, String msg, Integer userId) {
  41. super(msg);
  42. this.code = code;
  43. msg = msg == null ? "" : msg;
  44. this.msg = userId + ":" + msg;
  45. }
  46. /**
  47. * 格式化消息
  48. *
  49. * @param args
  50. */
  51. public BaseException format(Object... args) {
  52. return new BaseException(this.code, MessageFormat.format(this.msg, args));
  53. }
  54. }
  55. public int getHealthIndicator(int age) {
  56. if (age < 0) {
  57. BaseException baseException = new BaseException(01010001, "年龄不能小于0");
  58. throw baseException;
  59. }
  60. PersonHealthService personService = new PersonHealthService();
  61. PersonDto personDto = new PersonDto();
  62. personDto.setAge(age);
  63. return personService.getHealthIndicator(personDto);
  64. }

通过这种方式抛出的异常,我们就可以很明显的找到这个异常对应的服务、模块、错误内容,加快我们排查效率。

十、不要吝啬,请多打点错误日志

很多童靴写代码没有打印日志的习惯,可能很多时候因为是本地开发,出问题的时候直接调试一下就ko bug了,但是到线上的时候可没办法进行错误调试,甚至有些错误是瞬间性的,下一刻你就复现不出来了,所以如果没有日志记录这些错误信息,那就相当于蒙着眼睛过河一样,岌岌可危。

总结:

日常开发经验就分享到这边了,当然还有很多很多的场景博主没有说,这得靠童鞋们平时的积累了。博客的爬坑历程就到这边了,对上述有疑问或者想分享交流的童靴,欢迎随时@博主哦~

想要更多干货、技术猛料的孩子,快点拿起手机扫码关注我,我在这里等你哦~

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X2pwZy9zdTUxaWJiaWF5dnhzZEkwODVpY1JNWWljTDVFaWIwMVkxZ0drcTVNdWxMdXJ6T0QzU251V2oydzA5cjgwSnBTdm5xSTJtV2g0QUJ5RmhJTnZ1bHhwS2I2b1JBLzY0MD93eF9mbXQ9anBlZw

林老师带你学编程:https://wolzq.com

发表评论

表情:
评论列表 (有 0 条评论,90人围观)

还没有评论,来说两句吧...

相关阅读

    相关 如何质量代码

    即使是最优秀的开发人员也可能写出低质量的代码,这是正常的。不过,以下是一些编写高质量代码的实用技巧,可以帮助你提高代码的质量和可维护性。 1. 编写可读性强的代码。你的代码

    相关 如何质量代码

    一、 前言 > 编写高质量代码是每一位程序员的追求。高质量的代码可以提高代码可读性、可维护性、可扩展性以及软件运行的性能和稳定性。在这篇文章中,我将分享一些编写高质量代码的特

    相关 如何质量的简历?!

    见字如面,我是军哥! 现在找工作难,简历再写不好就更难了! 说真,我看过几千位程序员的简历,至少面试过 400/500 人,我发现 80% 的人简历或多或少都有这样那样的问

    相关 质量代码10个Tips

    很长一段时间以来,我都在关注如何提高代码质量,也为此做过一些尝试,我想这个话题可能大家会比较感兴趣,在这里分享一下我关于如何提高代码质量的一些体会。 ![640_wx_fmt_