引言:Java API的演进
\n\nJava开发的世界并非一成不变。就在10年前,选择还很明确:REST和JSON。而如今,在设计微服务架构或移动应用时,开发者会面对各种各样的协议。REST、GraphQL、gRPC——每一个都承诺带来天堂般的体验,但实际上,每项技术背后都伴随着权衡取舍。
\n\n在本文中,我们不会复述文档。我们将采用一个实际的任务:我们需要为一个教育平台创建一个API(就像我们的PythonLib,但使用Java)。我们有课程、学生和学习进度。我们将尝试用三种不同的方式来实现同一个端点。
\n\n让我们开始分析,看看哪种协议能让你的代码更快,生活更简单。
\n\nJava上的REST API:永不消亡的经典
\n\nREST(表述性状态转移)是一种架构风格,而非协议。在Java中,REST的事实标准是Spring Boot及其注解。简单、易懂、庞大的社区——这就是我们喜爱REST的原因。
\n\n示例:获取课程列表
\n\n假设我们需要向客户端返回所有课程及其基本信息的列表:
\n\n@RestController\n@RequestMapping("/api/courses")\npublic class CourseController {\n\n @GetMapping\n public ResponseEntity<List<CourseDTO>> getAllCourses() {\n List<Course> courses = courseService.findAll();\n List<CourseDTO> dtos = courses.stream()\n .map(c -> new CourseDTO(c.getId(), c.getTitle(), c.getAuthor()))\n .toList();\n return ResponseEntity.ok(dtos);\n }\n}\n\n客户端收到JSON:
\n\n[\n {"id": 1, "title": "Java入门", "author": "伊万·彼得罗夫"},\n {"id": 2, "title": "Spring Boot大师班", "author": "安娜·斯米尔诺娃"}\n]\n\nJava上REST的优点:
\n- \n
- 入门门槛极低——任何Java开发者都了解Spring。 \n
- 通过HTTP头(ETag、Cache-Control)进行缓存。 \n
- 广泛的工具支持(Postman、Swagger、OpenAPI)。 \n
缺点:
\n- \n
- 过度获取(多余数据)和获取不足(数据不够,需要多次请求)的问题。 \n
- 弱类型——一切由易于违反的契约决定。 \n
当客户端是第三方,并且您需要最大兼容性时,REST是公共API的理想选择。但如果您的客户端是一个移动应用,希望只获取所需的数据,REST就会开始让人烦恼。
\n\nJava上的GraphQL:只给我我请求的数据
\n\nGraphQL是一种查询语言,由Facebook创建。在Java中,最常通过graphql-java库或与Spring的集成GraphQL Kickstart来实现。
\n\n客户端自己决定需要哪些字段。没有过度获取。一次请求,你就能获得课程以及学生的学习进度。
\n\n示例:GraphQL schema和resolver
\n\n定义schema:
\n\ntype Course {\n id: ID!\n title: String!\n author: String!\n progress(studentId: ID!): Int\n}\n\ntype Query {\n courses: [Course!]!\n}\n\n用Java编写resolver:
\n\n@Component\npublic class CourseResolver implements GraphQLQueryResolver {\n\n @Autowired\n private CourseService courseService;\n\n public List<Course> courses() {\n return courseService.findAll();\n }\n}\n\n@Component\npublic class CourseFieldResolver implements GraphQLResolver<Course> {\n\n @Autowired\n private ProgressService progressService;\n\n public Integer progress(Course course, Long studentId) {\n return progressService.getProgress(course.getId(), studentId);\n }\n}\n\n来自客户端的查询:
\n\nquery {\n courses {\n title\n