本文目录导读:

我来详细讲解Java实现REST API的几种主流方式及完整案例。
基于Spring Boot的实现(最常用)
项目结构
rest-api-demo/
├── src/main/java/com/example/demo/
│ ├── controller/
│ │ └── UserController.java
│ ├── model/
│ │ └── User.java
│ ├── service/
│ │ └── UserService.java
│ └── DemoApplication.java
├── src/main/resources/
│ └── application.yml
└── pom.xml
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<groupId>com.example</groupId>
<artifactId>rest-api-demo</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
实体类(Model)
package com.example.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.*;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度2-20个字符")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能超过150")
private Integer age;
private LocalDateTime createTime;
}
控制器(Controller)
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// GET - 获取所有用户
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
return ResponseEntity.ok(userService.findAll());
}
// GET - 根据ID获取用户
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST - 创建用户
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User createUser(@Valid @RequestBody User user) {
return userService.create(user);
}
// PUT - 更新用户
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@Valid @RequestBody User user) {
return userService.update(id, user)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// DELETE - 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
if (userService.delete(id)) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
// GET - 根据条件查询
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age) {
return ResponseEntity.ok(userService.search(name, age));
}
}
服务层(Service)
package com.example.demo.service;
import com.example.demo.model.User;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
@Service
public class UserService {
private final Map<Long, User> users = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
public List<User> findAll() {
return new ArrayList<>(users.values());
}
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
public User create(User user) {
Long id = idGenerator.getAndIncrement();
user.setId(id);
user.setCreateTime(LocalDateTime.now());
users.put(id, user);
return user;
}
public Optional<User> update(Long id, User user) {
if (users.containsKey(id)) {
user.setId(id);
user.setCreateTime(users.get(id).getCreateTime());
users.put(id, user);
return Optional.of(user);
}
return Optional.empty();
}
public boolean delete(Long id) {
return users.remove(id) != null;
}
public List<User> search(String name, Integer age) {
return users.values().stream()
.filter(u -> name == null || u.getUsername().contains(name))
.filter(u -> age == null || u.getAge().equals(age))
.collect(Collectors.toList());
}
}
application.yml配置
server:
port: 8080
spring:
application:
name: rest-api-demo
全局异常处理
package com.example.demo.config;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.badRequest().body(errors);
}
}
API测试
使用curl测试
# 创建用户
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"username":"张三","email":"zhangsan@example.com","age":25}'
# 获取所有用户
curl http://localhost:8080/api/users
# 获取单个用户
curl http://localhost:8080/api/users/1
# 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{"username":"李四","email":"lisi@example.com","age":30}'
# 删除用户
curl -X DELETE http://localhost:8080/api/users/1
# 搜索用户
curl "http://localhost:8080/api/users/search?name=张&age=25"
使用JUnit测试
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void testCreateUser() throws Exception {
User user = new User();
user.setUsername("测试用户");
user.setEmail("test@example.com");
user.setAge(25);
when(userService.create(any(User.class))).thenReturn(user);
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.username").value("测试用户"));
}
}
REST API设计建议
URL设计规范
// 集合资源
GET /api/users // 获取用户列表
POST /api/users // 创建用户
GET /api/users/{id} // 获取单个用户
PUT /api/users/{id} // 更新用户
DELETE /api/users/{id} // 删除用户
// 子资源
GET /api/users/{id}/orders // 获取用户的订单
POST /api/users/{id}/orders // 创建用户订单
// 过滤和排序
GET /api/users?page=0&size=10&sort=age,desc
GET /api/users?name=张三&age=25
响应格式
// 成功响应
{
"status": 200,
"message": "success",
"data": {
"id": 1,
"username": "张三",
"email": "zhangsan@example.com",
"age": 25
}
}
// 错误响应
{
"status": 400,
"message": "验证失败",
"errors": {
"username": "用户名不能为空",
"email": "邮箱格式不正确"
}
}
// 分页响应
{
"status": 200,
"data": {
"content": [...],
"totalElements": 100,
"totalPages": 10,
"number": 0,
"size": 10
}
}
其他实现方式
使用JAX-RS
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/api/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
@GET
public Response getAllUsers() {
return Response.ok(userService.findAll()).build();
}
@GET
@Path("/{id}")
public Response getUserById(@PathParam("id") Long id) {
return userService.findById(id)
.map(u -> Response.ok(u).build())
.orElse(Response.status(404).build());
}
@POST
public Response createUser(User user) {
return Response.status(Response.Status.CREATED)
.entity(userService.create(user))
.build();
}
}
使用Micronaut
import io.micronaut.http.annotation.*;
import io.micronaut.http.HttpStatus;
import javax.validation.Valid;
@Controller("/api/users")
public class UserController {
@Get
public List<User> getAll() {
return userService.findAll();
}
@Post
@Status(HttpStatus.CREATED)
public User create(@Body @Valid User user) {
return userService.create(user);
}
}
这个案例涵盖了创建REST API的完整流程,包括实体的定义、控制器的实现、异常处理以及测试,你可以根据实际需求选择合适的技术栈。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播