从Spring MVC发送JSON时dynamic忽略Java对象的字段

我有像这样的模型类,hibernate

@Entity @Table(name = "user", catalog = "userdb") @JsonIgnoreProperties(ignoreUnknown = true) public class User implements java.io.Serializable { private Integer userId; private String userName; private String emailId; private String encryptedPwd; private String createdBy; private String updatedBy; @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "UserId", unique = true, nullable = false) public Integer getUserId() { return this.userId; } public void setUserId(Integer userId) { this.userId = userId; } @Column(name = "UserName", length = 100) public String getUserName() { return this.userName; } public void setUserName(String userName) { this.userName = userName; } @Column(name = "EmailId", nullable = false, length = 45) public String getEmailId() { return this.emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } @Column(name = "EncryptedPwd", length = 100) public String getEncryptedPwd() { return this.encryptedPwd; } public void setEncryptedPwd(String encryptedPwd) { this.encryptedPwd = encryptedPwd; } public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } @Column(name = "UpdatedBy", length = 100) public String getUpdatedBy() { return this.updatedBy; } public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; } } 

在Spring MVC控制器中,使用DAO,我可以得到对象。 并作为JSON对象返回。

 @Controller public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/getUser/{userId}", method = RequestMethod.GET) @ResponseBody public User getUser(@PathVariable Integer userId) throws Exception { User user = userService.get(userId); user.setCreatedBy(null); user.setUpdatedBy(null); return user; } } 

View部分是使用AngularJS完成的,所以它会得到像这样的JSON

 { "userId" :2, "userName" : "john", "emailId" : "john@gmail.com", "encryptedPwd" : "Co7Fwd1fXYk=", "createdBy" : null, "updatedBy" : null } 

如果我不想设置encryption的密码,我会将该字段也设置为空。

但我不想这样,我不想把所有的字段发送到客户端。 如果我不想要密码,updatedby,由字段发送创build,我的结果JSON应该是

 { "userId" :2, "userName" : "john", "emailId" : "john@gmail.com" } 

我不想从其他数据库表发送到客户端的字段列表。 所以它会根据login的用户而改变。我该怎么做?

我希望你有我的问题。

 Add the annotation @JsonIgnoreProperties("fieldname") to your POJO. 

或者也可以在字段名称之前使用@JsonIgnore ,在反序列化json的时候你想忽略它。

例如:

  @JsonIgnore @JsonProperty(value = "user_password") public java.lang.String getUserPassword() { return userPassword; } 

GitHub的例子

我知道我晚了一点,但是几个月前我还碰到过这个。 所有可用的解决scheme对我来说都不是很吸引人,所以我最终创build了一个新库来使这个过程更加清洁。 如果有人想尝试它,可以在这里find: https : //github.com/monitorjbl/spring-json-view 。

