jpa 无法识别Spring Data REST @ Id类

wqlqzqxt  于 2022-11-14  发布在  Spring
关注(0)|答案(4)|浏览(171)

我有一个名为EmployeeDepartment的实体,如下所示

@IdClass(EmployeeDepartmentPK.class) //EmployeeDepartmentPK is a serializeable object
@Entity
EmployeeDepartment{

@Id
private String employeeID;

@Id
private String departmentCode;
---- Getters, Setters and other props/columns
}

我有一个Spring Data 存储库,定义如下

@RepositoryRestResource(....)
public interface IEmployeeDepartmentRepository extends PagingAndSortingRepository<EmployeeDepartment, EmployeeDepartmentPK> {

}

此外,我还注册了一个转换器,用于将String转换为EmployeeDepartmentPK。
现在,对于一个由ID employeeID=“abc123”和departmentCode=“JBG”限定的实体,我希望在调用SDR接口时使用的ID是abc123_JBG。例如,http://localhost/EmployeeDepartment/abc123_JBG应该会获取结果,它确实做到了。
但是,当我尝试使用PUT保存实体时,Spring Data Commons的BasicPersistentEntity类中可用的ID属性的departmentCode值为abc123_JBG。这是错误的。我不确定这是否是预期行为。
请帮帮忙。
谢谢你!

8gsdolmq

8gsdolmq1#

目前Spring Data REST只支持由单个字段表示的复合键。这实际上意味着只支持@EmbeddedId。我已经提交了DATAJPA-770来解决这个问题。
如果您可以切换到@EmbeddedId,您仍然需要教Spring Data REST您希望在URI中表示复杂标识符的方式,以及如何将路径段转换回id类型的示例。要实现这一点,请实现一个BackendIdConverter并将其注册为Spring bean。

@Component
class CustomBackendIdConverter implements BackendIdConverter {

  @Override
  public Serializable fromRequestId(String id, Class<?> entityType) {

    // Make sure you validate the input

    String[] parts = id.split("_");
    return new YourEmbeddedIdType(parts[0], parts[1]);
  }

  @Override
  public String toRequestId(Serializable source, Class<?> entityType) {

    YourIdType id = (YourIdType) source;
    return String.format("%s_%s", …);
  }

  @Override
  public boolean supports(Class<?> type) {
    return YourDomainType.class.equals(type);
  }
}
pkwftd7m

pkwftd7m2#

如果你不能使用@EmbeddedId,你仍然可以使用@IdClass。为此,你需要像奥利弗Gierke回答的那样使用BackendIdConverter,但是你还需要为你的域类型添加一个Lookup:

@Configuration
public class IdClassAllowingConfig extends RepositoryRestConfigurerAdapter {

@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.withEntityLookup().forRepository(EmployeeDepartmentRepository.class, (EmployeeDepartment ed) -> {
        EmployeeDepartmentPK pk = new EmployeeDepartmentPK();
        pk.setDepartmentId(ed.getDepartmentId());
        pk.setEmployeeId(ed.getEmployeeId());
        return pk;
    }, EmployeeDepartmentRepository::findOne);
}

}

yeotifhr

yeotifhr3#

使用@BasePathAwareController自定义Spring Data 休息控制器。

@BasePathAwareController
    public class CustInfoCustAcctController {

    @Autowired
    CustInfoCustAcctRepository cicaRepo;

    @RequestMapping(value = "/custInfoCustAccts/{id}", method = RequestMethod.GET)
    public @ResponseBody custInfoCustAccts getOne(@PathVariable("id") String id) {
        String[] parts = id.split("_");
        CustInfoCustAcctKey key = new CustInfoCustAcctKey(parts[0],parts[1]);
        return cicaRepo.getOne(key);
    }
}

对于示例uri /api/custInfoCustAccts/89232_70,它可以正常工作

t30tvxxf

t30tvxxf4#

更一般的方法如下:

package com.pratham.persistence.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.istack.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import javax.persistence.EmbeddedId;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * Customization of how composite ids are exposed in URIs.
 * The implementation will convert the Ids marked with {@link EmbeddedId} to base64 encoded json
 * in order to expose them properly within URI.
 *
 * @author im-pratham
 */
@Component
@RequiredArgsConstructor
public class EmbeddedBackendIdConverter implements BackendIdConverter {
    private final ObjectMapper objectMapper;

    @Override
    public Serializable fromRequestId(String id, Class<?> entityType) {
        return getFieldWithEmbeddedAnnotation(entityType)
                .map(Field::getType)
                .map(ret -> {
                    try {
                        String decodedId = new String(Base64.getUrlDecoder().decode(id));
                        return (Serializable) objectMapper.readValue(decodedId, (Class) ret);
                    } catch (JsonProcessingException ignored) {
                        return null;
                    }
                })
                .orElse(id);
    }

    @Override
    public String toRequestId(Serializable id, Class<?> entityType) {
        try {
            String json = objectMapper.writeValueAsString(id);
            return Base64.getUrlEncoder().encodeToString(json.getBytes(UTF_8));
        } catch (JsonProcessingException ignored) {
            return id.toString();
        }
    }

    @Override
    public boolean supports(@NonNull Class<?> entity) {
        return isEmbeddedIdAnnotationPresent(entity);
    }

    private boolean isEmbeddedIdAnnotationPresent(Class<?> entity) {
        return getFieldWithEmbeddedAnnotation(entity)
                .isPresent();
    }

    @NotNull
    private static Optional<Field> getFieldWithEmbeddedAnnotation(Class<?> entity) {
        return Arrays.stream(entity.getDeclaredFields())
                .filter(method -> method.isAnnotationPresent(EmbeddedId.class))
                .findFirst();
    }
}

相关问题