Java对象中转换空值的字段
Posted LonZyuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java对象中转换空值的字段相关的知识,希望对你有一定的参考价值。
在后端返回数据给前端时,公司的框架会把值为null的数据去掉,方便前端取值。
如:Person对象为:name:"浩二", age:24, weight:null, height:114,那返回给前端的就为name:"浩二", age:24, height:114。
如果这个时候有个需求:
Integer类型的字段为null给-1
Long类型的字段为null给-1L
String类型的字段为null给""(空字符串)
对象类型的字段为null给new对象,
不能直接动框架,因此需要手动转化。
代码写死转换
这种是最简单的方式,顾名思义,写死代码的方式一个一个字段来转换
示例
转换对象 ConvertNullFiledInfo:
@Data public class ConvertNullFiledInfo private Integer intNum; private Long longNum; private String str; private ConvertNullFiledInfo info;
转换代码:
@Service public class ConvertNullFiledService /** * 写死代码的方式一个一个字段来转换 * @param info * @return */ public ConvertNullFiledInfo convertFunction01(ConvertNullFiledInfo info) info.setIntNum(info.getIntNum() == null ? -1 : info.getIntNum()); info.setLongNum(info.getLongNum() == null ? -1L : info.getLongNum()); info.setStr(info.getStr() == null ? "" : info.getStr()); info.setInfo(info.getInfo() == null ? new ConvertNullFiledInfo() : info.getInfo()); return info;
测试代码:
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest @RunWith(SpringRunner.class) public class ConvertNullFiledServiceTest @Autowired private ConvertNullFiledService convertNullFiledService; @Test public void convertFunction01() // str和info字段给null ConvertNullFiledInfo info = createConvertNullFiledInfo(1, 1L, null, null); ConvertNullFiledInfo result = convertNullFiledService.convertFunction01(info); System.out.println(result); /** * 自定义字段创建ConvertNullFiledInfo * @param intNum * @param longNum * @param str * @param info * @return */ private ConvertNullFiledInfo createConvertNullFiledInfo(Integer intNum, Long longNum, String str, ConvertNullFiledInfo info) ConvertNullFiledInfo result = new ConvertNullFiledInfo(); result.setIntNum(intNum); result.setLongNum(longNum); result.setStr(str); result.setInfo(info); return result;
运行结果:
可以看到是正常转换了的
问题点
这样写虽然简单方便,但是如果有非常多的对象需要转换,就会有许多重复代码;
而且如果字段有修改(类型、名称、被删除、新增),就需要在去转换方法中修改,因此可以用更好的方式。
遍历Filed转换
所有对象都有Class<T>类,而Class有getDeclaredFields()方法,能获取到所有字段(filed),
因此可以使用这种方式来转换。
示例
转换代码:
/** * 遍历field的方式一个一个字段来转换 * @param info * @return */ public ConvertNullFiledInfo convertByField(ConvertNullFiledInfo info) try Field[] fields = info.getClass().getDeclaredFields(); for (Field field : fields) // 设置可访问私有变量 field.setAccessible(true); // 获取当前字段值 Object value = field.get(info); // value不为空就跳过 if (value != null) continue; // 获取当前字段类型 Class<?> type = field.getType(); if (type == Integer.class) // Integer类型就设置为-1 field.set(info, -1); else if (type == Long.class) // Long类型就设置为-1L field.set(info, -1L); else if (type == String.class) // String类型就设置为“” field.set(info, ""); else if (type == ConvertNullFiledInfo.class) // ConvertNullFiledInfo类型就设置为新对象 field.set(info, new ConvertNullFiledInfo()); catch (Exception e) e.printStackTrace(); return info;
测试代码:
@Test public void convertByField() // str和info字段给null ConvertNullFiledInfo info = createConvertNullFiledInfo(1, 1L, null, null); ConvertNullFiledInfo result = convertNullFiledService.convertByField(info); System.out.println(result);
运行结果:
可以看到也是成功转换了
问题点
这种写法仍然存在问题,可以看到方法的传参和返回值都是固定类型为ConvertNullFiledInfo,
并且在遍历field的时候,也有if判断是写定的ConvertNullFiledInfo,
因此也在一定程度上写死了代码
优化
为了避免写死的情况,可以使用泛型来写
转换代码:
@Service public class ConvertNullFiledService<T> /** * 使用泛型,遍历field的方式一个一个字段来转换 * @param object * @return */ public T convertByFieldGeneric(T object) try Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) // 设置可访问私有变量 field.setAccessible(true); // 获取当前字段值 Object value = field.get(object); // value不为空就跳过 if (value != null) continue; // 获取当前字段类型 Class<?> type = field.getType(); if (type == Integer.class) // Integer类型就设置为-1 field.set(object, -1); else if (type == Long.class) // Long类型就设置为-1L field.set(object, -1L); else if (type == String.class) // String类型就设置为“” field.set(object, ""); else if (type == object.getClass()) // T类型就设置为新对象 Object newObj = object.getClass().newInstance(); field.set(object, newObj); catch (Exception e) e.printStackTrace(); return object;
测试代码:
@Test public void convertByFieldGeneric() // 全部字段给null ConvertNullFiledInfo info = createConvertNullFiledInfo(null, null, null, null); ConvertNullFiledInfo result = (ConvertNullFiledInfo) convertNullFiledService.convertByFieldGeneric(info); System.out.println(result);
运行结果:
成功转换
将表单序列化为没有空值的 json
【中文标题】将表单序列化为没有空值的 json【英文标题】:Serialize form as json without empty values 【发布时间】:2016-12-08 08:16:36 【问题描述】:我有一个包含 3 个字段的 HTML 表单。我想将它们序列化为 json 对象(到目前为止,使用我的 getFormData($form)
方法有效。但现在我想在我的表单中排除所有没有 inputtext/value 的字段。
这会序列化我的表单并将其保存为 json 对象:
function getFormData($form)
var unindexed_array = $form.serializeArray();
var indexed_array = ;
$.map(unindexed_array, function(n, i)
indexed_array[n['name']] = n['value'];
);
return indexed_array;
这就是我尝试过滤没有值的字段的方式:
var form = $("#bulk-edit-fut-account-form :input[value!='']");
console.log(JSON.stringify(form));
var formData = getFormData(form);
我的 HTML 表单:
<form id="bulk-edit-fut-account-form" class="form-horizontal" novalidate="novalidate"><div class="form-group"><label class="col-sm-3 control-label">Id<span class="asterisk">*</span></label><div class="col-sm-9"><input id="bulkAccountIds" type="text" required="" readonly="" value="118 119 " data-id="["Id":118,"Id":119]" class="form-control valid" aria-required="true"></div></div><div class="form-group"><label class="col-sm-3 control-label">Max. Requests / minute</label><div class="col-sm-9"><input type="number" name="RequestsPerMinute" placeholder="Type maximum amount of reqs/min..." class="form-control valid"></div></div><div class="form-group"><label class="col-sm-3 control-label">Request Threshold</label><div class="col-sm-9"><input type="number" name="Threshold" placeholder="Type fastest timeframe for 1 request in seconds..." class="form-control valid"></div></div><div class="form-group"><label class="col-sm-3 control-label">Comment</label><div class="col-sm-9"><textarea name="Comment" rows="5" class="form-control"></textarea></div></div></form>
问题:
使用上面的代码,它仍然会序列化空字段(但我想避免这种情况)。这是结果 RequestsPerMinute: '121', Threshold: '', Comment: ''
。如何避免序列化没有值的字段?
【问题讨论】:
您可以尝试从您的var form = $("#bulk-edit-fut-account-form :input[value!='']");
中删除:
吗?
@TylerRoper 实际上这可能是正确的。现在它忽略了我的“评论”字段,它是一个文本区域,它仍然不过滤空值字段。看来我的想法没有达到预期效果。
查看我的答案,如果可行,请告诉我。
为什么是 JSON,为什么你不将它序列化为 x-www-form-encoded 并使用form.serialize()
@adeneo 因为我使用 websockets 并将它与其他信息一起传递。我尽可能简化了这里的问题。由于其他原因,我也需要它
【参考方案1】:
这是修改函数的一种方法
function getFormData($form, no_empty)
var unindexed_array = $form.serializeArray();
var indexed_array = ;
$.map(unindexed_array, function(n, i)
indexed_array[n['name']] = n['value'];
);
if (no_empty)
$.each(indexed_array, function(key, value)
if ( $.trim(value) === "" ) delete indexed_array[key];
);
return indexed_array;
当您不想正常调用它并包含所有内容时,您只需这样做
var json = getFormData( form );
当您不想要空输入时,您只需这样做
var json = getFormData( form, true );
它们被过滤掉了
【讨论】:
感谢您的回答,但我也在其他要序列化空字段的地方使用该方法。如果没有更好的解决方案,我会尝试你的答案。【参考方案2】:试试这个:
var form = $(); //Initialize empty jQuery object
//Iterate through all inputs, textareas
$('#bulk-edit-fut-account-form input, #bulk-edit-fut-account-form textarea').each(function()
//Add to jQuery object if not empty
if ($(this).val().length)
form = form.add($(this));
)
console.log(JSON.stringify(form));
var formData = getFormData(form);
【讨论】:
我认为问题在于我没有正确描述问题。这与“属性”值无关,因为它是一个输入文本框。我想检查这个文本框是否为空。如果为空 => 过滤 空文本框和没有值的文本框有什么区别?我上面的例子说“如果文本框没有值,或者文本框有一个空白值,则排除它”。 我已经尝试过您的解决方案。它过滤所有字段,无论它们是否有内容。 我的意思是你的另一个选择是为每个输入和文本区域做一个$.each
,如果有一个值,把它添加到form
。
@kentor 我最近的最后一次更新 - 将数组更改为 jQuery 对象以匹配您的原始脚本。【参考方案3】:
您可以 filter
并删除 .val()
为空的元素:
$.map(unindexed_array, function(n, i)
indexed_array[n['name']] = n['value'];
).filter(function()
// will be removed from array if empty
return $(this).val();
);
【讨论】:
感谢您的回答,但我也在其他要序列化空字段的地方使用该方法。如果没有更好的解决方案,我会尝试你的答案。以上是关于Java对象中转换空值的字段的主要内容,如果未能解决你的问题,请参考以下文章