Spring MVC 透過 @ResponseBody 配合 HttpMessageConverter 將回傳物件自動序列化為 JSON。預設使用 Jackson (MappingJackson2HttpMessageConverter)。
@RestController // 等同 @Controller + 所有方法隱含 @ResponseBody
@RequestMapping("/api/json")
public class JsonController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id); // 自動序列化為 JSON
}
@PostMapping("/user")
public User createUser(@RequestBody User user) { // 自動反序列化請求體
return userService.save(user);
}
}
Jackson 預設使用 ISO-8859-1 編碼輸出,導致中文字元變亂碼。
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list><value>text/plain;charset=UTF-8</value></list>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list><value>application/json;charset=UTF-8</value></list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?> converters) {
// 1. JSON 轉換器 (Jackson 2.x)
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(Arrays.asList(
MediaType.APPLICATION_JSON_UTF8,
new MediaType("application", "json", StandardCharsets.UTF_8)
));
// 自訂 ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
jsonConverter.setObjectMapper(mapper);
converters.add(jsonConverter);
// 2. String 轉換器 (處理純文字回應)
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
converters.add(stringConverter);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?> converters) {
// 確保 UTF-8 排在最前
converters.stream()
.filter(c -> c instanceof StringHttpMessageConverter)
.findFirst()
.ifPresent(c -> ((StringHttpMessageConverter) c).setDefaultCharset(StandardCharsets.UTF_8));
}
}
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.mvc.converters.preferred-json-mapper=jackson
# Jackson 日期格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-dates-as-timestamps=false
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
return mapper;
}
// 注入到 MappingJackson2HttpMessageConverter
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
public class Order {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate shipDate; // Java 8 時間 API 直接支援
}
| 現象 | 可能原因 | 解決 |
|---|---|---|
| 中文亂碼 | Converter 編碼未設 UTF-8 | 配置 supportedMediaTypes 含 charset=UTF-8 |
| 日期變時間戳 | Jackson 預設 WRITE_DATES_AS_TIMESTAMPS=true | 設為 false 並指定 date-format |
| @ResponseBody 406 | Accept 標頭不匹配 / 缺 Jackson 依賴 | 引入 jackson-databind、檢查 produces 設定 |
| 大量資料 OOM | 一次序列化大 List | 分頁、串流輸出 (ResponseBodyEmitter) |