Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.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
Spring boot 在Spring数据REST中发布重复条目不会导致PK冲突_Spring Boot_Spring Data Rest - Fatal编程技术网

Spring boot 在Spring数据REST中发布重复条目不会导致PK冲突

Spring boot 在Spring数据REST中发布重复条目不会导致PK冲突,spring-boot,spring-data-rest,Spring Boot,Spring Data Rest,根据,POST方法从给定的请求主体创建一个新实体。但是,我发现它还可以更新现有的实体。在某些情况下,这可能会有问题。以下是一个例子: DemoApplication.java package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplicat

根据,POST方法从给定的请求主体创建一个新实体。但是,我发现它还可以更新现有的实体。在某些情况下,这可能会有问题。以下是一个例子:

DemoApplication.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
UserRepository.java

package com.example;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface UserRepository extends PagingAndSortingRepository<User, String> {}
pom.xml(在项目标记内)

我假设上面的POST请求在第一次得到HTTP 201,并且只有一次。然而,我能够多次发送上面的POST请求,并且一直得到HTTP201。此外,我还可以使用POST请求更改数据库中的密码

我认为这是一个安全问题。例如,我可能允许通过POST请求进行匿名用户注册。但是,在上述情况下,现有用户可能会被覆盖

问题:如果已存在具有相同id的旧实体,如何防止通过POST请求创建新实体?或者,我没有解释Spring数据REST文档吗

补充说明:

此问题的原因是Spring数据REST背后的设计。因为SpringDataREST是基于SpringDataJPA构建的,而JPA并没有用于直接向“外部”公开。因此,它“信任”输入的数据。中的“方法是新的”显示了如何确定数据是否为新数据

public boolean isNew(T entity) {

    ID id = getId(entity);
    Class<ID> idType = getIdType();

    if (!idType.isPrimitive()) {
        return id == null;
    }

    if (id instanceof Number) {
        return ((Number) id).longValue() == 0L;
    }

    throw new IllegalArgumentException(String.format("Unsupported primitive id type %s!", idType));
}
public boolean isNew(T实体){
ID=getId(实体);
类idType=getIdType();
如果(!idType.isPrimitive()){
返回id==null;
}
if(id instanceof Number){
返回((数字)id).longValue()==0L;
}
抛出新的IllegalArgumentException(String.format(“不支持的基元id类型%s!”,idType));
}
新方法的结果将最终影响保存方法

public的保存(S实体){
if(entityInformation.isNew(实体)){
em.persist(实体);
返回实体;
}否则{
返回em.merge(实体);
}
}
在本问题中提到的情况下,用户名字段(也是用户实体的id)将始终包含创建新用户所需的数据。因此,当它转到isNew时,id==null将始终返回false。然后save方法将始终执行合并操作

以上是我所能提供的全部提示。尽管如此,我不知道是否有解决这个问题的办法


URL链接只是引用。它们可能与我使用的版本不完全相同。

要使实体与Spring数据REST(以及Spring数据JPA)正常工作,实体类需要实现持久化。要重写的更值得注意的方法是isNew()。将调用此方法,而不是问题中提到的AbstractEntityInformation中的方法。为了使实体了解自己的状态(新的或旧的),还需要一个版本变量。通过在显式字段上注释@Version,Spring数据JPA将更新此字段。因此,一旦第一次构造实体,字段就是它的默认值(null或0,取决于它使用的数据类型)。此外,由于SpringDataREST旨在向外界公开,为了防止版本被误用,在版本字段中使用@JsonIgnore

对于这个特定问题,User.java类需要更改为以下内容:

package com.example;

import javax.persistence.*;
import org.springframework.data.domain.Persistable;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
public class User implements Persistable<String> {

    /**
     * 
     */
    private static final long serialVersionUID = 7509971300023426574L;
    @Id
    private String username;

    private String password;

    @Version
    @JsonIgnore
    private Long version;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

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

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    @Override
    public String getId() {
        return username;
    }

    @Override
    public boolean isNew() {
        return version == null;
    }
}
package.com.example;
导入javax.persistence.*;
导入org.springframework.data.domain.Persistable;
导入com.fasterxml.jackson.annotation.JsonIgnore;
@实体
公共类用户实现持久化{
/**
* 
*/
私有静态最终长serialVersionUID=7509971300023426574L;
@身份证
私有字符串用户名;
私有字符串密码;
@版本
@杰索尼奥雷
私人长版;
公共字符串getUsername(){
返回用户名;
}
public void setUsername(字符串用户名){
this.username=用户名;
}
公共字符串getPassword(){
返回密码;
}
public void setPassword(字符串密码){
this.password=密码;
}
公共长getVersion(){
返回版本;
}
公共版本(长版本){
this.version=版本;
}
@凌驾
公共字符串getId(){
返回用户名;
}
@凌驾
public boolean isNew(){
返回版本==null;
}
}

正如@Alan Hay所提到的,还应该对传入数据进行验证。拥有它肯定很好。

即使它不是PK/ID,您仍然需要在添加/编辑之前进行验证以捕获重复项。对吗?所以写一个验证器。
{"username":"user","password":"password"}
public boolean isNew(T entity) {

    ID id = getId(entity);
    Class<ID> idType = getIdType();

    if (!idType.isPrimitive()) {
        return id == null;
    }

    if (id instanceof Number) {
        return ((Number) id).longValue() == 0L;
    }

    throw new IllegalArgumentException(String.format("Unsupported primitive id type %s!", idType));
}
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}
package com.example;

import javax.persistence.*;
import org.springframework.data.domain.Persistable;
import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
public class User implements Persistable<String> {

    /**
     * 
     */
    private static final long serialVersionUID = 7509971300023426574L;
    @Id
    private String username;

    private String password;

    @Version
    @JsonIgnore
    private Long version;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

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

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    @Override
    public String getId() {
        return username;
    }

    @Override
    public boolean isNew() {
        return version == null;
    }
}