使用CrudRepository

时间:2018-08-06 10:09:47

标签: spring-data-jpa amazon-dynamodb

我正在测试DynamoDB表,并想使用关键字“ dev ”进行开发,并使用 prod 进行生产并为prod和dev环境设置不同的表名。

我有一个POJO

@DynamoDBTable(tableName = "abc_xy_dev_MyProjectName_Employee")
public class Employee implements Cloneable {

}

在Prod上,我希望它的名称为abc_xy_prod_MyProjectName_Employee。

所以,我写了一个TableNameResolver

public static class MyTableNameResolver implements TableNameResolver {
    public static final MyTableNameResolver INSTANCE = new MyTableNameResolver();

    @Override
    public String getTableName(Class<?> clazz, DynamoDBMapperConfig config) {
        final TableNameOverride override = config.getTableNameOverride();
        String tableNameToReturn = null;
        if (override != null) {
            final String tableName = override.getTableName();
            if (tableName != null) {
                System.out.println("MyTableNameResolver ==================================");
                return tableName;
            }
        }
        String env = System.getenv("DEPLOYMENT_ENV");
        for(Annotation annotation : clazz.getAnnotations()){
                if(annotation instanceof DynamoDBTable){
                    DynamoDBTable myAnnotation = (DynamoDBTable) annotation;
                    if ("production".equals(env)){
                        tableNameToReturn = myAnnotation.tableName().replace("_dev_", "_prod_");
                    }
                    else {
                        tableNameToReturn = myAnnotation.tableName();
                    }
                }
            }

        return tableNameToReturn;
    }
}

这可以通过在生产环境中创建一个名称为abc_xy_prod_MyProjectName_Employee的表来实现。

但是,我有一个包含以下代码的存储库

@EnableScan
public interface EmployeeRepository extends CrudRepository<Employee, String> 
{

    @Override
    <S extends Employee> S save(S employee);

    Optional<Employee> findById(String id);

    @Override
    List<Employee> findAll();

    Optional<Employee> findByEmployeeNumber(String EmployeeNumber);

}

因此,当我尝试通过端点/测试用例调用方法findAll时,我得到了异常

  

发生意外错误(类型=内部服务器错误,   状态= 500)。用户:   arn:aws:iam :: 87668976786:user / svc_nac_ps_MyProjectName_prod不是   被授权执行:dynamodb:扫描资源:   :table / abc_xy_dev_MyProjectName_Employee(服务:AmazonDynamoDBv2;   状态码:400;错误代码:AccessDeniedException;要求编号:   aksdnhLDFL)

即,执行存储库方法时,不会在内部调用MyTableNameResolver。它仍然指向在@DynamoDBTable批注中给出的名称为abc_xy_dev_MyProjectName_Employee的表名(tableName =“ abc_xy_dev_MyProjectName_Employee”)

2 个答案:

答案 0 :(得分:1)

您正在使用DynamoDBMapper(Java SDK)。这是我的用法。可以说我有一个名为Users的表,并带有一个关联的User POJO。在DynamoDB中,我有DEV_Users和LIVE_Users。

我有一个环境变量'ApplicationEnvironmentName',它是DEV或LIVE。

我这样创建一个自定义DynamoDBMapper:

public class ApplicationDynamoMapper {

    private static Map<String, DynamoDBMapper> mappers = new HashMap<>();

    private static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
            .withRegion(System.getProperty("DynamoDbRegion")).build();

    protected ApplicationDynamoMapper() {
        // Exists only to defeat instantiation.
    }

    public static DynamoDBMapper getInstance(final String tableName) {
        final ApplicationLogContext LOG = new ApplicationLogContext();
        DynamoDBMapper mapper = mappers.get(tableName);
        if (mapper == null) {
            final String tableNameOverride = System.getProperty("ApplicationEnvironmentName") + "_" + tableName;
            LOG.debug("Creating DynamoDBMapper with overridden tablename {}.", tableNameOverride);
            final DynamoDBMapperConfig mapperConfig = new DynamoDBMapperConfig.Builder().withTableNameOverride(TableNameOverride.withTableNameReplacement(tableNameOverride)).build();
            mapper = new DynamoDBMapper(client, mapperConfig);
            mappers.put(tableName, mapper);
        }
        return mapper;
    }
}

我的用户POJO如下所示:

@DynamoDBTable(tableName = "Users")
public class User {
   ...
}

当我想使用数据库时,我将创建一个应用程序映射器,如下所示:

DynamoDBMapper userMapper = ApplicationDynamoMapper.getInstance(User.DB_TABLE_NAME);

如果我想加载一个用户,我会这样做:

User user = userMapper.load(User.class, userId);

希望有帮助。

答案 1 :(得分:1)

您已将spring JPA用作持久性dynamoDB集成。
下面的配置可作为Spring Boot配置的一部分来设置表名称覆盖。

https://github.com/ganesara/SpringExamples/tree/master/spring-dynamo

中找到了示例示例

使用用户定义的映射器配置参考来映射Dynamo数据库存储库

@EnableDynamoDBRepositories(basePackages = "home.poc.spring", dynamoDBMapperConfigRef="dynamoDBMapperConfig")

用于表覆盖的映射器配置如下

@Bean
public DynamoDBMapperConfig dynamoDBMapperConfig() {
    DynamoDBMapperConfig mapperConfig = new DynamoDBMapperConfig
            .Builder()
            .withTableNameOverride(DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix("PROD_"))
            .build();
    return mapperConfig;
}

完整配置供参考

@Configuration
@EnableDynamoDBRepositories(basePackages = "home.poc.spring", dynamoDBMapperConfigRef="dynamoDBMapperConfig")
public class DynamoDBConfig {

    @Value("${amazon.dynamodb.endpoint}")
    private String amazonDynamoDBEndpoint;

    @Value("${amazon.aws.accesskey}")
    private String amazonAWSAccessKey;

    @Value("${amazon.aws.secretkey}")
    private String amazonAWSSecretKey;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        AmazonDynamoDB amazonDynamoDB
                = new AmazonDynamoDBClient(amazonAWSCredentials());

        if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
            amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
        }

        return amazonDynamoDB;
    }

    @Bean
    public AWSCredentials amazonAWSCredentials() {
        return new BasicAWSCredentials(
                amazonAWSAccessKey, amazonAWSSecretKey);
    }

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
        DynamoDBMapperConfig mapperConfig = new DynamoDBMapperConfig
                .Builder()
                .withTableNameOverride(DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix("PROD_"))
                .build();
        return mapperConfig;
    }

    @Bean
    public DynamoDBMapper dynamoDBMapper() {
        return new DynamoDBMapper(amazonDynamoDB(), dynamoDBMapperConfig());
    }
}