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="[&quot;Id&quot;:118,&quot;Id&quot;: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对象中转换空值的字段的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery - 加载具有空值的 JSON 字段

如何在Java中解析具有空值的JSON对象?

将表单序列化为没有空值的 json

在 Java 中检查空值的最佳方法是啥?

access中查询出来值的为空,如何将空值改为0,具体表达式是啥,从啥地方输入表达式,多谢

sql中更新某个字段中部分空值的语句怎样写?