我有这样的模型类,用于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;
}
}
查看部分是使用AngularJS完成的,所以它会像这样获得JSON
{
"userId" :2,
"userName" : "john",
"emailId" : "john@gmail.com",
"encryptedPwd" : "Co7Fwd1fXYk=",
"createdBy" : null,
"updatedBy" : null
}
如果我不想设置加密密码,我会将该字段设置为空。
但我不想这样,我不想将所有字段发送到客户端。如果我不想要密码,更新,由字段创建发送,我的结果JSON应该像
{
"userId" :2,
"userName" : "john",
"emailId" : "john@gmail.com"
}
我不希望从其他数据库表发送到客户端的字段列表。所以它会根据登录的用户而改变。我该怎么做?
我希望你能得到我的问题。
答案 0 :(得分:106)
将@JsonIgnoreProperties("fieldname")
注释添加到您的POJO。
或者,您可以在反序列化JSON时在要忽略的字段名称前使用@JsonIgnore
。例如:
@JsonIgnore
@JsonProperty(value = "user_password")
public java.lang.String getUserPassword() {
return userPassword;
}
答案 1 :(得分:26)
我知道我参加派对有点晚了,但几个月前我也遇到了这个问题。所有可用的解决方案对我来说都不是很吸引人(mixins?唉!),所以我最终创建了一个新的库来使这个过程更加清晰。如果有人想尝试一下,可以在这里找到它: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"));
答案 2 :(得分:9)
将@JsonInclude(JsonInclude.Include.NON_NULL)
(迫使Jackson序列化空值)添加到班级以及@JsonIgnore
添加到密码字段。
你当然可以在createdBy和updatedBy上设置@JsonIgnore
,如果你总是想忽略它而不仅仅是在这个特定的情况下。
<强>更新强>
如果您不想将注释添加到POJO本身,一个很好的选择是Jackson的Mixin Annotations。查看documentation
答案 3 :(得分:4)
如果我是你并希望这样做,我就不会在Controller层中使用我的用户实体。相反,我创建并使用UserDto(数据传输对象)与业务(服务)层和Controller进行通信。 您可以使用Apache ConvertUtils将数据从User实体复制到UserDto。
答案 4 :(得分:4)
是的,您可以指定将哪些字段序列化为JSON响应以及将哪些字段忽略。 这是实现动态忽略属性所需的操作。
1)首先,您需要将com.fasterxml.jackson.annotation.JsonFilter中的@JsonFilter添加为您的实体类。
import com.fasterxml.jackson.annotation.JsonFilter;
@JsonFilter("SomeBeanFilter")
public class SomeBean {
private String field1;
private String field2;
private String field3;
// getters/setters
}
2)然后,在控制器中,必须添加创建的MappingJacksonValue对象并在其上设置过滤器,最后必须返回此对象。
import java.util.Arrays;
import java.util.List;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
@RestController
public class FilteringController {
// Here i want to ignore all properties except field1,field2.
@GetMapping("/ignoreProperties")
public MappingJacksonValue retrieveSomeBean() {
SomeBean someBean = new SomeBean("value1", "value2", "value3");
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("field1", "field2");
FilterProvider filters = new SimpleFilterProvider().addFilter("SomeBeanFilter", filter);
MappingJacksonValue mapping = new MappingJacksonValue(someBean);
mapping.setFilters(filters);
return mapping;
}
}
这是您将得到的答复:
{
field1:"value1",
field2:"value2"
}
代替此:
{
field1:"value1",
field2:"value2",
field3:"value3"
}
在这里您可以看到它忽略了属性field1和field2以外的其他属性(在这种情况下为field3)。
希望这会有所帮助。
答案 5 :(得分:4)
我们可以通过在声明属性时设置对JsonProperty.Access.WRITE_ONLY
的访问权限来实现。
@JsonProperty( value = "password", access = JsonProperty.Access.WRITE_ONLY)
@SerializedName("password")
private String password;
答案 6 :(得分:3)
我可以动态地进行吗?
创建视图类:
<%String p = (String)request.getParameter("multiPage");
%>
<c:choose>
<c:when test="${p==null}">
<jsp:include page="HOME.jsp" flush="true"/>
</c:when>
<c:when test="${p=='HOME'}">
<jsp:include page="HOME.jsp" flush="true"/>
</c:when>
<c:when test="${p=='SERVICES'}">
<jsp:include page="SERVICES.jsp" flush="true"/>
</c:when>
<c:when test="${p=='EXAMPLE'}">
<jsp:include page="EXAMPLE.jsp" flush="true"/>
</c:when>
<c:when test="${p=='PRODUCTS'}">
<jsp:include page="PRODUCTS.jsp" flush="true"/>
</c:when>
<c:when test="${p=='CONTACT'}">
<jsp:include page="CONTACT.jsp" flush="true"/>
</c:when>
</c:choose>
</div>
注释你的模型
public class View {
static class Public { }
static class ExtendedPublic extends Public { }
static class Internal extends ExtendedPublic { }
}
在控制器中指定视图类
@Document
public class User {
@Id
@JsonView(View.Public.class)
private String id;
@JsonView(View.Internal.class)
private String email;
@JsonView(View.Public.class)
private String name;
@JsonView(View.Public.class)
private Instant createdAt = Instant.now();
// getters/setters
}
数据示例:
@RequestMapping("/user/{email}")
public class UserController {
private final UserRepository userRepository;
@Autowired
UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@RequestMapping(method = RequestMethod.GET)
@JsonView(View.Internal.class)
public @ResponseBody Optional<User> get(@PathVariable String email) {
return userRepository.findByEmail(email);
}
}
答案 7 :(得分:1)
我为Spring和杰克逊找到了解决方案
首先在实体中指定过滤器名称
@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);
}
然后您可以看到常量过滤器名称类与Spring配置中使用的默认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);
}
}
春季配置:
@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());
}
}
我需要在restConstoller中指定一个特定的过滤器....
@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;
}
答案 8 :(得分:1)
我创建了一个JsonUtil,它可以在运行时忽略字段,同时给出响应。
用法示例: 第一个参数应该是任何POJO类(Student),ignoreFields是您要在响应中忽略的逗号分隔字段。
Student st = new Student();
createJsonIgnoreFields(st,"firstname,age");
import java.util.logging.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.map.ser.FilterProvider;
import org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter;
import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider;
public class JsonUtil {
public static String createJsonIgnoreFields(Object object, String ignoreFields) {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.getSerializationConfig().addMixInAnnotations(Object.class, JsonPropertyFilterMixIn.class);
String[] ignoreFieldsArray = ignoreFields.split(",");
FilterProvider filters = new SimpleFilterProvider()
.addFilter("filter properties by field names",
SimpleBeanPropertyFilter.serializeAllExcept(ignoreFieldsArray));
ObjectWriter writer = mapper.writer().withFilters(filters);
return writer.writeValueAsString(object);
} catch (Exception e) {
//handle exception here
}
return "";
}
public static String createJson(Object object) {
try {
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter();
return writer.writeValueAsString(object);
}catch (Exception e) {
//handle exception here
}
return "";
}
}
答案 9 :(得分:1)
我已经解决了仅使用@JsonIgnore
的问题,如@kryger建议的那样。
这样您的吸气剂将变为:
@JsonIgnore
public String getEncryptedPwd() {
return this.encryptedPwd;
}
您可以像描述的here一样,在字段,设置器或获取器上设置@JsonIgnore
。
并且,如果您只想在序列化方面(例如,当您需要登录用户时)保护加密密码,请将此@JsonProperty
批注添加到您的字段:
@JsonProperty(access = Access.WRITE_ONLY)
private String encryptedPwd;
更多信息here。
答案 10 :(得分:0)
不会创建UserJsonResponse
类并填充想要的字段是一个更清洁的解决方案吗?
直接返回JSON似乎是一个很好的解决方案,当你想要回馈所有模型时。否则它就会变得混乱。
将来,例如,您可能希望拥有一个与任何模型字段都不匹配的JSON字段,然后您就会遇到更大麻烦。
答案 11 :(得分:0)
这是上面answer的干净实用工具:
@GetMapping(value = "/my-url")
public @ResponseBody
MappingJacksonValue getMyBean() {
List<MyBean> myBeans = Service.findAll();
MappingJacksonValue mappingValue = MappingFilterUtils.applyFilter(myBeans, MappingFilterUtils.JsonFilterMode.EXCLUDE_FIELD_MODE, "MyFilterName", "myBiggerObject.mySmallerObject.mySmallestObject");
return mappingValue;
}
//AND THE UTILITY CLASS
public class MappingFilterUtils {
public enum JsonFilterMode {
INCLUDE_FIELD_MODE, EXCLUDE_FIELD_MODE
}
public static MappingJacksonValue applyFilter(Object object, final JsonFilterMode mode, final String filterName, final String... fields) {
if (fields == null || fields.length == 0) {
throw new IllegalArgumentException("You should pass at least one field");
}
return applyFilter(object, mode, filterName, new HashSet<>(Arrays.asList(fields)));
}
public static MappingJacksonValue applyFilter(Object object, final JsonFilterMode mode, final String filterName, final Set<String> fields) {
if (fields == null || fields.isEmpty()) {
throw new IllegalArgumentException("You should pass at least one field");
}
SimpleBeanPropertyFilter filter = null;
switch (mode) {
case EXCLUDE_FIELD_MODE:
filter = SimpleBeanPropertyFilter.serializeAllExcept(fields);
break;
case INCLUDE_FIELD_MODE:
filter = SimpleBeanPropertyFilter.filterOutAllExcept(fields);
break;
}
FilterProvider filters = new SimpleFilterProvider().addFilter(filterName, filter);
MappingJacksonValue mapping = new MappingJacksonValue(object);
mapping.setFilters(filters);
return mapping;
}
}
答案 12 :(得分:0)
将@JsonIgnore
放在字段或其获取器上,或创建自定义dto
@JsonIgnore
private String encryptedPwd;
或如上所述ceekay
用@JsonProperty
对其进行注释,其中访问属性设置为仅写
@JsonProperty( value = "password", access = JsonProperty.Access.WRITE_ONLY)
private String encryptedPwd;
答案 13 :(得分:0)
要实现动态过滤,请点击链接-https://iamvickyav.medium.com/spring-boot-dynamically-ignore-fields-while-converting-java-object-to-json-e8d642088f55
将@JsonFilter(“ Filter name”)注释添加到模型类。
在控制器功能内添加代码:-
SimpleBeanPropertyFilter simpleBeanPropertyFilter =
SimpleBeanPropertyFilter.serializeAllExcept("id", "dob");
FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("Filter name", simpleBeanPropertyFilter);
List<User> userList = userService.getAllUsers();
MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(userList);
mappingJacksonValue.setFilters(filterProvider);
return mappingJacksonValue;
确保返回类型为MappingJacksonValue。
答案 14 :(得分:-4)
在您的实体类中添加@JsonInclude(JsonInclude.Include.NON_NULL)
注释以解决问题
它看起来像
@Entity
@JsonInclude(JsonInclude.Include.NON_NULL)