栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

3. AWS DynamoDB实战之CRUD

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

3. AWS DynamoDB实战之CRUD

基表抽象

 在 2. AWS DynamoDB实战之表的设计 一文中,详细介绍了如何设计dto model以及dynamodb的表,仔细观察我们的三个dto,它们具有一些共同点:

  • 都有pk和sk的getter和setter
  • item的唯一标识符由pk和sk构成

综合上述特点,我们抽象出一个dto mode的基类AbstractDto:

  • AbstractDto是一个抽象类
  • 包含四个抽象方法,分别为pk和sk的getter和setter
  • 包含一个用于获取item唯一标识符的方法,返回的唯一标识符格式为:  pk#sk
package com.jessica.dynamodb.favorite.dto;

public abstract class AbstractDto {
	public abstract String getPk();

	public abstract void setPk(String hashKey);

	public abstract String getSk();

	public abstract void setSk(String rangeKey);

	
	public String getCompositeKey() {
		return String.join("#", getPk(), getSk());
	}
}

添加了AbstractDto以后,其他所有的Dto都需要继承该类:

package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class TagDto extends AbstractDto {
	private static final String DTO_NAME = "Tag";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String tagId;
	@DynamoDBAttribute
	private String tagName;
	@DynamoDBAttribute
	private long createTime;
	@DynamoDBAttribute
	private long lastAccessTime;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(tagId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.tagId = keys[0];
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_ONE_NAME)
	public String getLsioneSk() {
		return KeyGenerator.createRangeKey(tagName);
	}

	public void setLsioneSk(String lsiOneSk) {
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_TWO_NAME)
	public String getLsiTwoSk() {
		return KeyGenerator.createRangeKey(String.valueOf(createTime), tagId);
	}

	public void setLsiTwoSk(String lsiTwoSk) {
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_THREE_NAME)
	public String getLsiThreeSk() {
		return KeyGenerator.createRangeKey(String.valueOf(lastAccessTime), tagId);
	}

	public void setLsiThreeSk(String lsiThreeSk) {
	}

}
package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConvertedEnum;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class FavoriteDataDto extends AbstractDto {
	private static final String DTO_NAME = "FavoriteData";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String dataId;
	@DynamoDBAttribute
	private String creatorId;
	@DynamoDBAttribute
	private String title;
	@DynamoDBAttribute
	private String thumbnailUrl;
	@DynamoDBAttribute
	private String contentUrl;
	@DynamoDBTypeConvertedEnum
	@DynamoDBAttribute
	private FavoriteDataType dataType;
	@DynamoDBAttribute
	private String clipTime;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(dataId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.dataId = keys[0];
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsionePk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, dataType.getValue());
	}

	public void setGsionePk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsioneSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsioneSk(String rangeKey) {
	}
}
package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConvertedEnum;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class FavoriteDataTagDto extends AbstractDto {
	private static final String DTO_NAME = "FavoriteDataTag";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String dataId;
	@DynamoDBIgnore
	private String tagId;
	@DynamoDBAttribute
	private String clipTime;
	@DynamoDBTypeConvertedEnum
	@DynamoDBAttribute
	private FavoriteDataType dataType;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, dataId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
		this.dataId = keys[1];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(tagId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.tagId = keys[0];
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsionePk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, tagId);
	}

	public void setGsionePk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsioneSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsioneSk(String rangeKey) {
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_TWO_NAME)
	public String getGsiTwoPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, tagId, dataType.getValue());
	}

	public void setGsiTwoPk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_TWO_NAME)
	public String getGsiTwoSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsiTwoSk(String rangeKey) {
	}
}
通用接口抽象

一般来讲,每个dto model都会对应一个dao,用于对该dto进行crud操作.实际实现过程中发现一些基本的crud操作的代码是完全一样的,因此我们也实现一个通用接口来进行这些基本的crud操作.

package com.jessica.dynamodb.favorite.dao;

import java.util.List;
import java.util.Map;

import com.jessica.dynamodb.favorite.data.LazyLoadResult;

public interface BasicDao {
	
