Spring请求传递JSON数据的完整指南

一、基础配置

1.1 添加依赖

<!-- Spring Boot Web Starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Jackson for JSON处理 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>
图片[1]_Spring请求传递JSON数据的完整指南_知途无界

1.2 配置HTTP消息转换器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }
}

二、服务端接收JSON

2.1 基本接收方式

@RestController
@RequestMapping("/api")
public class JsonController {
    
    @PostMapping("/basic")
    public ResponseEntity<String> handleBasic(@RequestBody Map<String, Object> payload) {
        String name = (String) payload.get("name");
        return ResponseEntity.ok("Received: " + name);
    }
}

2.2 绑定到POJO对象

public class UserDTO {
    private String username;
    private String email;
    private Integer age;
    
    // 必须有无参构造函数
    public UserDTO() {}
    
    // Getter和Setter方法
    // 省略...
}

@PostMapping("/object")
public ResponseEntity<UserDTO> handleObject(@RequestBody UserDTO user) {
    // 直接操作对象
    user.setEmail(user.getEmail().toLowerCase());
    return ResponseEntity.ok(user);
}

三、客户端发送JSON

3.1 使用RestTemplate

@RestController
public class ClientController {
    
    @GetMapping("/send")
    public String sendJson() {
        RestTemplate restTemplate = new RestTemplate();
        
        // 准备请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        
        // 构建请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("name", "Spring User");
        requestBody.put("age", 5);
        
        HttpEntity<Map<String, Object>> request = 
            new HttpEntity<>(requestBody, headers);
        
        // 发送请求
        String url = "http://localhost:8080/api/basic";
        ResponseEntity<String> response = 
            restTemplate.postForEntity(url, request, String.class);
        
        return response.getBody();
    }
}

3.2 使用WebClient (Reactive)

@Bean
public WebClient webClient() {
    return WebClient.builder()
            .baseUrl("http://localhost:8080")
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
}

@GetMapping("/send-reactive")
public Mono<String> sendJsonReactive() {
    Map<String, Object> requestBody = Map.of(
        "name", "Reactive User",
        "age", 3
    );
    
    return webClient.post()
            .uri("/api/basic")
            .bodyValue(requestBody)
            .retrieve()
            .bodyToMono(String.class);
}

四、高级特性

4.1 自定义JSON处理器

@Configuration
public class JacksonConfig {
    
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> {
            builder.serializationInclusion(JsonInclude.Include.NON_NULL);
            builder.featuresToEnable(SerializationFeature.INDENT_OUTPUT);
            builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        };
    }
}

4.2 验证JSON数据

public class ValidUserDTO {
    @NotBlank
    @Size(min = 3, max = 20)
    private String username;
    
    @Email
    private String email;
    
    @Min(18)
    private Integer age;
    
    // Getter/Setter...
}

@PostMapping("/validate")
public ResponseEntity<?> handleValidated(@Valid @RequestBody ValidUserDTO user) {
    // 只有通过验证才会执行到这里
    return ResponseEntity.ok(user);
}

@ControllerAdvice
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);
    }
}

五、测试JSON接口

5.1 使用MockMvc测试

@SpringBootTest
@AutoConfigureMockMvc
public class JsonControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testJsonEndpoint() throws Exception {
        String jsonContent = "{\"username\":\"testuser\",\"email\":\"test@example.com\"}";
        
        mockMvc.perform(post("/api/object")
                .contentType(MediaType.APPLICATION_JSON)
                .content(jsonContent))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.email").value("test@example.com"));
    }
}

5.2 使用TestRestTemplate

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class JsonIntegrationTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testJsonIntegration() {
        Map<String, String> request = Map.of(
            "username", "integration",
            "email", "integration@test.com"
        );
        
        ResponseEntity<UserDTO> response = restTemplate.postForEntity(
            "/api/object", 
            request, 
            UserDTO.class
        );
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody().getEmail());
    }
}

六、性能优化

6.1 流式处理大JSON

@PostMapping("/large")
public void handleLargeJson(InputStream inputStream) throws IOException {
    JsonFactory factory = new JsonFactory();
    JsonParser parser = factory.createParser(inputStream);
    
    while (parser.nextToken() != null) {
        // 流式处理每个token
        String fieldName = parser.getCurrentName();
        if ("importantField".equals(fieldName)) {
            parser.nextToken();
            String value = parser.getText();
            // 处理关键字段
        }
    }
    parser.close();
}

6.2 异步JSON处理

@PostMapping("/async")
public CompletableFuture<ResponseEntity<UserDTO>> handleAsync(@RequestBody UserDTO user) {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟耗时处理
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        user.setUsername(user.getUsername().toUpperCase());
        return ResponseEntity.ok(user);
    });
}

七、常见问题解决方案

7.1 日期格式处理

public class EventDTO {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime eventTime;
    
    // Getter/Setter...
}

// 或者全局配置
@Bean
public Jackson2ObjectMapperBuilderCustomizer dateCustomizer() {
    return builder -> builder.dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
}

7.2 处理多态JSON

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Cat.class, name = "cat"),
    @JsonSubTypes.Type(value = Dog.class, name = "dog")
})
public abstract class Animal {
    private String name;
    // ...
}

public class Cat extends Animal {
    private Boolean likesCream;
    // ...
}

@PostMapping("/animals")
public ResponseEntity<String> handleAnimal(@RequestBody Animal animal) {
    if (animal instanceof Cat) {
        return ResponseEntity.ok("Received a cat");
    }
    return ResponseEntity.ok("Received some animal");
}

八、安全注意事项

8.1 JSON注入防护

@Bean
public MappingJackson2HttpMessageConverter jsonMessageConverter() {
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    ObjectMapper mapper = new ObjectMapper();
    
    // 防止JSON注入
    mapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
    mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
    
    converter.setObjectMapper(mapper);
    return converter;
}

8.2 大小限制配置

# application.properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
spring.jackson.parser.max-string-length=1048576 # 1MB

最佳实践建议​:

  1. 始终为JSON模型类实现toString()方法便于调试
  2. 生产环境应开启完整的JSON输入验证
  3. 对于公共API,考虑使用JSON Schema验证
  4. 在Controller层处理业务异常,返回结构化的JSON错误响应
  5. 考虑使用Swagger/OpenAPI文档化JSON接口

性能关键点​:

  1. 大JSON使用流式处理避免内存溢出
  2. 频繁调用的接口可考虑JSON字段过滤
  3. 启用GZIP压缩减少传输体积
  4. 对不变的数据结构考虑JSON序列化缓存
© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞43 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容