• 如何写得一手优雅规范的SpringBoot 接口?


    导语

    优雅的代码赏心悦目,你的代码触目惊心。

    当编写 Spring Boot 接口时,优雅和规范是至关重要的。一个良好设计的接口能够提高代码的可读性、可维护性和可扩展性,从而为整个应用程序的开发和维护带来便利。

    在本文中,我们将探讨如何通过遵循最佳实践和设计原则,编写出优雅规范的 Spring Boot 你的接口也可以像企业级项目接口一般规范且优雅。


    严格遵循RESTful API 设计原则

    • 清晰一致的资源命名:使用准确反映 API 管理的资源的名词(例如,/articles、/users)。
    @GetMapping("/articles/{id}")
    public ResponseEntity<Product> getArticleById(@PathVariable Long id) {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 标准化 HTTP 方法:遵循 CRUD 操作的 RESTful 约定(CREATE: POST、READ: GET、UPDATE: PUT、DELETE:DELETE)。
    @PostMapping("/users")
    public ResponseEntity<User> createUser(@RequestBody User user) {
        // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 有意义的状态代码:返回相应的 HTTP 状态代码,如成功 (2xx)、错误 (4xx) 或服务器问题 (5xx)。
    @DeleteMapping("/articles/{id}")
    public ResponseEntity<?> deleteArticle(@PathVariable Long id) {
        if (productService.deleteArticle(id)) {
            return ResponseEntity.noContent().build(); // 204 No Content
        } else {
            return ResponseEntity.notFound().build(); // 404 Not Found
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    关于更多restful标准,参考https://en.wikipedia.org/wiki/REST


    合理利用好 Spring Boot 注解

    这里所谓得合理,不是很好定义,但本着高效、简洁、清晰得原则推荐。

    • @RestController:默认情况下,将控制器标记为返回 JSON 或其他结构化数据。

    这是一个综合注解,是@Controller@ResponseBody的功能于一身,一个注解作两个注解的事情,简洁高效。

    @RestController
    public class HelloController {
        // .....
    }
    
    • 1
    • 2
    • 3
    • 4
    • @RequestMapping:定义每个controller的基本路径。

    这样做可以使代码更加整洁和易于维护。不需要在每个方法上都重复写基本路径部分,在类级别定义基本路径可以带来更清晰、更简洁、更易维护的代码结构,同时也有助于提高开发效率和代码质量。

    @RestController
    @RequestMapping("/user")
    public class HelloController {
        // .....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 使用简化的请求方式注解。

    在不同类型的方法上直接使用@GetMapping、@PostMapping、@PutMapping@DeleteMapping注解进行标识,而不是使用笼统的 @RequestMapping(method = RequestMethod.POST)

    • 使用@PathVariable获取请求的路径变量;
    @RestController
    @RequestMapping("/articles")
    public class ArticleController {
    
        @GetMapping("/{id}")
        public ResponseEntity<Article> getArticleById(@PathVariable Long id) {
            // 根据文章的id查询文章
            Article article = articleService.findArticleById(id);
    
            if (article != null) {
                return ResponseEntity.ok(article);
            } else {
                return ResponseEntity.notFound().build();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 使用@RequestBody将请求正文内容反序列化为 Java 对象。
    @RestController
    @RequestMapping("/api")
    public class UserController {
    
        @PostMapping("/users")
        public ResponseEntity<User> createUser(@RequestBody User user) {
            // 这里的 User 对象会从请求的 JSON 数据中反序列化得到
            userService.saveUser(user);
            return ResponseEntity.ok(user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    关于依赖注入的使用建议

    • 使用构造函数注入方式

    通过在类的构造函数中接受依赖对象作为参数来进行注入。这种方式可以确保依赖在对象创建时被注入,提高了代码的可测试性和可维护性。

    @RestController
    public class ProductController {
    
        private final ProductService productService;
    
        public ProductController(ProductService productService) {
            this.productService = productService;
        }
        // ... other controller methods
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    针对接口的异常处理

    • @ControllerAdvice的使用
    @ControllerAdvice
    public class ApiExceptionHandler {
        @ExceptionHandler(ArticleNotFoundException.class)
        public ResponseEntity<ErrorResponse> handleArticleNotFound(ArticleNotFoundException ex) {
            // ... create error response with details
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用DTO代替POJO的直接使用

    对于数据传输对象,建议对pojo进行dto的封装,而不是使用原实体。提高代码的可读性、可维护性和数据封装性。

    public class ArticleDto {
        private Long id;
        private String title;
        private String contents;
        // more
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接口安全的建议

    • 使用SpringSecurity等安全框架进行认证授权,包括令牌机制的使用,如JWT
    • 对接口进行常见的漏洞检查并采取防范措施,比如XSSSQL注入等。
    • 使用https进行网络通信;

    关于版本控制

    • 使用路径版本控制(例如,/api/v1/articles)或基于标头的版本控制。

    使用版本控制 API 来管理更改并保持与客户端的兼容性。

    @RestController
    @RequestMapping("/api/products")
    public class ProductController {
    
        @GetMapping("/details")
        public ResponseEntity<String> getProductDetails(@RequestHeader("Accept-Version") String version) {
            if ("v1".equals(version)) {
                return ResponseEntity.ok("Product details for version 1");
            } else if ("v2".equals(version)) {
                return ResponseEntity.ok("Product details for version 2");
            } else {
                return ResponseEntity.badRequest().body("Unsupported version");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    完备的接口测试

    • 考虑使用 Mockito JUnit 等工具对每个接口进行测试,保证接口的准确性和稳健性。

    本文小结

    上面虽然列举好几种编写接口的规范和建议,但这些不是一成不变的,在具体的项目,还需要根据业务和项目需求做出一些让步和改动,灵活运用这些建议,你的接口也可以很优雅。代码就是一行行蓝色的诗,而不是冰冷乏味的英文串

  • 相关阅读:
    Mysql数据库清空表中数据、删除表
    【笔试题】【day21】
    uniapp使用vue
    python django 小程序图书借阅源码
    leetcode 1586 二叉搜索树迭代器 II 与 173. 二叉搜索树迭代器
    C/C++编程 —— 读取和保存 TXT 文本
    UVA 10050【埃筛】【set】
    python基础语法快速复习
    cpp随笔——浅谈右值引用,移动语义与完美转发
    【 java 常用类】你不知道的String
  • 原文地址:https://blog.csdn.net/2302_76401343/article/details/138207846