	void save(T dto);

	
	T load(T keyDto);

	
	void delete(T keyDto);

	
	void batchSave(List dtos);

	
	List batchLoad(List keyDtos);

	
	Map batchLoadMap(List keyDtos);

	
	void batchDelete(List keyDtos);

	
	LazyLoadResult query(Class clazz, T hashKeyDto, boolean asc, String lastLoadSk, Integer size);

	
	LazyLoadResult queryIndex(Class clazz, String indexName, String indexSkName, T hashKeyDto, boolean asc,
			String lastLoadSk, Integer size);
}
package com.jessica.dynamodb.favorite.dao.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryexpression;
import com.amazonaws.services.dynamodbv2.model.Attributevalue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.BasicDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.AbstractDto;

public class BasicDaoImpl implements BasicDao {
	protected DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(AmazonDynamoDBClientBuilder.standard().build());

	@Override
	public void save(T dto) {
		this.dynamoDBMapper.save(dto);
	}

	@Override
	public T load(T keyDto) {
		return this.dynamoDBMapper.load(keyDto);
	}

	@Override
	public void delete(T keyDto) {
		this.dynamoDBMapper.delete(keyDto);
	}

	@Override
	public void batchSave(List dtos) {
		this.dynamoDBMapper.batchSave(dtos);
	}

	@Override
	public List batchLoad(List keyDtos) {
		return this.dynamoDBMapper.batchLoad(keyDtos).values().stream().flatMap(Collection::stream)
				.map(object -> (T) object).collect(Collectors.toList());
	}

	@Override
	public Map batchLoadMap(List keyDtos) {
		return this.batchLoad(keyDtos).stream()
				.collect(Collectors.toMap(t -> ((AbstractDto) t).getCompositeKey(), Function.identity()));
	}

	@Override
	public void batchDelete(List keyDtos) {
		this.dynamoDBMapper.batchDelete(keyDtos);
	}

	@Override
	public LazyLoadResult query(Class clazz, T hashKeyDto, boolean asc, String lastLoadSk, Integer size) {
		DynamoDBQueryexpression queryexpression = new DynamoDBQueryexpression().withHashKeyValues(hashKeyDto)
				.withScanIndexForward(asc);
		if (lastLoadSk != null) {
			Condition rangeCondition = new Condition()
					.withComparisonOperator(asc ? ComparisonOperator.GT : ComparisonOperator.LT)
					.withAttributevalueList(new Attributevalue(lastLoadSk));
			queryexpression.withRangeKeyCondition(DynamoDBConstant.RANGE_KEY, rangeCondition);
		}

		List dtos;
		boolean hasLimit = size != null && size > 0;
		if (hasLimit) {
			queryexpression.setLimit(size);
			dtos = this.dynamoDBMapper.queryPage(clazz, queryexpression).getResults();
		} else {
			dtos = this.dynamoDBMapper.query(clazz, queryexpression);
		}

		if (dtos.size() == 0) {
			return new LazyLoadResult<>(new ArrayList<>(), false, null);
		}
		return new LazyLoadResult<>(dtos, hasLimit ? dtos.size() == size : false, dtos.get(dtos.size() - 1).getSk());
	}

