向对象中的List添加元素后,返回前端数据丢失

在Java开发中,遇到一个问题:向对象的List属性添加元素后,接口返回的数据丢失。原因是Spring MVC在处理返回值时,通过getter方法获取list,导致手动添加的元素被覆盖。建议避免在get/set方法中编写逻辑,遵循阿里巴巴Java开发手册,以减少问题和隐患。
摘要由CSDN通过智能技术生成

1. 现象

在开发中遇到了一个bug,我在一个对象的 list 属性中add了一个新值,但是接口返回时 list 并没有被改变。

下面我用demo模拟了一下:

定义返回的对象clazz班级,studentsJson 对应数据库中存储的 Json Array 字符串,students是将字符串处理后返回的列表:

public class Clazz {

    private String name;

    private String studentsJson;

    private List<Student> students;

    public List<Student> getStudents() {
        if (!StringUtils.isEmpty(studentsJson)) {
            students = JSON.parseArray(studentsJson, Student.class);
            return students;
        }
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStudentsJson() {
        return studentsJson;
    }

    public void setStudentsJson(String studentsJson) {
        this.studentsJson = studentsJson;
    }

    @Override
    public String toString() {
        return "Clazz{" +
                "name='" + name + '\'' +
                ", studentsJson='" + studentsJson + '\'' +
                ", students=" + students +
                '}';
    }
}

Student对象:

public class Student {

    private String name;

    // 省略 get/set 方法 ...

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

接口模拟:

@RestController
public class TestController {

    Logger logger = LoggerFactory.getLogger(TestController.class);

    @GetMapping("/test")
    public Clazz showClazz() {
        // 模拟数据库中查出的对象
        Clazz clazz = new Clazz();
        clazz.setName("一班");
        clazz.setStudentsJson("[{\"name\":\"zhangsan\"},{\"name\":\"lisi\"}]");
        logger.info("初始clazz对象: {}", clazz);

        List<Student> students = clazz.getStudents();
        logger.info("调用getStudents方法获取的students: {}", students);

        students.add(new Student("wangwu"));
        logger.info("向students中添加一个新的学生后: {}", students);

        return clazz;
    }
}

请求接口后的输出:

2021-05-20 11:32:28.865 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 初始clazz对象: Clazz{name='一班', studentsJson='[{"name":"zhangsan"},{"name":"lisi"}]', students=null}
2021-05-20 11:32:28.916 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 调用getStudents方法获取的students: [Student{name='zhangsan'}, Student{name='lisi'}]
2021-05-20 11:32:28.917 [INFO ] [http-nio-8080-exec-1] [c.jiangxb.test.TestController ] 向students中添加一个新的学生后: [Student{name='zhangsan'}, Student{name='lisi'}, Student{name='wangwu'}]

这里students中添加一个应该是三个的,但是用postman调用返回后:

{
    "name": "一班",
    "studentsJson": "[{\"name\":\"zhangsan\"},{\"name\":\"lisi\"}]",
    "students": [
        {"name": "zhangsan"},
        {"name": "lisi"}
    ]
}

2. 原因

从controller返回后,spring mvc会对返回值进行处理

ServletInvocableHandlerMethod#invokeAndHandle

this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);

在这一步会调用对象的get方法,所以手动加入进students中的对象被覆盖掉了。

3. 建议

建议不要在 get/set 方法中写任何的逻辑,这样虽然可以简化一些代码,但是出现问题时不容易排查,会有很大的隐患,也不利于其他同事修改。

这点在阿里Java开发手册(泰山版)中也有提到:

getter.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值