当前位置: 首页 > 知识库问答 >
问题:

向Spring JSON视图响应添加动态字段

秦楚
2023-03-14

有一种Spring方法可以用JSON视图从服务响应中过滤出字段,但我缺少一种等效的方法,可以用一些类似这样的动态/语法字段来丰富响应;

class User{
    getFirstName(){...}
    getLastName(){...}
    getCreateDate(){...}
}

class UserViewA{
    getFullName(){
      return getLastName()+", "+getFirstName()
    }
    getCreateDate(){...}
}

class UserViewB{
    getFullName(){
      return getFirstName()+" "+getLastName()
    }
    getCreateDate(){...}
}

我可以在视图中包装用户,但我不想手动传播所有需要的用户字段。

我的另一个想法是用用户对象扩展视图,并创建某种引用链接器,将值引用从用户对象复制到视图中,但这将使集合变得复杂。

是否有其他方法或框架来实现这一目标?这一概念是否根本没有得到解决?

更新:

举例说明:

  • 我不想包装User对象,因为我不想在不同的UserView对象中维护来自User类的相同getter方法

我正在寻找一种门面解决方案/框架/方法。

共有3个答案

翟泰
2023-03-14

实际上,最好的方法是包装用户对象(如果序列化框架使用getter方法)或将整个对象重写为另一个视图对象(如果序列化框架使用属性)。如果不想手动重写对象,可以使用dozer之类的框架或其他JavaBean映射框架。

如果你的模特是这样的:

public class User {
    private final String firstName;
    private final String lastName;

    // constructor and getter method
}

你的wrap类可以如下所示:

public class UserView {
    private final User user;

    public UserView(User user) {
        this.user = user;
    }

    public String getFullName() {
        return user.getFirstName() + " " + user.getLastName();
    }
}

或者你也可以重写整个对象:

public class UserView {
    private final String fullName;

    public UserView(User user) {
        this.fullName = user.getFirstName() + " " + user.getLastName();
    }

    // getter if needed
}
卫增
2023-03-14

当无法修改域对象的类时,可以使用mix-in使用“virtual”字段来丰富JSON。

例如,您可以创建一个名为UserMixin的类,该类隐藏firstNamelastName字段,并公开一个虚拟的fullName字段:

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonAppend;

import java.util.Date;

@JsonAppend(
    prepend = true,
    props = {
            @JsonAppend.Prop(name = "fullName", value = UserFullName.class)
    })
public abstract class UserMixin
{
    @JsonIgnore
    public abstract String getFirstName();
    @JsonIgnore
    public abstract String getLastName();
    public abstract Date getCreatedDate();
}

然后,您将实现一个名为UserFullName的类,该类扩展了VirtualBeanProperty tyWriter以提供虚拟字段的值:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.ser.VirtualBeanPropertyWriter;
import com.fasterxml.jackson.databind.util.Annotations;

public class UserFullName extends VirtualBeanPropertyWriter
{
    public UserFullName() {}

    public UserFullName(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType)
    {
        super(propDef, contextAnnotations, declaredType);
    }

    @Override
    protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception
    {
        return ((User) bean).getFirstName() + " " + ((User) bean).getLastName();
    }

    @Override
    public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type)
    {
        return new UserFullName(propDef, null, type);
    }
}

最后,您需要在ObjectMapper中注册mix,如以下JUnit测试所示:

@Test
public void testUserFullName() throws IOException
{
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.addMixIn(User.class, UserMixin.class);
    System.out.println(objectMapper.writeValueAsString(new User("Frodo", "Baggins")));
}

然后输出为:

{"fullName":"Frodo Baggins","createdDate":1485036953535}
朱建弼
2023-03-14

使用jackson@JsonUnwrapped怎么样?

http://fasterxml.github.io/jackson-annotations/javadoc/2.0.0/com/fasterxml/jackson/annotation/JsonUnwrapped.html

public class UserViewA {

    @JsonUnwrapped
    private User user;

    public User getUser() ...

    public String getFullName() {
        return user.getFirstName() + " " + user.getLastName()
    }
}

JsonUnwrapped只会将用户的所有属性拉到根级别,其中仍然有自己的UserViewA属性。

 类似资料:
  • 我希望将动态字段存储到文档中,但每个文档可以有不同的字段。 例如: 如果我运行上述程序,mongodb文档如下所示。 但我想要的是字段名称应该是“field1”而不是这样的“df”。 这只是一个示例代码,所以我知道df值是什么,但实际上我不知道df值是什么。那么在存储时动态命名字段的方法是什么? 在Mongoengine中有一个类似的使用key作为值的问题,但是解决方案建议使用DictField(

  • 目前我有下面的代码。它将imageview添加到现有的背景中。然而,在图像创建后,当我试图拖动它时,程序崩溃了...有人知道为什么它不起作用吗? 日志如下: ------崩溃开始 E/AndroidRuntime:致命异常:main process:com.example.dan.ball,pid:2795 java.lang.nullpointerException:在Android.view.

  • 问题内容: 我有一个空的JTable,绝对没有。我需要以某种方式动态生成其表列。我尝试使用的代码的简化版本: 但是我得到了 线程“ AWT-EventQueue-0”中的异常java.lang.ArrayIndexOutOfBoundsException:0> = 0 我究竟做错了什么? 如果有帮助,这是完整的堆栈跟踪: 问题答案: 我认为您需要将列添加到表的数据模型及其列模型中。当数据模型更改时

  • 本文向大家介绍CI框架给视图添加动态数据,包括了CI框架给视图添加动态数据的使用技巧和注意事项,需要的朋友参考一下 数据通过控制器以一个数组或是对象的形式传入视图 , 这个数组或对象作为视图载入函数的第二个参数如果你使用一个对象,那么类变量将转换为数组元素。好了,让我们用你的控制器试试。打开控制器并添加以下代码 现在,打开你的视图文件,将其中的文本替换成与数组对应的变量:注意才前台页面取值时,直接

  • 我有一个flask web应用程序,它使用render_template如下所示。我需要在响应中添加一个Content-Security-Policy作为额外的http响应头。我试着按照方法走,但都失败了,给了我500。 1. 在终端上,当我以localhost身份访问web应用程序时,会看到以下内容:3001 127.0.0.1--[06/APR/2015 01:45:01]“GET/HTTP/

  • 若要添加一个新的视图,点击工具栏的 按钮,并点击画布的任意位置。你可以从浏览器的模型选项卡添加一个现有的视图,简单地从模型选项卡拖放视图到画布。 【注意】如果你右击视图连接器,你可以选择添加或删除顶点,以及更改它的颜色,或者前往源视图和目标表。 在画布中视图对象的弹出式菜单选项包括: 选项 描述 设计视图 在视图设计器中编辑视图结构。设计器内的选项卡和选项是根据你所选择的图表数据库类型而有所不同。