	@Override
	public LazyLoadResult queryIndex(Class clazz, String indexName, String indexSkName, T hashKeyDto, boolean asc,
			String lastLoadSk, Integer size) {
		DynamoDBQueryexpression queryexpression = new DynamoDBQueryexpression().withIndexName(indexName)
				.withHashKeyValues(hashKeyDto).withScanIndexForward(asc);
		if (lastLoadSk != null) {
			Condition rangeCondition = new Condition()
					.withComparisonOperator(asc ? ComparisonOperator.GT : ComparisonOperator.LT)
					.withAttributevalueList(new Attributevalue(lastLoadSk));
			queryexpression.withRangeKeyCondition(indexSkName, rangeCondition);
		}

		List dtos;
		boolean hasLimit = size != null && size > 0;
		if (hasLimit) {
			queryexpression.setLimit(size);
			dtos = this.dynamoDBMapper.queryPage(clazz, queryexpression).getResults();
		} else {
			dtos = this.dynamoDBMapper.query(clazz, queryexpression);
		}

		if (dtos.size() == 0) {
			return new LazyLoadResult<>(new ArrayList<>(), false, null);
		}
		T lastLoadDto = dtos.get(dtos.size() - 1);
		try {
			Method method = clazz.getMethod("get" + upperCaseFirstLatter(indexSkName));
			return new LazyLoadResult(dtos, hasLimit ? dtos.size() == size : false,
					(String) method.invoke(lastLoadDto));
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	private String upperCaseFirstLatter(String str) {
		char[] strChar = str.toCharArray();
		strChar[0] -= 32;
		return String.valueOf(strChar);
	}
}

实现了BasicDao之后,我们通过编写JUnit test来对实现类进行测试:

pom文件中添加dependency:

 
   junit
   junit
   4.12
   test
 

测试类:

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.junit.Test;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.impl.BasicDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class BasicDaoImplTest {

	BasicDao basicDao = new BasicDaoImpl<>();

	@Test
	public void testSaveLoadDelete() {
		// prepare data
		String userId = "userId1";
		String tagId = UUID.randomUUID().toString();
		String tagName = "firstTag";
		Date now = new Date();
		TagDto newTagDto = TagDto.builder().userId(userId).tagId(tagId).tagName(tagName).createTime(now.getTime())
				.lastAccessTime(now.getTime()).build();
		// run test
		basicDao.save(newTagDto);
		TagDto loadedDto = basicDao.load(newTagDto);
		assertNotNull(loadedDto);

		// clean data
		basicDao.delete(newTagDto);
		loadedDto = basicDao.load(newTagDto);
		assertNull(loadedDto);
	}

	@Test
	public void testBatchSaveLoadDelete() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date1 = new Date();
		String userId2 = "userId2";
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		Date date2 = new Date();
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1).createTime(date1.getTime())
				.lastAccessTime(date1.getTime()).build();
		TagDto newTagDto2 = TagDto.builder().userId(userId2).tagId(tagId2).tagName(tagName2).createTime(date2.getTime())
				.lastAccessTime(date2.getTime()).build();
		List dtos = Arrays.asList(newTagDto1, newTagDto2);
		basicDao.batchSave(dtos);

		// run test
		List loadedDtos = basicDao.batchLoad(dtos);
		assertEquals(2, loadedDtos.size());

		// clean data
		basicDao.batchDelete(dtos);

		// run test
		loadedDtos = basicDao.batchLoad(dtos);
		assertEquals(0, loadedDtos.size());
	}

	@Test
	public void testQuery() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = "firstTag";
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = "secondTag";
		String tagName2 = "secondTag";
		String tagId3 = "thirdTag";
		String tagName3 = "thirdTag";
		String tagId4 = "fouthTag";
		String tagName4 = "fouthTag";
		String userId2 = "userId2";
		String tagId5 = "fifthTag";
		String tagName5 = "fifthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		TagDto newTagDto5 = TagDto.builder().userId(userId2).tagId(tagId5).tagName(tagName5).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4, newTagDto5);
		basicDao.batchSave(dtos);

		try {
			// test sk desc order with size
			LazyLoadResult lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, null, 2);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false,
					lazyLoadResult.getLoadedDtos().get(1).getSk(), 3);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk aes order with size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, null, 2);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true,
					lazyLoadResult.getLoadedDtos().get(1).getSk(), 3);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk aes order without size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, null, null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, newTagDto4.getSk(), null);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk desc order without size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, null, null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, newTagDto3.getSk(), null);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(2).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			basicDao.batchDelete(dtos);
		}
	}

	@Test
	public void testQueryIndex() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		String tagId3 = UUID.randomUUID().toString();
		String tagName3 = "thirdTag";
		String tagId4 = UUID.randomUUID().toString();
		String tagName4 = "fouthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		basicDao.save(newTagDto1);
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		basicDao.save(newTagDto2);
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		basicDao.save(newTagDto3);
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4);
		basicDao.batchSave(dtos);
		try {
			// test tag name desc order
			LazyLoadResult lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false, null,
					3);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false,
					lazyLoadResult.getLastLoadPos(), 3);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test load all
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false, null,
					null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			// test tag name aes order
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), true, null, 3);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), true,
					lazyLoadResult.getLastLoadPos(), 3);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			basicDao.batchDelete(dtos);
		}
	}
}
实现TagDao

