从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)
- JPA / Hibernate:传递给persist的分离实体
- 如何强制Hibernate返回date为java.util.Date而不是Timestamp?
- HQL留下了非关联实体的连接
- 什么是在Web应用程序中的jpa persistence.xml中引用jar文件的正确path?
- 如何从我的控制器中加载Hibernate / JPA中的延迟获取项目
- java.lang.ClassNotFoundException:org.hibernate.HibernateException
- @ManyToOne属性不允许使用@Column(s)
- find对集合org.hibernate.HibernateException的共享引用
- Java是否有使用声明?