后臺提供API給前端調(diào)用选调,一般使用
HttpMessageConverter
把Json字符串轉(zhuǎn)換成對象肩钠,如果存在格式問題則會拋出異常HttpMessageNotReadableException
图甜。但是后臺拿不到原始的Json字符串,不方便定位到確切的格式錯誤。 本文介紹一個簡易方法祷膳,可以在出錯時,展示Json原文信息乃戈。
一開始想尋找其他方式褂痰,當(dāng)拋出異常的時候,就從HttpServletRequest
讀取body內(nèi)容症虑。但是做不到缩歪,因為在做Json讀取的時候,InputStream已經(jīng)被讀取了谍憔,無法再次獲取到body內(nèi)容匪蝙。所以只能通過自定義MessageConverter
的方式。
其實也可以韵卤,把request中inpustream讀取出來保存骗污,再提供一個getInputStream,參見 How to read request.getInputStream() multiple times
自定義MessageConverter
- Spring4
import com.google.common.io.CharStreams;
public class HttpMessageConverter extends GsonHttpMessageConverter {
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
TypeToken<?> token = getTypeToken(type);
return readTypeToken(token, inputMessage);
}
private Object readTypeToken(TypeToken<?> token, HttpInputMessage inputMessage) throws IOException {
Reader json = new InputStreamReader(inputMessage.getBody(), getCharset(inputMessage.getHeaders()));
//先獲取Json原始字符串
final String jsonBody = CharStreams.toString(json);
try {
return this.getGson().fromJson(jsonBody, token.getType());
} catch (JsonParseException ex) {
//解析失敗沈条,則在異常中輸出Json原始字符串
throw new HttpMessageNotReadableException(String.format("JSON parse error: %s%n%s", ex.getMessage(), jsonBody), ex);
}
}
private Charset getCharset(HttpHeaders headers) {
if (headers == null || headers.getContentType() == null || headers.getContentType().getCharset() == null) {
return DEFAULT_CHARSET;
}
return headers.getContentType().getCharset();
}
}
- Spring 5
在Spring 5中實現(xiàn)起來更加簡單
public class HttpMessageConverter extends GsonHttpMessageConverter {
@Override
protected Object readInternal(Type resolvedType, Reader reader) throws Exception {
String jsonBody = CharStreams.toString(reader);
try {
return this.getGson().fromJson(jsonBody, resolvedType);
} catch (JsonParseException ex) {
//解析失敗需忿,則在異常中輸出Json原始字符串
throw new JsonParseException(String.format("JSON parse error: %s%n%s", ex.getMessage(), jsonBody), ex);
}
}
}
配置自定義MessageConverter
spring-mvc.xml
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.tenmao.HttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
結(jié)果
假設(shè)參數(shù)對象如下:
@Data
public class Person {
private String name;
private Integer age;
private Boolean gender;
private List<String> hobbies;
}
如果收到錯誤格式的Json消息,則會拋出異常(hobbies應(yīng)該是一個數(shù)組蜡歹,參數(shù)中是字符串basketball)
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 5 column 14 path $.hobbies
{
"name": "tenmao",
"gender": true,
"age": 28,
"hobbies": "basketball"
}; nested exception is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 5 column 14 path $.hobbies