根据之前的分析,除了基本的crud操作之后,TagDao还需要支持获取某个user创建的所有tag,返回结果可以有三种排序方式:

  • 按照tag创建的时间进行排序
  • 按照tag的名称进行排序
  • 按照tag的最近访问时间进行排序

因此只需要在TagDao实现上述三种排序方式的查询即可.

package com.jessica.dynamodb.favorite.dao;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public interface TagDao extends BasicDao {
	
	LazyLoadResult getTagsByUserId(String userId, TagSortField tagSortField, String lastLoadSk, Integer size,
			boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.dao.TagDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class TagDaoImpl extends BasicDaoImpl implements TagDao {

	@Override
	public LazyLoadResult getTagsByUserId(String userId, TagSortField tagSortField, String lastLoadSk,
			Integer size, boolean asc) {
		return this.queryIndex(TagDto.class, tagSortField.getLsiName(), tagSortField.getLsiSkName(),
				TagDto.builder().userId(userId).build(), asc, lastLoadSk, size);
	}
}

同样,我们通过编写JUnit test来对实现类进行测试,也可以直接写个main方法来测试:

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.junit.Test;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.dao.impl.TagDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class TagDaoImplTest {

	TagDao tagDao = new TagDaoImpl();

	@Test
	public void testGetTagsByUserId() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		String tagId3 = UUID.randomUUID().toString();
		String tagName3 = "thirdTag";
		String tagId4 = UUID.randomUUID().toString();
		String tagName4 = "fouthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		tagDao.save(newTagDto1);
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		tagDao.save(newTagDto2);
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		tagDao.save(newTagDto3);
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4);
		tagDao.batchSave(dtos);
		try {

			// test tag name desc order
			LazyLoadResult lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, null, 3,
					false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test tag name aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test create time desc order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, null, 3, false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, lazyLoadResult.getLastLoadPos(),
					3, false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test create time aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, lazyLoadResult.getLastLoadPos(),
					3, true);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test last access time desc order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME, null, 3, false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME,
					lazyLoadResult.getLastLoadPos(), 3, false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test last access time aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME,
					lazyLoadResult.getLastLoadPos(), 3, true);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			tagDao.batchDelete(dtos);
		}
	}
}
实现FavoriteDataDao

根据需求,除了基本的crud操作之外,FavoriteDataDto有两个方法需要实现:

  • 获取用户收藏的所有数据,并按收藏时间降序排序,只需要以userId作为hashKey进行query操作即可,已经在BasicDao中实现
  • 获取所有某种特定类型的收藏数据,并按收藏时间降序排序,所以只需要实现这一个方法,以userId&type作为hashKey,对Global Secondary Index进行query操作即可
package com.jessica.dynamodb.favorite.dao;