基本用法非常简单,你可以在你的控制器方法中使用JsonView对象,如下所示:

 import com.monitorjbl.json.JsonView; import static com.monitorjbl.json.Match.match; @RequestMapping(method = RequestMethod.GET, value = "/myObject") @ResponseBody public void getMyObjects() { //get a list of the objects List<MyObject> list = myObjectService.list(); //exclude expensive field JsonView.with(list).onClass(MyObject.class, match().exclude("contains")); } 

你也可以在Spring之外使用它:

 import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import static com.monitorjbl.json.Match.match; ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(JsonView.class, new JsonViewSerializer()); mapper.registerModule(module); mapper.writeValueAsString(JsonView.with(list) .onClass(MyObject.class, match() .exclude("contains")) .onClass(MySmallObject.class, match() .exclude("id")); 

添加@JsonInclude(JsonInclude.Include.NON_NULL) (强制jackson序列化空值)的类以及@JsonIgnore密码字段。

你当然可以在@JsonIgnore@JsonIgnore上设置@JsonIgnore ,如果你总是想忽略,那么不仅仅是在这个特定的情况下。

UPDATE

如果您不想将注释添加到POJO本身,jackson的Mixin注释是一个很好的select。 检查文档

如果我是你,想这样做,我不会在Controller层使用我的用户实体。相反,我创build并使用UserDto(数据传输对象)与业务(服务)层和控制器进行通信。 您可以使用Apache ConvertUtils将用户实体中的数据复制到UserDto。

我为Spring和Jacksonfind了一个解决scheme

首先在实体中指定filter名称

 @Entity @Table(name = "SECTEUR") @JsonFilter(ModelJsonFilters.SECTEUR_FILTER) public class Secteur implements Serializable { /** Serial UID */ private static final long serialVersionUID = 5697181222899184767L; /** * Unique ID */ @Id @JsonView(View.SecteurWithoutChildrens.class) @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @JsonView(View.SecteurWithoutChildrens.class) @Column(name = "code", nullable = false, length = 35) private String code; /** * Identifiant du secteur parent */ @JsonView(View.SecteurWithoutChildrens.class) @Column(name = "id_parent") private Long idParent; @OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "id_parent") private List<Secteur> secteursEnfants = new ArrayList<>(0); } 

然后你可以看到常量filter名称类与弹簧configuration中使用的默认FilterProvider

 public class ModelJsonFilters { public final static String SECTEUR_FILTER = "SecteurFilter"; public final static String APPLICATION_FILTER = "ApplicationFilter"; public final static String SERVICE_FILTER = "ServiceFilter"; public final static String UTILISATEUR_FILTER = "UtilisateurFilter"; public static SimpleFilterProvider getDefaultFilters() { SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter.serializeAll(); return new SimpleFilterProvider().setDefaultFilter(theFilter); } } 

弹簧configuration:

 @EnableWebMvc @Configuration @ComponentScan(basePackages = "fr.sodebo") public class ApiRootConfiguration extends WebMvcConfigurerAdapter { @Autowired private EntityManagerFactory entityManagerFactory; /** * config qui permet d'éviter les "Lazy loading Error" au moment de la * conversion json par jackson pour les retours des services REST<br> * on permet à jackson d'acceder à sessionFactory pour charger ce dont il a * besoin */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper mapper = new ObjectMapper(); // config d'hibernate pour la conversion json mapper.registerModule(getConfiguredHibernateModule());// // inscrit les filtres json subscribeFiltersInMapper(mapper); // config du comportement de json views mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); converter.setObjectMapper(mapper); converters.add(converter); } /** * config d'hibernate pour la conversion json * * @return Hibernate5Module */ private Hibernate5Module getConfiguredHibernateModule() { SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class); Hibernate5Module module = new Hibernate5Module(sessionFactory); module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true); return module; } /** * inscrit les filtres json * * @param mapper */ private void subscribeFiltersInMapper(ObjectMapper mapper) { mapper.setFilterProvider(ModelJsonFilters.getDefaultFilters()); } } 

最后,我可以指定一个特定的filterrestConstoller当我需要….

 @RequestMapping(value = "/{id}/droits/", method = RequestMethod.GET) public MappingJacksonValue getListDroits(@PathVariable long id) { LOGGER.debug("Get all droits of user with id {}", id); List<Droit> droits = utilisateurService.findDroitsDeUtilisateur(id); MappingJacksonValue value; UtilisateurWithSecteurs utilisateurWithSecteurs = droitsUtilisateur.fillLists(droits).get(id); value = new MappingJacksonValue(utilisateurWithSecteurs); FilterProvider filters = ModelJsonFilters.getDefaultFilters().addFilter(ModelJsonFilters.SECTEUR_FILTER, SimpleBeanPropertyFilter.serializeAllExcept("secteursEnfants")).addFilter(ModelJsonFilters.APPLICATION_FILTER, SimpleBeanPropertyFilter.serializeAllExcept("services")); value.setFilters(filters); return value; } 

不会创build一个UserJsonResponse类和填充想要的领域是一个更清洁的解决scheme?

当你想把所有的模型都返回时,直接返回一个JSON似乎是一个很好的解决scheme。 否则它会变得混乱。

在将来,例如,您可能希望有一个与任何Model字段不匹配的JSON字段,然后遇到更大的麻烦。

在您的实体类中添加@JsonInclude(JsonInclude.Include.NON_NULL)注释来解决问题

它会喜欢

 @Entity @JsonInclude(JsonInclude.Include.NON_NULL)