当前位置: 首页 > 知识库问答 >
问题:

Spring:无法持久化用@JsonIgnore注释的实体

曾华翰
2023-03-14

我是Spring靴的初学者,不能解决问题。我有一个实体类(Customer)和一个REST存储库(CustomerRepository)。类包含一些我不想被REST存储库公开的敏感字段。因此,我使用@jsonIgnore注释对这些字段进行了注释,如下所示:

package br.univali.sapi.entities;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Customer
{
    @Id
    @GeneratedValue
    private Long id = null;

    private String login;

    private String name;

    @JsonIgnore
    private String password;

    @JsonIgnore
    private String email;

    public Customer()
    {

    }

    public Long getId()
    {
            return id;
    }

    public void setId(Long id)
    {
            this.id = id;
    }

    public String getLogin()
    {
            return login;
    }

    public void setLogin(String login)
    {
            this.login = login;
    }

    public String getName()
    {
            return name;
    }

    public void setName(String name)
    {
            this.name = name;
    }

    public String getPassword()
    {
            return password;
    }

    public void setPassword(String password)
    {
            this.password = password;
    }

    public String getEmail()
    {
            return email;
    }

    public void setEmail(String email)
    {
            this.email = email;
    }
}

一切正常,我的REST API返回了所需的结果。但是,当我向API发出POST请求以插入新实体时,我会收到数据库错误:“Column password Can't be Null”、“Column email Can't be Null”

在POST请求中,密码和电子邮件与其他参数一起发送到服务器,但似乎被忽略了。如果删除@JSONIGNORE注释,实体将正常持久化。

我知道我可以用投影来隐藏这些区域。但投影是URL中的可选参数。这样,经验丰富的用户就可以从请求URL中删除参数,并查看这些字段。

如果我可以隐式地强制一个投影,那就解决了问题,但这似乎仅仅使用Spring框架是不可能做到的。我可以使用Apache URL重写来实现这一点,但维护会很糟糕。

有没有人知道我该怎么解决这个问题?谢谢!

public interface CustomerViewDTO
{
    public Long getId();
    public String getLogin();
    public String getName();
}
public class CustomerUpdateDTO
{
   private String login;
   private String name;
   private String password;
   private String email;

   // Getters and Setters ommited for breviety
}
@Transactional(readOnly = true)
public interface CustomerRepository extends JPARepository<Customer, Long>
{
   // Using derived query
   public CustomerViewDTO findByIdAsDTO(Long id);

   // Using @Query annotation
   @Query("SELECT C FROM Customer C WHERE C.id = :customerId")
   public CustomerViewDTO findByIdAsDTO(@Param("customerId") Long id);
}   
@RestController
public class CustomerController
{
    @Autowired
    private CustomerService customerService;

    @RequestMapping(method = "PATCH", path = "/customers/{customerId}")
    public ResponseEntity<?> updateCustomer(@PathVariable Long customerId, @RequestBody CustomerUpdateDTO customerDTO)
    {
        CustomerViewDTO updatedCustomer = customerService.updateCustomer(customerId, customerDTO);

        return ResponseEntity.ok(updatedCustomer);
    }

    @RequestMapping(method = GET, path = "/customers/{customerId}")
    public ResponseEntity<?> findCustomerById(@PathVariable Long customerId)
    {
        return ResponseEntity.ok(customerService.findByIdAsDTO(Long));
    }
}
@Service
public class CustomerService
{
    @Autowired
    private CustomerRepository customerRepository;

    // Follow this tutorial:
    // https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
    @Autowired
    private ModelMapper modelMapper; 

    @Transactional(readOnly = false)
    public CustomerViewDTO updateCustomer(Long customerId, CustomerUpdateDTO customerDTO)
    {
         Customer customerEntity = customerRepository.findById(customerId);

         // This copies all values from the DTO to the entity
         modelMapper.map(customerDTO, customerEntity); 

         // Now we have two aproaches: 
         // 1. save the entity and convert back to DTO manually using the model mapper
         // 2. save the entity and call the repository method which will convert to the DTO automatically
         // The second approach is the one I use for several reasons that
         // I won't explain here

         // Here we use save and flush to force JPA to execute the update query. This way, when we do the select the entity will come with the fields updated
         customerEntity = customerRepository.saveAndFlush(customerEntity);

         // First aproach
         return modelMapper.map(customerEntity, CustomerViewDTO.class);

         // Second approach
         return customerRepository.findByIdAsDTO(customerId);
    }

    @Transactional(readOnly = true)
    public CustomerViewDTO findByIdAsDTO(Long customerId)
    {
         return customerRepository.findByIdAsDTO(customerId);
    }
}

共有1个答案

陈坚
2023-03-14

我想您在db级别上没有null约束。基本上,当您在字段上执行@jsonignore时,您只是没有传递它,数据库就不能插入该值,这是非常清楚的。

所以我在这里看到的解决方案是这样的:

1)删除@jsonIgnore注释,以便能够执行POST请求。

 类似资料:
  • 我对Spring注释和persist有一个误解。我使用的是Spring3.1,带有JPA和Hibernate。我认为persist意味着将实体添加到持久性上下文中(但在提交或刷新之前不要执行任何查询),而注释意味着用事务包装方法。 然而,在这个简短的例子中,当执行指针到达持久性时,它会失败并出现异常,因为name不能为null(db约束)。 如果我交换和,一切正常。然而,我不明白为什么反过来没有,

  • 我有以下JPA实体类。和扩展Project的另一个实体OptProject。我正在使用InheritanceType.Jointed OptProject实体的JPA存储库如下 当我创建一个OptProject并尝试保存它时,我会得到下面的错误消息。这对我来说毫无意义,因为我使用@GeneratedValue(Streaty=GenerationType.Identity)为SQL server生

  • 我正在尝试使用来持久化一个实体。当我自己处理事务时,我的测试用例工作(数据保存在db中)。 (实体管理器来自我的DAO类扩展的模板类) 当我配置spring来处理事务时,它会停止分发数据。 测试上下文。xml: UsersRepositoryTest: 堆栈跟踪: 从stacktrace中可以看到,事务似乎已经启动和完成,但没有生成sql插入,也没有数据插入到数据库中(数据回滚设置为false)

  • 我创建了一个简单的3实体数据模型,当试图持久化数据时,它不起作用。下面是实体及其id类,server: 服务: 容器: 创建的数据库似乎正常:

  • 我已经在这个问题上工作了两天了,现在我没有主意了。 下面是entity和dao类: 抽象性: 域道: 我不认为问题出在EntityManager或dao类中,因为EntityManager(find())至少有一个方法起作用。我会很感激和帮忙的。

  • 我可以在lombok中使用@JsonIgnore和@getter注释,而不显式定义getter,因为我必须在序列化对象时使用这个JsonIgnore,但是在反序列化时,JsonIgnore注释必须是ignore,所以对象中的字段不能为空。 我知道,只要在password的getter上定义JsonIgnore就可以防止我的密码被序列化,但为此我必须显式定义我不想要的getter。任何建议,任何帮助