Weforward Data 项目提供一套存储的API,方便编程使用,目前主要有persister,search,array,counter,log几个模块。
1.定义一个 di(dependency interface)和它的实现类
public interface OrderDi extends BusinessDi {
}
public class OrderImpl implements OrderDi {
protected PersisterFactory m_Factory;
public OrderImpl(PersisterFactory factory) {
m_Factory = factory;
}
@Override
public <E extends Persistent> Persister<E> getPersister(Class<E> clazz) {
return m_Factory.getPersister(clazz);
}
}
Tip
|
di需要继承BusinessDi接口 |
2.定义业务对象
public class Order extends AbstractPersistent<OrderDi> {
@Resource
protected int m_Amount;
protected Order(OrderDi di) {
super(di);//反射对象用的不能删除
}
public Order(OrderDi di, int amount) {
super(di);//创建对象的方法
genPersistenceId();// 生成id
}
public void submit() {
// TODO
markPersistenceUpdate();//标记保存对象
}
}
3.定义服务并创建持久器
public class OrderService extends OrderDiImpl {
protected Persister<Order> m_PsOrder;
public OrderService(PersisterFactory factory) {
super(factory);
m_PsOrder = factory.createPersister(Order.class, this);
}
public Order getOrder(String id) {
return m_PsOrder.get(id);
}
public Order createOrder(int amount) {
return new Order(this, amount);
}
}
Tip
|
Data模块没有PersisterFactory的具体实现,需参考Weforward Data Mongodb实现 |
4.条件搜索
Persister提供一定的条件搜索支撑
单一比较的条件
//相等
ps.search(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"));
//不相等
ps.search(ConditionUtil.ne(ConditionUtil.field("name"), "HelloWorld"));
//小于
ps.search(ConditionUtil.lt(ConditionUtil.field("date"), "20200808"));
//大于
ps.search(ConditionUtil.gt(ConditionUtil.field("date"), "20200808"));
//小于等于
ps.search(ConditionUtil.lte(ConditionUtil.field("date"), "20200808"));
//大于等于
ps.search(ConditionUtil.gte(ConditionUtil.field("date"), "20200808"));
范围查询条件
ps.search(ConditionUtil.range(ConditionUtil.field("name"), "20200808", "202008089"));
与条件查询(全匹配)
ps.search(ConditionUtil.and(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"),
ConditionUtil.eq(ConditionUtil.field("name"), "20200808")));
或条件查询(有一个匹配)
ps.search(ConditionUtil.or(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"),
ConditionUtil.eq(ConditionUtil.field("name"), "20200808")));
上面举例的属性者是持久类的基本属性的查询,有一种情况,我们需要根据持久类的属性对象(如VO类)里面的属性查询,这时的处理如下
public class Order extends AbstractPersistent<OrderDi> {
@Resource
protected Vo m_Vo;
protected Order(OrderDi di) {
super(di);//反射对象用的不能删除
}
}
public class Vo {
@Resource
protected String m_Name;
}
ps.search(ConditionUtil.eq(ConditionUtil.field("m_Vo","m_Name"), "HelloWorld"));
5.建立索引
条件搜索理论上支持持久类的所有属性,但是直接按这些属性条件搜索可以效率会比较低,所以我们需要对经常用来查询的属性建立索引
public class Order extends AbstractPersistent<OrderDi> {
@Resource
protected Vo m_Vo;
protected Order(OrderDi di) {
super(di);//反射对象用的不能删除
}
}
public class Vo {
@Index //标记索引
@Resource
protected String m_Name;
}
有一点需要注意的是索引只会自己建议,不会自己删除,如在A上加个索引@Index,之后又将A的索引@Index去掉,些时需要人工登陆数据库将对应索引删除。
6.排序
条件查询的同时,指定排序
// 正序
ps.search(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"), OrderByUtil.asc("age"));
// 倒序
ps.search(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"), OrderByUtil.desc("age"));
// 混合
ps.search(ConditionUtil.eq(ConditionUtil.field("name"), "HelloWorld"),
OrderByUtil.unite(Arrays.asList("age"), Arrays.asList("date")));
1.通过工厂创建搜索器
Searcher searcher = m_Factory.createSearcher("order_doc");
Tip
|
Data模块没有SearchFactory的具体实现,需参考 Weforward Data Mongodb实现 |
2.创建索引
List<? extends IndexKeyword> keywords = new ArrayList<>();
keywords.add(IndexKeywordHelper.newKeyword("小额"));
keywords.add(IndexKeywordHelper.newKeyword("汽车");
keywords.add(IndexKeywordHelper.newKeyword("D:20200524"));
searcher.updateElement(IndexElementHelper.newElement("Order$123"), keywords);
3.单关键字匹配
searcher.search(null, "汽车");
4.多关键字匹配
searcher.search(null, "小额", "汽车");// 与关系
5.任意关键字匹配
searcher.union(null, "小额", "汽车");// 或关系
6.范围匹配
searcher.searchRange("D:20200524", "D:202005249", null);// 加上属性前端(如D:)后可精确匹配到属性
7.匹配率排序
//updateElement时指定匹配率
searcher.updateElement(IndexElementHelper.newElement(UniteId.valueOf("Order$1")),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的", 1)));
searcher.updateElement(IndexElementHelper.newElement(UniteId.valueOf("Order$2")),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的", 2)));
IndexResults irs = searcher.search(SearchOption.valueOf(SearchOption.OPTION_RATE_SORT), "我们的");
//结果为order2,order1的顺序
for (IndexResult ir : ResultPageHelper.toForeach(irs)) {
System.out.println(ir.getKey());
}
8.匹配率过滤
//updateElement时指定匹配率
searcher.updateElement(IndexElementHelper.newElement(UniteId.valueOf("Order$1")),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的", 1)));
searcher.updateElement(IndexElementHelper.newElement(UniteId.valueOf("Order$2")),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的", 2)));
searcher.updateElement(IndexElementHelper.newElement(UniteId.valueOf("Order$3")),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的", 3)));
//通过OPTION_RATE_LEAST指定至少匹配
IndexResults irs = searcher.search(SearchOption.valueOf(SearchOption.OPTION_RATE_LEAST).setRate(2), "我们的");
// 结果为order2,order3
for (IndexResult ir : ResultPageHelper.toForeach(irs)) {
System.out.println( ir.getKey());
}
也可按范围过滤
IndexResults irs = searcher.search(SearchOption.valueOf(SearchOption.OPTION_RATE_RANGE).setStartRate(1).setEndRate(2), "我们的");
// 结果为order1,order2
for (IndexResult ir : ResultPageHelper.toForeach(irs)) {
System.out.println( ir.getKey());
}
9.按属性排序
//updataElement时指定属性
searcher.updateElement(
IndexElementHelper.newElement(UniteId.valueOf("Order$1"),
Arrays.asList(IndexAttributeHelper.newAttribute("level", "1"))),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的")));
searcher.updateElement(
IndexElementHelper.newElement(UniteId.valueOf("Order$2"),
Arrays.asList(IndexAttributeHelper.newAttribute("level", "2"))),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的")));
searcher.updateElement(
IndexElementHelper.newElement(UniteId.valueOf("Order$3"),
Arrays.asList(IndexAttributeHelper.newAttribute("level", "3"))),
Arrays.asList(IndexKeywordHelper.newKeyword("我们的")));
IndexResults irs = searcher.search(null, "我们的");
irs.sort("level", IndexResults.OPTION_ORDER_BY_DESC);
// 结果为order3,order2,order1的顺序
for (IndexResult ir : ResultPageHelper.toForeach(irs)) {
System.out.println("场景7:" + ir.getKey());
}
1.实现LabelElement
public class MyLabel implements LabelElement {
@Resource
protected String m_Id;
@Resource
protected String m_Name;
protected MyLabel() {
// 反射使用
}
public MyLabel(String id, String name) {
m_Id = id;
m_Name = name;
}
@Override
public String getIdForLabel() {
return m_Id;
}
}
2.通过工厂创建标签集合
LabelSet<MyLabel> myLabel = m_Factory.createLabelSet("mylabel", FieldMapper.valueOf(MyLabel.class));
Tip
|
Data模块没有LabelSetFactory的具体实现,需参考 Weforward Data Mongodb实现 |
3.保存标签
String label = "one";
MyLabel l = new MyLabel("123", "HelloWorld!");
myLabel.put(label, l);
label = "two";
l = new MyLabel("231", "HelloWorld!");
myLabel.put(label, l);
4.获取标签
MyLabel l= myLabel.get("one", "123");
1.通过工厂创建计数器
/** x00ff为服务器的标识,无固定格式,保证每一台服务器唯一即可*/
LabelCounterFactory factory = new LabelCounterFactory(labelSetFactory, "x00ff");
Counter counter = factory.createCounter("order");
Tip
|
Data模块指定依赖LabelSetFactory的CounterFactory实现,如果有需要也可自行实现一个CounterFactory |
2.计数
counter.inc("Order$123");
3.获取值
counter.get("Order$123");
数据存储通过ObjectMapper实现对象对存储数据的转换,除了自己实现一个ObjectMapper的方式,Weforward Data还提供了两种自动映射方式
实现类为FieldMapper
1.使用规则
属性映射通过在类属性增加@Resource或@ResourceExt注释需要转换保存数据
Tip
|
基础类型使用@Resource即可,@ResourceExt用于集合等特殊类型,具体参考 支持数据类型 说明 |
默认情况下只解析当前类的属性,如果需要保存父类属性,需要有当前类加上@Inherited
2.指定方式
persister
继承了AbstractPersisterFactory类的PersisterFactory实现默认使用属性映射 也可通过setMapperType("field")强制指定
array
通过在创建LabelSetHub时指定
m_Factory.createLabelSet("mylabel", FieldMapper.valueOf(MyLabel.class));
实现类为MethodMapper
1.使用规则
方法映射通过解析类的get和set方法映射,默认解析所有get和set方法(包括父类getClass()除外)
如果不想映射指定方法,可使用@Transient注释方法
-
get方法标准:非静态,方法可见性public,返回类型不为void,没有入参。如:public String getName()
-
set方法标准:非静态,方法可见性public,返回类型为void,有且只有一个入参。如:public void setName(String name)
另外方法同样可以使用@Resource和@Resource注解,具体参考 支持数据类型 说明
2.指定方式
persister
继承了AbstractPersisterFactory类可通过setMapperType("method")指定
array
通过在创建LabelSetHub时指定
m_Factory.createLabelSet("mylabel", MethodMapper.valueOf(MyLabel.class));
类型 |
默认值 |
byte |
0 |
short |
0 |
int |
0 |
long |
0 |
float |
0 |
double |
0 |
boolean |
false |
Byte |
null |
Short |
null |
Integer |
null |
Long |
null |
Float |
null |
Double |
null |
Boolean |
null |
String |
null |
java.math.BigInteger |
null |
java.math.BigDecimal |
null |
-
属性映射方式下,使用@Resource注解即可
-
方法映射方式下,不需要注解
属性或方法的类型可以为以下类
-
java.util.Collection
-
java.util.AbstractCollection
-
java.util.List
-
java.util.AbstractList
-
java.util.ArrayList
-
java.util.set
-
java.util.AbstractList
-
java.util.HashSet
Collection、AbstractCollection、List与AbstractList反射后的实现类为ArrayList
Set与AbstractSet反射后的实现类为HashSet
当元素是基础类型或者VO
-
属性映射方式下,使用@ResourceExt(component = xxx.class)指定元素类型
-
方法映射方式下,不需要注解
当元素的集合又是一个集合时,不管是哪种映射方式,都需要使用ResourceExt注解,并且指定@ResourceExt(components ={ component1.class,component2.class … componentx.class })
如:
@ResourceExt(components = { List.class, String.class })
public List<List<String>> myListList;
@ResourceExt(components = { List.class, String.class })
public List<List<String>> getMyListList()
属性或方法的类型可以为以下类
-
java.util.Map
-
java.util.AbstractMap
-
java.util.HashMap
-
java.util.ConcurrentMap
-
java.util.ConcurrentHashMap
Map、AbstractMap反射后的实现类为HashMap
ConcurrentMap反射后的实现类为ConcurrentHashMap
当Map的Key和Value都基础类型或者VO
-
属性映射方式下,使用@ResourceExt(components ={ key.class,value.class})指定元素类型
-
方法映射方式下,使用@ResourceExt(components ={ key.class,value.class})指定元素类型
当Value为集合时,可在components 指定下级组件类型。 如:
@ResourceExt(components = { String.class, List.class, Date.class })
public Map<String, List<Date>> myMapList;
@ResourceExt(components = { String.class, List.class, Date.class })
public Map<String, List<Date>> getMyMapList()
Important
|
key只能是基础类型或VO |
有时候我们为了编程方便定义了一些封装对象,但保存数据时又只需要保存简单的数据类型。 这种时间就适合使用自动拆装箱机制。
Important
|
属性映射和方法映射启动自动拆装箱机制相同 |
要启动自动拆装箱机制非常容易,只需要在@Resource或@ResourceExt注解时同时指定type即可
如:
@Resource(type = String.class)
public UniteId myId;
@Resource(type = String.class)
public UniteId getMyId()
-
拆箱规则:调用源对象的XXXValue方法转换成目标对象,如上面代码会调用 myId.stringValue()方法
-
装箱规则:调用目标对象的valueOf(xxx)静态方法生成目标对象 ,如上面代码会调用 UniteId.valueOf(String value)方法