Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从SpringMVC以JSON形式发送时动态忽略Java对象中的字段_Java_Json_Hibernate_Spring Mvc - Fatal编程技术网

从SpringMVC以JSON形式发送时动态忽略Java对象中的字段

从SpringMVC以JSON形式发送时动态忽略Java对象中的字段,java,json,hibernate,spring-mvc,Java,Json,Hibernate,Spring Mvc,我有这样的模型类,用于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 emailI

我有这样的模型类,用于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;
    }
}
在SpringMVC控制器中,使用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
}
如果我不想设置加密密码,我会将该字段也设置为空

但我不想这样,我不想把所有字段都发送到客户端。如果我不想发送password、updatedby、createdby字段,我的JSON结果应该是

{
  "userId" :2,
  "userName" : "john",
  "emailId" : "john@gmail.com"
}
我不想从其他数据库表发送到客户端的字段列表。因此,它将根据登录的用户进行更改。我该怎么做

我希望你明白我的问题

@JsonInclude(JsonInclude.Include.NON_NULL)
(强制Jackson序列化空值)添加到类中,并将
@JsonIgnore
添加到密码字段中

当然,如果您总是想忽略,而不仅仅是在这个特定的情况下,那么也可以在createdBy和updatedBy上设置
@JsonIgnore

更新


如果您不想将注释添加到POJO本身,最好的选择是Jackson的Mixin注释。查看将
@JsonIgnoreProperties(“fieldname”)
注释添加到POJO中

或者,在反序列化JSON时,可以在要忽略的字段名称之前使用
@JsonIgnore
。例如:

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

我知道我参加聚会有点晚了,但几个月前我也遇到过这种情况。所有可用的解决方案对我都不是很有吸引力(mixins?啊!),所以我最终创建了一个新的库来让这个过程更干净。如果有人想试用,可以在此处使用:

基本用法非常简单,您可以在控制器方法中使用
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"));
}

如果我是你们并且想这样做,我不会在控制器层使用我的用户实体,而是创建并使用UserDto(数据传输对象)与业务(服务)层和控制器通信。
您可以使用Apache BeanUtils(copyProperties方法)将数据从用户实体复制到用户DTO。

我找到了一个使用Spring和jackson的解决方案

首先在实体中指定过滤器名称

@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);

}
弹簧配置:

@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());

}

}
@EnableWebMvc
@配置
@组件扫描(basePackages=“fr.sodebo”)
公共类ApiRootConfiguration扩展了WebMVCConfigureAdapter{
@自动连线
私人实体管理工厂实体管理工厂;
/**
*这是一个“延迟加载错误”的配置
*转换JSOR Pr.Jackson倒灌DES服务
*关于jackson d’Accessor’a sessionFactory pour ce Don il a
*贝松
*/
@凌驾

public void configureMessageConverters(列表在实体类中添加
@JsonInclude(JsonInclude.Include.NON_NULL)
注释以解决此问题

看起来像

@Entity
@JsonInclude(JsonInclude.Include.NON_NULL)

创建
UserJsonResponse
类并填充所需字段不是一个更干净的解决方案吗

当您想要返回所有的模型时,直接返回JSON似乎是一个很好的解决方案,否则会变得很混乱

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

我可以动态地做吗

创建视图类:

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);
    }

}

我创建了一个JsonUtil,可以在运行时在给出响应时忽略字段

 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 "";
   }
 }    
用法示例: 第一个参数应该是任何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 "";
   }
 }    

是的,您可以指定哪些字段被序列化为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)


希望这有帮助。

我们可以通过在声明属性时设置对
JsonProperty.access.WRITE\u的访问权限来实现这一点

@JsonProperty( value = "password", access = JsonProperty.Access.WRITE_ONLY)
@SerializedName("password")
private String password;

这是用于上述用途的干净实用工具:

@GetMapping(value=“/myURL”)
公共@ResponseBody
MappingJacksonValue getMyBean(){
List myBeans=Service.findAll();
MappingJacksonValue mappingValue=MappingFilterUtils.applyFilter(myBeans,MappingFilterUtils.JsonFilterMode.EXCLUDE_字段_模式,“MyFilterName”,“myBiggerObject.MyMalleRobject.MyMallesObject”);
返回映射值;
}
//和实用类
公共类MappingFilterUtils{
公共枚举JsonFilterMode{
包括\字段\模式,排除\字段\模式
}
公共静态映射JacksonValue applyFilter(对象对象、最终JsonFilterMode模式、最终字符串过滤器名称、最终字符串…字段){
if(fields==null | | fields.length==0){
抛出新的IllegalArgumentException(“您应该至少通过一个字段”);
}
返回applyFilter(对象、模式、过滤器名称、新哈希集(Arrays.asList(fields));
}
公共静态映射JacksonValue applyFilter(对象对象、最终JsonFilterMode模式、最终字符串过滤器名称、最终设置字段){
if(fields==null | | fields.isEmpty()){
抛出新的IllegalArgumentException(“您应该至少通过一个字段”);
}
SimpleBeanPropertyFilter过滤器=null;
开关(模式){
案例排除\字段\模式:
过滤器=SimpleBeanPropert
{
  field1:"value1",
  field2:"value2"
}
{
  field1:"value1",
  field2:"value2",
  field3:"value3"
}
@JsonProperty( value = "password", access = JsonProperty.Access.WRITE_ONLY)
@SerializedName("password")
private String password;
@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;
    }
}
@JsonIgnore
private String encryptedPwd;
@JsonProperty( value = "password", access = JsonProperty.Access.WRITE_ONLY)
private String encryptedPwd;
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;