A: 两张表示例
/**
*
* @author xiaofanku@live.cn
*/
@Entity
@Table(name="apo_config")
public class SiteConfig implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long ID;
private String caption;
@ElementCollection(fetch = FetchType.LAZY)
@MapKeyColumn(name="name")
@Column(name="value")
@CollectionTable(name="apo_config_attributes", joinColumns=@JoinColumn(name="ca_id"))
private Map<String, String> attributes = new HashMap<String, String>();
//GET/SET
}
测试代码
@Test
public void test(){
SiteConfig sc=new SiteConfig();
sc.setID(1L);
sc.setCaption("全局配置");
Map<String, String> data=new HashMap<>();
data.put("site", "csdn.net");
data.put("account", "xiaofanku");
sc.setAttributes(data);
siteConfigDao.save(sc);
}
@Test
public void getConfig(){
SiteConfig config=siteConfigDao.findOne(1L);
assertEquals(config.getAttributes().get("site"), "csdn.net");
}
apo_config:表结构
apo_config_attributes:表结构
B: 三张表示例
/**
*
* @author xiaofanku@live.cn
*/
@Entity
@Table(name="apo_config")
public class SiteConfig implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long ID;
private String caption;
@OneToMany(cascade=CascadeType.ALL, orphanRemoval = true)
@MapKey(name="name")
@JoinTable(name = "apo_config_attributes")
private Map<String, ConfigAttribute> attributes=new HashMap<>();
//GET/SET
}
/**
*
* @author xiaofanku@live.cn
*/
@Entity
@Table(name="apo_attributes")
public class ConfigAttribute implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long ID;
@Column(name="name")
private String name;
private String value;
//GET/SET
}
测试代码
@Test @Ignore
public void test(){
SiteConfig sc=new SiteConfig();
sc.setID(1L);
sc.setCaption("全局配置");
Map<String, ConfigAttribute> data=new HashMap<>();
ConfigAttribute ca1=new ConfigAttribute();
ca1.setName("site");ca1.setValue("csdn.net");
data.put("site", ca1);
ConfigAttribute ca2=new ConfigAttribute();
ca2.setName("account");ca2.setValue("xiaofanku");
data.put("account", ca2);
sc.setAttributes(data);
siteConfigDao.save(sc);
}
@Test @Ignore
public void getConfig(){
SiteConfig config=siteConfigDao.findOne(1L);
assertEquals(config.getAttributes().get("site").getValue(), "csdn.net");
}
apo_config:表结构
apo_attributes:表结构
apo_config_attributes:中间表结构
C: 使用ASF Commons BeanUtils来构造一个Dynamic Class
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.beanutils.BasicDynaClass;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
/**
* 使用Commons Beanutils实现动态类
* @author xiaofanku@live.cn
* @since 20171024
*/
public class DynamicClass{
private final DynaBean config;
/**
* 构造一个运态类型
* @param attributeMeta key属性名,value为属性名的类型,例:java.lang.Boolean
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
public DynamicClass(Map<String,String> attributeMeta) throws IllegalAccessException, InstantiationException, ClassNotFoundException{
DynaProperty[] props=covert(attributeMeta).toArray(new DynaProperty[]{});
BasicDynaClass dynaClass = new BasicDynaClass("CustomConfig", null, props);
this.config = dynaClass.newInstance();
}
/**
* 构造一个运态类型
* @param attributes
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public DynamicClass(Set<Attribute> attributes) throws ClassNotFoundException, IllegalAccessException, InstantiationException{
DynaProperty[] props=covert(attributes).toArray(new DynaProperty[]{});
BasicDynaClass dynaClass = new BasicDynaClass("CustomConfig", null, props);
this.config = dynaClass.newInstance();
load(attributes);
}
/**
* 获得属性值
* @param attributeName 属性名
* @return
*/
public Object getValue(String attributeName){
return config.get(attributeName);
}
/**
* 获得属性值
* @param attributeName 属性名
* @param classType 属性类型
* @param <T>
* @return
* @throws java.lang.ClassCastException
*/
public <T> T getValue(String attributeName, Class<T> classType) throws java.lang.ClassCastException{
return (T)getValue(attributeName);
}
/**
* 设置属性
* @param attributeName 属性名
* @param attributeValue 属性值
*/
public void setValue(String attributeName, String attributeValue){
DynaProperty dp = config.getDynaClass().getDynaProperty(attributeName);
config.set(attributeName, ConvertUtils.convert(attributeValue, dp.getType()));
}
/**
* 设置属性
* @param attribute 属性实例
* @throws ClassNotFoundException
*/
public void setValue(Attribute attribute) throws ClassNotFoundException {
config.set(attribute.getName(), ConvertUtils.convert(attribute.getValue(), Class.forName(attribute.getClassName())));
}
/**
* 装载属性集合,填充动态类实例
* @param attributes
*/
private void load(Set<Attribute> attributes){
for(Attribute attr : attributes){
try{
config.set(attr.getName(), ConvertUtils.convert(attr.getValue(), Class.forName(attr.getClassName())));
}catch(ClassNotFoundException e){
}
}
}
/**
* 返回一个DynaProperty列表
* @param attributes
* @return
* @throws ClassNotFoundException
*/
private List<DynaProperty> covert(Set<Attribute> attributes) throws ClassNotFoundException{
List<DynaProperty> attres=new ArrayList<>();
for(Attribute attr : attributes){
attres.add(new DynaProperty(attr.getName(), Class.forName(attr.getClassName())));
}
return attres;
}
/**
* 返回一个DynaProperty列表
* @param attributeMeta key属性名,value为属性名的类型,例:java.lang.Boolean
* @return
* @throws ClassNotFoundException
*/
private List<DynaProperty> covert(Map<String,String> attributeMeta) throws ClassNotFoundException{
List<DynaProperty> properties=new ArrayList<>();
Set<String> attrSet=attributeMeta.keySet();
for(String attrName : attrSet){
String className=attributeMeta.get(attrName);
properties.add(new DynaProperty(attrName, Class.forName(className)));
}
return properties;
}
public static enum Type{
BOOLEAN("java.lang.Boolean"),
INTEGER("java.lang.Integer"),
LONG("java.lang.Long"),
STRING("java.lang.String"),
CHAR("java.lang.Character"),
DOUBLE("java.lang.Double"),
FLOAT("java.lang.Float");
private final String name;
private Type(String className){
this.name=className;
}
public String getName() {
return name;
}
}
public static class Attribute{
//属性名,例:show
private final String name;
//属性名的值,例:"true"
private final String value;
//属性名的类型,例:java.lang.Boolean
private final String className;
public Attribute(String name, String value, String className) {
this.name = name;
this.value = value;
this.className = className;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public String getClassName() {
return className;
}
@Override
public int hashCode() {
int hash = 5;
hash = 97 * hash + Objects.hashCode(this.name);
hash = 97 * hash + Objects.hashCode(this.className);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Attribute other = (Attribute) obj;
if (!Objects.equals(this.name, other.name)) {
return false;
}
if (!Objects.equals(this.className, other.className)) {
return false;
}
return true;
}
}
}
测试代码:
@Test
public void test(){
Set<Attribute> sas=new HashSet<>();
sas.add(new Attribute("logo", "logo.png", DynamicClass.Type.STRING.getName()));
sas.add(new Attribute("pageSize", "50", DynamicClass.Type.INTEGER.getName()));
sas.add(new Attribute("shortcut", "true", DynamicClass.Type.BOOLEAN.getName()));
try{
DynamicClass dc=new DynamicClass(sas);
Integer ps = dc.getValue("pageSize", Integer.class);
System.out.println(ps);
dc.setValue("pageSize", "150");
System.out.println(dc.getValue("pageSize"));
}catch(Exception e){
e.printStackTrace();
}
}
@Test @Ignore
public void base() {
Map<String, String> am = new HashMap<>();
am.put("logo", DynamicClass.Type.STRING.getName());
am.put("pageSize", DynamicClass.Type.INTEGER.getName());
am.put("shortcut", DynamicClass.Type.BOOLEAN.getName());
try {
DynamicClass dc = new DynamicClass(am);
dc.setValue("pageSize", "150");
System.out.println(dc.getValue("pageSize"));
dc.setValue(new Attribute("shortcut", "true", DynamicClass.Type.BOOLEAN.getName()));
System.out.println(dc.getValue("shortcut"));
} catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
最后说明:
JPA 2.1 实现 EclipseLink 2.5.2
JDK 1.8.x
Mysql 5.5.x
ASF Commons BeanUtils 1.8.3