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

1. 现象

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

下面我用demo模拟了一下:

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

public class Clazz {

    private String name;

    private String studentsJson;

    private List students;

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

    public void setStudents(List 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 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

你可能感兴趣的:(向对象中的List添加元素后,返回前端数据丢失)