【发布时间】:2014-06-07 13:08:50
【问题描述】:
我正在寻找一种方便的方式来为我的应用程序提供初始数据。目前我已经实现了一个基于 Spring Data JPA 的项目,这是我所有数据库相关操作的基础。
例子:
我有一个实体Role,它可以分配给实体User。在一个干净的应用程序启动时,我想直接提供一些默认角色(例如管理员、经理等)。
最好的
【问题讨论】:
标签: spring jpa spring-data
我正在寻找一种方便的方式来为我的应用程序提供初始数据。目前我已经实现了一个基于 Spring Data JPA 的项目,这是我所有数据库相关操作的基础。
例子:
我有一个实体Role,它可以分配给实体User。在一个干净的应用程序启动时,我想直接提供一些默认角色(例如管理员、经理等)。
最好的
【问题讨论】:
标签: spring jpa spring-data
我建立了一个随机数据工厂:
public class RandomDataFactory {
private static final String UNGENERATED_VALUE_MARKER = "UNGENERATED_VALUE_MARKER";
private static void randomlyPopulateFields(Object object) {
new RandomValueFieldPopulator().populate(object);
}
/**
* Instantiates a single object with random data
*/
public static <T> T getSingle(Class<T> clazz) throws IllegalAccessException, InstantiationException {
T object = clazz.newInstance();
randomlyPopulateFields(object);
return object;
}
/**
* Returns an unmodifiable list of specified type objects with random data
*
* @param clazz the myPojo.class to be instantiated with random data
* @param maxLength the length of list to be returned
*/
public static <T> List<T> getList(Class<T> clazz, int maxLength) throws IllegalAccessException, InstantiationException {
List<T> list = new ArrayList<T>(maxLength);
for (int i = 0; i < maxLength; i++) {
T object = clazz.newInstance();
randomlyPopulateFields(object);
list.add(i, object);
}
return Collections.unmodifiableList(list);
}
/**
* Returns a unmodifiable list of specified type T objects with random data
* <p>List length will be 3</p>
*
* @param clazz the myPojo.class to be instantiated with random data
*/
public static <T> List<T> getList(Class<T> clazz) throws InstantiationException, IllegalAccessException {
return getList(clazz, 3);
}
public static <T> T getPrimitive(Class<T> clazz) {
return (T) RandomValueFieldPopulator.generateRandomValue(clazz);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz) {
return getPrimitiveList(clazz, 3);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz, int length) {
List<T> randoms = new ArrayList<T>(length);
for (int i = 0; i < length; i++) {
randoms.add(getPrimitive(clazz));
}
return randoms;
}
private static class RandomValueFieldPopulator {
public static Object generateRandomValue(Class<?> fieldType) {
Random random = new Random();
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis() - random.nextInt());
} else if (LocalDate.class.isAssignableFrom(fieldType)) {
Date date = new Date(System.currentTimeMillis() - random.nextInt());
return new LocalDate(date);
} else if (fieldType.equals(Character.class) || fieldType.equals(Character.TYPE)) {
return (char) (random.nextInt(26) + 'a');
} else if (fieldType.equals(Integer.TYPE) || fieldType.equals(Integer.class)) {
return random.nextInt();
} else if (fieldType.equals(Short.TYPE) || fieldType.equals(Short.class)) {
return (short) random.nextInt();
} else if (fieldType.equals(Long.TYPE) || fieldType.equals(Long.class)) {
return random.nextLong();
} else if (fieldType.equals(Float.TYPE) || fieldType.equals(Float.class)) {
return random.nextFloat();
} else if (fieldType.equals(Double.TYPE)) {
return random.nextInt(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Double.class)) {
return random.nextDouble(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Boolean.TYPE) || fieldType.equals(Boolean.class)) {
return random.nextBoolean();
} else if (fieldType.equals(BigDecimal.class)) {
return new BigDecimal(random.nextFloat());
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else {
return UNGENERATED_VALUE_MARKER;
}
public void populate(Object object) {
ReflectionUtils.doWithFields(object.getClass(), new RandomValueFieldSetterCallback(object));
}
private static class RandomValueFieldSetterCallback implements ReflectionUtils.FieldCallback {
private final Object targetObject;
public RandomValueFieldSetterCallback(Object targetObject) {
this.targetObject = targetObject;
}
@Override
public void doWith(Field field) throws IllegalAccessException {
Class<?> fieldType = field.getType();
if (!Modifier.isFinal(field.getModifiers())) {
Object value = generateRandomValue(fieldType);
if (!value.equals(UNGENERATED_VALUE_MARKER)) {
ReflectionUtils.makeAccessible(field);
field.set(targetObject, value);
}
}
}
}
}
}
【讨论】:
查看内存中的 H2 数据库。
http://www.h2database.com/html/main.html
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.178</version>
</dependency>
@Bean
public DataSource dataSource() {
System.out.println("**** USING H2 DATABASE ****");
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
您可以使用 .addscript() 在上述代码中使用 SQL 脚本创建/加载 H2 数据库。
【讨论】:
如果你将它用于单元测试,并且需要不同的状态来进行不同的测试,那么
专门针对 Spring 有 http://springtestdbunit.github.io/spring-test-dbunit/
如果您只需要初始化一次并使用 EmbeddedDatabaseBuilder 进行测试,那么正如 Brandon 所说,您可以使用 EmbeddedDatabaseBuilder。
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
如果你希望它在应用程序启动时被初始化,你可以在你的配置bean中添加@PostConstruct函数,它会在配置bean创建后被初始化。
@PostConstruct
public void initializeDB() {
}
【讨论】: