SpringBoot項(xiàng)目如何把接口參數(shù)中的空白值替換為null值(推薦)
問題發(fā)生
我們公司代碼生成的時(shí)候,查詢列表統(tǒng)一都是使用了setEntity() ,查詢寫法如下:
public List<BasReservoirArea> selectList(BasReservoirArea basReservoirArea) {
QueryWrapper<BasReservoirArea> where = new QueryWrapper<>();
where.setEntity(basReservoirArea);
return baseMapper.selectList(where);
}
查詢的方法是Get方法:
前端是通過url加參數(shù)傳過來的,如果有一個(gè)參數(shù)值為空的時(shí)候,由于setEntity() 并不過濾空白,執(zhí)行sql的時(shí)候 會把""作為參數(shù)去當(dāng)做查詢條件,查詢就出現(xiàn)了問題:


于是我就想把空白轉(zhuǎn)換為null來解決這個(gè)問題了。
初始解決
一開始自然而然想到在setEntity之前先判斷, 如果BasReservoirArea這個(gè)實(shí)例有字段的值是空白就設(shè)置為null
//1.對象轉(zhuǎn)map Map<Object, Object> map = MapUtil.beanToMap(test); //2.移除空值 MapUtil.removeNullValue(map); //3.map轉(zhuǎn)回對象 Test entity = JSON.parseObject(JSON.toJSONString(map), Test.class);
用到的工具類如下
/**
* 將對象屬性轉(zhuǎn)化為map結(jié)合
*/
public static <T> Map<Object, Object> beanToMap(T bean) {
Map<Object, Object> map = new HashMap<>();
if (bean != null) {
BeanMap beanMap = BeanMap.create(bean);
for (Object key : beanMap.keySet()) {
map.put(key, beanMap.get(key));
}
}
return map;
}
/**
* 移除map中的value空值
*
* @param map
* @return
*/
public static void removeNullValue(Map map) {
Set set = map.keySet();
for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
Object obj = (Object) iterator.next();
Object value = (Object) map.get(obj);
remove(value, iterator);
}
}
問題解決了。
優(yōu)化
由于感覺上面的解決方案不夠?qū)I(yè),不夠優(yōu)雅,所以先尋找更好的解決辦法,在后端接收參數(shù)值的時(shí)候,如果接收的是空白,直接設(shè)置為null, 這樣就不需要再次轉(zhuǎn)換了。
解決問題首先要考慮兩種情況,一種是前端通過Get請求,路徑上帶參數(shù);另一種是Post請求,帶著Request報(bào)文。
Post請求報(bào)文體
由于筆者熟悉Post中報(bào)文體的轉(zhuǎn)換,知道是MappingJackson2HttpMessageConverter結(jié)合Jackson實(shí)現(xiàn)報(bào)文體轉(zhuǎn)換為實(shí)例的,而且也研究過Jackson, 所以解決辦法如下
創(chuàng)建一個(gè)針對于String.class的Jackson的反序列類:
public class StringDescrializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String value = jsonParser.getValueAsString();
if (value == null || "".equals(value.trim())) {
return null;
}
return value;
}
}
創(chuàng)建一個(gè)MappingJackson2HttpMessageConverter Bean:
@Bean
@Primary
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
//設(shè)置解析JSON工具類
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getSerializerProvider().setNullValueSerializer(
new JsonSerializer<Object>() {
@Override
public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
}
);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(String.class, new StringDescrializer());
//注冊自定義的StringDescrializer
//registerModules函數(shù)可以注冊多個(gè)Module
objectMapper.registerModule(simpleModule);
//忽略未知屬性 防止解析報(bào)錯(cuò)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonConverter.setObjectMapper(objectMapper);
List<MediaType> list = new ArrayList<>();
list.add(MediaType.APPLICATION_JSON_UTF8);
jsonConverter.setSupportedMediaTypes(list);
return jsonConverter;
}
對于Post報(bào)文體來說,測試成功了。
Get路徑帶參數(shù)
上面的解決方法不適用于Get方法路徑帶參數(shù)的情況,所以需要另外想辦法了。
由于我使用過@InitBinder注解,知道可以注入自定義的PropertyEditor, 在Editor里面可以自定義格式或者返回值,于是,自定義一個(gè)StringEditor來處理空白的問題:、
public class StringEditor extends PropertyEditorSupport {
//setAsText完成字符串到具體對象類型的轉(zhuǎn)換,
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (text == null || "".equals(text.trim())) {
text = null;
}
setValue(text);
}
//getAsText完成具體對象類型到字符串的轉(zhuǎn)換。
@Override
public String getAsText() {
if (getValue() != null) {
return getValue().toString();
}
return null;
}
}
想要全局controller共享這個(gè)Databinder:
@ControllerAdvice
public class GlobalControllerAdiviceController {
//WebDataBinder是用來綁定請求參數(shù)到指定的屬性編輯器,可以繼承WebBindingInitializer
//來實(shí)現(xiàn)一個(gè)全部controller共享的dataBiner
@InitBinder
public void dataBind(WebDataBinder binder) {
///給指定類型注冊類型轉(zhuǎn)換器操作
binder.registerCustomEditor(String.class, new StringEditor());
}
}
對于Get路徑帶參數(shù)來說,測試也成功了
思考
解決完問題后,還是覺得不夠優(yōu)雅,覺得spring 應(yīng)該會考慮到這種情況,終于在spring 的文檔中查閱到StringTrimmerEditor(https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-beans) 可以實(shí)現(xiàn)「Get」方法時(shí)參數(shù)去除空格:

只不過這個(gè)editor缺省沒有注冊,需要手工注冊。
@ControllerAdvice
public class GlobalControllerAdiviceController {
//WebDataBinder是用來綁定請求參數(shù)到指定的屬性編輯器,可以繼承WebBindingInitializer
//來實(shí)現(xiàn)一個(gè)全部controller共享的dataBiner Java代碼
@InitBinder
public void dataBind(WebDataBinder binder) {
///注冊
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}
注意,StringTrimmerEditor構(gòu)造方法中有一個(gè)參數(shù),如果傳入true,則會將空白轉(zhuǎn)換為null. 這樣前面寫的StringEditor就不用了,spring 已經(jīng)幫我們寫好了。
對于「Post」報(bào)文體來說,實(shí)際上我只需要改變的是「Jackson ObjectMapper」,不需要自定義整個(gè)MappingJackson2HttpMessageConverter ,只需要自定義Jackson ObjectMapper.百度了一下,果然有同學(xué)已經(jīng)有了解決方案:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder
.deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
throws IOException {
// 重點(diǎn)在這兒:如果為空白則返回null
String value = jsonParser.getValueAsString();
if (value == null || "".equals(value.trim())) {
return null;
}
return value;
}
});
}
};
}
把上面的自定義StringDescrializer和MappingJackson2HttpMessageConverter去掉, 只保留上面的就行。
后記
好多問題,其實(shí)spring 都已經(jīng)提供了解決方案,但是spring體系目前太龐大了,所以好多API和功能都不為人知。所以碰上問題就記錄下來是個(gè)很好的習(xí)慣
到此這篇關(guān)于SpringBoot項(xiàng)目如何優(yōu)雅的把接口參數(shù)中的空白值替換為null值的文章就介紹到這了,更多相關(guān)SpringBoot空白值替換為null值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例
- Springboot?接口需要接收參數(shù)類型是數(shù)組問題
- SpringBoot接口接收json參數(shù)解析
- 在SpringBoot中使用@Value注解來設(shè)置默認(rèn)值的方法
- SpringBoot的@Value注解如何設(shè)置默認(rèn)值
- Springboot @Value注入boolean設(shè)置默認(rèn)值方式
- springboot配置Jackson返回統(tǒng)一默認(rèn)值的實(shí)現(xiàn)示例
- SpringBoot接口參數(shù)的默認(rèn)值與必要性最佳實(shí)踐記錄
相關(guān)文章
帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之棧
這篇文章主要為大家介紹了Java數(shù)據(jù)結(jié)構(gòu)和算法之棧 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01
利用JAVA反射,讀取數(shù)據(jù)庫表名,自動生成對應(yīng)實(shí)體類的操作
這篇文章主要介紹了利用JAVA反射,讀取數(shù)據(jù)庫表名,自動生成對應(yīng)實(shí)體類的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Spring?Boot實(shí)現(xiàn)web.xml功能示例詳解
這篇文章主要介紹了Spring?Boot實(shí)現(xiàn)web.xml功能,通過本文介紹我們了解到,在Spring Boot應(yīng)用中,我們可以通過注解和編程兩種方式實(shí)現(xiàn)web.xml的功能,包括如何創(chuàng)建及注冊Servlet、Filter以及Listener等,需要的朋友可以參考下2023-09-09
關(guān)于springboot中nacos動態(tài)路由的配置
這篇文章主要介紹了springboot中nacos動態(tài)路由的配置方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
使用SpringBoot和JPA實(shí)現(xiàn)批量處理新增、修改
最近項(xiàng)目需要在JPA中使用ID進(jìn)行批量更新,所以下面這篇文章主要給大家介紹了關(guān)于使用SpringBoot和JPA實(shí)現(xiàn)批量處理新增、修改的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06