import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public interface FavoriteDataDao extends BasicDao {
	
	LazyLoadResult getFavoriteData(String userId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.FavoriteDataDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataDaoImpl extends BasicDaoImpl implements FavoriteDataDao {

	@Override
	public LazyLoadResult getFavoriteData(String userId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc) {
		return this.queryIndex(FavoriteDataDto.class, DynamoDBConstant.GSI_ONE_NAME, DynamoDBConstant.GSI_ONE_RANGE_KEY,
				FavoriteDataDto.builder().userId(userId).dataType(dataType).build(), asc, lastLoadSk, size);
	}
}

测试类

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.jessica.dynamodb.favorite.dao.impl.FavoriteDataDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataDaoImplTest {
	FavoriteDataDao favoriteDataDao = new FavoriteDataDaoImpl();

	@Test
	public void testGetFavoriteData() {
		// prepare data
		String userId1 = "userId1";
		String userId2 = "userId2";
		String dataId1 = "dataId1";
		String dataId2 = "dataId2";
		String dataId3 = "dataId3";
		String dataId4 = "dataId4";
		String dataId5 = "dataId5";
		String dataId6 = "dataId6";
		FavoriteDataType dataType1 = FavoriteDataType.FILE;
		FavoriteDataType dataType2 = FavoriteDataType.IMAGE;
		Date date = new Date();
		FavoriteDataDto dataDto1 = FavoriteDataDto.builder().userId(userId1).dataId(dataId1)
				.clipTime(String.valueOf(date.getTime())).dataType(dataType1).build();
		FavoriteDataDto dataDto2 = FavoriteDataDto.builder().userId(userId1).dataId(dataId2)
				.clipTime(String.valueOf(date.getTime() - 2000)).dataType(dataType1).build();
		FavoriteDataDto dataDto3 = FavoriteDataDto.builder().userId(userId1).dataId(dataId3)
				.clipTime(String.valueOf(date.getTime() - 3000)).dataType(dataType1).build();
		FavoriteDataDto dataDto4 = FavoriteDataDto.builder().userId(userId1).dataId(dataId4)
				.clipTime(String.valueOf(date.getTime() - 4000)).dataType(dataType1).build();
		FavoriteDataDto dataDto5 = FavoriteDataDto.builder().userId(userId1).dataId(dataId5)
				.clipTime(String.valueOf(date.getTime() - 5000)).dataType(dataType2).build();
		FavoriteDataDto dataDto6 = FavoriteDataDto.builder().userId(userId1).dataId(dataId6)
				.clipTime(String.valueOf(date.getTime() - 6000)).dataType(dataType2).build();
		FavoriteDataDto dataDto7 = FavoriteDataDto.builder().userId(userId2).dataId(dataId5)
				.clipTime(String.valueOf(date.getTime() - 7000)).dataType(dataType1).build();
		FavoriteDataDto dataDto8 = FavoriteDataDto.builder().userId(userId2).dataId(dataId6)
				.clipTime(String.valueOf(date.getTime() - 8000)).dataType(dataType2).build();
		List dtos = Arrays.asList(dataDto1, dataDto2, dataDto3, dataDto4, dataDto5, dataDto6, dataDto7,
				dataDto8);
		favoriteDataDao.batchSave(dtos);

		try {

			// test clip time desc order
			LazyLoadResult lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, null,
					2, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(1).getDataId());

			// test clip time desc order
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, null, 2, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1).getDataId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataDao.batchDelete(dtos);
		}
	}
}

实现FavoriteDataTagDao

根据需求,FavoriteDataTagDto有如下特性:

  • 获取被收藏数据上添加的所有tag, 以userId作为hashKey进行query操作即可,已经在BasicDao中实现
  • 获取所有添加了某个tag的收藏数据,并按收藏时间降序排序,以userId&tagId作为hashKey,对第一个Global Secondary Index进行query操作即可
  • 获取所有添加了某个tag的某种特定类型的收藏数据,并按收藏时间降序排序,以userId&tagId&type作为hashKey,对第二个Global Secondary Index进行query操作即可
package com.jessica.dynamodb.favorite.dao;

