我有两种模式:
@Entity
class ModelA {
...
@OneToMany(mappedBy = "modelA")
@JsonManagedReference
private List<ModelB> modelBs = new ArrayList<ModelB>();
...
}
@Entity
class ModelB {
...
@ManyToOne
@JoinColumn(name = "modela_id")
@JsonBackReference
private ModelA modela;
...
}
ModelA的REST /资源控制器,它有一个列表方法:
@GetMapping("list")
public @ResponseBody ArrayList<ModelA> list() {
ArrayList<ModelA> modelas = new ArrayList();
for (ModelA moa : modelARepository.findAll()) {
modelas.add(moa);
}
return modelas;
}
现在默认情况下,来自该控制器的响应将包含ModelA对象的JSON数组,但这些对象也将包含ModelB。有没有办法选择你想要序列化的关系以及什么时候?
来自Django / Laravel我会用专门的序列化来解决这个问题,例如我会有一个ModelAWithRelatiionsSerializer
我会序列化ModelA +它的所有关系或ModelAWithModelBSerializer
会返回一个序列化的ModelA ModelB等等。
我知道我可以忽略注释而不包含它但是真的不一样,我在Spring包中没有看到关于序列化的内容。这样做的最佳或最佳方式是什么?
答案 0 :(得分:0)
对于其他任何从Laravel(PHP),Django(Python),Rails(Ruby)迁移的人:
我创建了一个包serializers
,其中我为每个模型都有一个序列化程序类。
public class UserSerializer {
// Default user values
public interface User {}
// User values with users posts
public interface UserWithPosts extends User {}
}
现在,在您的模型中,您所做的是注释它们所属的序列化程序的字段:
@Entity
class User {
@Id
@GeneratedValue
@JsonView(UserSerializer.User.class)
private Long id;
@JsonView(UserSerializer.User.class)
private String username;
@JsonView(UserSerializer.User.class)
private String email;
@OneToMany(mappedBy = "user")
@JsonManagedReference // This prevents infinite loop
@JsonView(UserSerializer.UserWithPosts.class)
private List<Post> posts;
// .. getters and setters bellow
}
在您的控制器中,您可以使用@JsonView(..)
为您的方法添加关于要使用的序列化程序的注释。
@RestController
@RequestMapping("users")
public class UsersController {
private UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
/**
* In list method we only want users default values to keep the payload smaller.
*/
@GetMapping("list")
@JsonView(UserSerializer.User.class)
public @ResponseBody ArrayList<User> list() {
ArrayList<User> users = new ArrayList<>();
for (User user : userRepository.findAll()) {
users.add(user);
}
return users;
}
/**
* In this method we are only fetching a single user so payload is smaller so we can add the users posts as well. You could also toggle this with a url filter/parameter.
*/
@GetMapping("show")
@JsonView(UserSerializer.UserWithPosts.class)
public @ResponseBody ArrayList<User> show(@RequestParam(name = "id", required = true) Long id) {
return userRepository.findOne(id):
}
}
配置!这很容易理解,但是当我第一次做到这一点时,没有任何示例/教程告诉/表明您还需要更新配置。如果你没有这样做,那么序列化你的关系会有问题,序列化器仍然可以工作,但你会在你的JSON响应中得到这样的东西:
...
"posts": [
{},
{},
{},..
]
...
所以它会为每个帖子用户返回一个JSON对象,但没有值来修复这个我创建的config
包添加了WebConfiguration
类:
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().defaultViewInclusion(true).build();
converters.add(new MappingJackson2HttpMessageConverter(mapper));
}
}
您也可以在XML配置中执行此操作。但我个人更喜欢使用基于Java类的配置。如果弹簧文档包含对新手的更好解释,那将是很好的。