import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public interface FavoriteDataTagDao extends BasicDao {
	
	LazyLoadResult getFavoriteDataIds(String userId, String tagId, String lastLoadSk, Integer size,
			boolean asc);

	
	LazyLoadResult getFavoriteDataIds(String userId, String tagId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import java.util.stream.Collectors;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.FavoriteDataTagDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataTagDaoImpl extends BasicDaoImpl implements FavoriteDataTagDao {

	@Override
	public LazyLoadResult getFavoriteDataIds(String userId, String tagId, String lastLoadSk, Integer size,
			boolean asc) {
		LazyLoadResult result = this.queryIndex(FavoriteDataTagDto.class,
				DynamoDBConstant.GSI_ONE_NAME, DynamoDBConstant.GSI_ONE_RANGE_KEY,
				FavoriteDataTagDto.builder().userId(userId).tagId(tagId).build(), asc, lastLoadSk, size);
		return new LazyLoadResult<>(
				result.getLoadedDtos().stream().map(FavoriteDataTagDto::getDataId).collect(Collectors.toList()),
				result.isHasMore(), result.getLastLoadPos());

	}

	@Override
	public LazyLoadResult getFavoriteDataIds(String userId, String tagId, FavoriteDataType dataType,
			String lastLoadSk, Integer size, boolean asc) {
		LazyLoadResult result = this.queryIndex(FavoriteDataTagDto.class,
				DynamoDBConstant.GSI_TWO_NAME, DynamoDBConstant.GSI_TWO_RANGE_KEY,
				FavoriteDataTagDto.builder().userId(userId).tagId(tagId).dataType(dataType).build(), asc, lastLoadSk,
				size);
		return new LazyLoadResult<>(
				result.getLoadedDtos().stream().map(FavoriteDataTagDto::getDataId).collect(Collectors.toList()),
				result.isHasMore(), result.getLastLoadPos());
	}

}

测试类

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.jessica.dynamodb.favorite.dao.impl.FavoriteDataTagDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataTagDaoImplTest {
	FavoriteDataTagDao favoriteDataTagDao = new FavoriteDataTagDaoImpl();
	String userId1 = "userId1";
	String userId2 = "userId2";
	String tagId1 = "tagId1";
	String tagId2 = "tagId2";
	String dataId1 = "dataId1";
	String dataId2 = "dataId2";
	String dataId3 = "dataId3";
	String dataId4 = "dataId4";
	String dataId5 = "dataId5";
	String dataId6 = "dataId6";
	String dataId7 = "dataId7";
	String dataId8 = "dataId8";
	String dataId9 = "dataId9";
	String dataId10 = "dataId10";
	Date nowDate = new Date();
	FavoriteDataType dataType1 = FavoriteDataType.FILE;
	FavoriteDataType dataType2 = FavoriteDataType.IMAGE;

	@Test
	public void testGetFavoriteDataIdsByTagId() {
		// prepare data
		List dtos = this.prepareDataTagDtos();
		favoriteDataTagDao.batchSave(dtos);
		/// run test
		try {
			// test clip time desc order
			LazyLoadResult lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, null, 4,
					false);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(2));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(3));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(1));

			// test clip time desc order
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, null, 4, true);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(1));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(2));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(3));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1));
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataTagDao.batchDelete(dtos);
		}
	}

	@Test
	public void testGetFavoriteDataIdsByTagIdAndType() {
		// prepare data
		List dtos = this.prepareDataTagDtos();
		favoriteDataTagDao.batchSave(dtos);
		// run test
		try {
			// test clip time desc order
			LazyLoadResult lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					null, 2, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					lazyLoadResult.getLastLoadPos(), 3, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(1));

			// test clip time desc order
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1, null, 2, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(1));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					lazyLoadResult.getLastLoadPos(), 3, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1));
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataTagDao.batchDelete(dtos);
		}
	}

	private List prepareDataTagDtos() {
		FavoriteDataTagDto dataTagDto1 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId1)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime())).build();
		FavoriteDataTagDto dataTagDto2 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId2)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 1000)).build();
		FavoriteDataTagDto dataTagDto3 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId3)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 2000)).build();
		FavoriteDataTagDto dataTagDto4 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId4)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 3000)).build();
		FavoriteDataTagDto dataTagDto5 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId5)
				.dataType(dataType2).clipTime(String.valueOf(nowDate.getTime() - 4000)).build();
		FavoriteDataTagDto dataTagDto6 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId6)
				.dataType(dataType2).clipTime(String.valueOf(nowDate.getTime() - 5000)).build();
		FavoriteDataTagDto dataTagDto7 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId2).dataId(dataId7)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 6000)).build();
		FavoriteDataTagDto dataTagDto8 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId2).dataId(dataId8)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 7000)).build();
		FavoriteDataTagDto dataTagDto9 = FavoriteDataTagDto.builder().userId(userId2).tagId(tagId1).dataId(dataId9)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 8000)).build();
		FavoriteDataTagDto dataTagDto10 = FavoriteDataTagDto.builder().userId(userId2).tagId(tagId1).dataId(dataId10)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 9000)).build();
		return Arrays.asList(dataTagDto1, dataTagDto2, dataTagDto3, dataTagDto4, dataTagDto5, dataTagDto6, dataTagDto7,
				dataTagDto8, dataTagDto9, dataTagDto10);
	}
}
完整代码

GitHub - JessicaWin/dynamodb-in-action at dao-impl

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/325309.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号