-
Notifications
You must be signed in to change notification settings - Fork 0
exitsoft orm 基于spring data jpa 持久化使用说明
exitsoft orm 是对持久化层所使用到的框架进行封装,exitsof orm目前支持Hibernate4和spring data jpa,至于spring data jpa 是如何使用的可以参考:官方首页的文档的文档,或者参考IBM的文章:使用Spring Data JPA简化JPA开发,本文介绍exitsoft orm对spring data jpa的扩展,和在一起是怎么使用.
对于exitsoft orm对spring data jpa的扩展有:
- 添加了一个BasicJpaRepository<T,D> 接口该接口继承了JpaRepository<T,D>, JpaSpecificationExecutor<T,D>,目的是为了通过继承该接口.可以直接通过propertyFilter的查询
- 对BasicJpaRepository<T,D>做了实现类JpaSupportRepository<T,D>,该类是继承自SimpleJpaRepository的扩展类.
- 在JpaSupportRepository<T,D>类中添加了状态删除以及,转码功能.
BasicJpaRepository<T,D>只要的扩展方法有.对PropertyFilter的查询和表达式的查询(具体表达式和PropertyFilter和Hibernate是一样使用的),可以参考:exitsoft orm 基于 Hibernate 4 持久化使用说明.的表达式章节.
要使用到BasicJpaRepository<T,D>需要在spring data jpa配置文件中对jpa:repositories的factory-class属性添加一个类:org.exitsoft.orm.core.spring.data.jpa.factory.BasicRepositoryFactoryBean:
<jpa:repositories base-package="你的repository包路径"
transaction-manager-ref="transactionManager"
factory-class="org.exitsoft.orm.core.spring.data.jpa.factory.BasicRepositoryFactoryBean"
entity-manager-factory-ref="entityManagerFactory" />
因为BasicJpaRepository<T,D>的实现类是JpaSupportRepository<T,D>,所以要把spring data jpa默认使用的:SimpleJpaRepository<T,D>替换为:JpaSupportRepository<T,D>类,BasicRepositoryFactoryBean就是做了这个替换工作.
当配置好spring data jpa配置文件之后,BasicJpaRepository<T,D>就可以使用了.
现在有一个实体:
@Entity
@Table(name="TB_DATA_DICTIONARY")
public class DataDictionary extends UniversallyUniqueIdentifier{
//名称
private String name;
//值
private String value;
//类型
private String type = "S";
//备注
private String remark;
//所属类别
public DictionaryCategory category;
//五笔编码
private String wubiCode;
//拼音编码
private String pinYinCode;
//状态,1:启用,2:禁用,3:删除
private Integer state;
//----------GETTER/SETTER-----------//
}
通过该实体的描述的数据访问为:
public interface DataDictionaryDao extends BasicJpaRepository<DataDictionary, String> {
}
对于CURD的基本操作都和原有的spring data jpa提供的方法一样使用,该方法的实现类都是来源与SimpleJpaRepository<T,D>,而BasicJpaRepository<T,D>主要扩展的是查询方法:
DataDictionary entity = new DataDictionary();
dd.setName("test");
dd.setValue("01")
//dd.set...
//保存
dataDictionaryDao.save(entity);
//删除
//dataDictionaryDao.delete(entity);
List<PropertyFilter> filters = Lists.newArrayList(
PropertyFilters.build("EQI_id", "1234567"),
);
dictionaryCategoryDao.findAll(filters);
//sql:select from TB_DATA_DICTIONARY where id = ?;
List<PropertyFilter> filters = Lists.newArrayList(
PropertyFilters.build("EQI_id", "1234567"),
);
dictionaryCategoryDao.findAll(filters);
//sql:select from TB_DATA_DICTIONARY where state <> ?;
List<PropertyFilter> filters = Lists.newArrayList(
PropertyFilters.build("LIKES_name", "t"),
PropertyFilters.build("NEI_state", "3")
);
//---------------------多条件查询---------------------//
dictionaryCategoryDao.findAll(filters);
//sql:select from TB_DATA_DICTIONARY where state <> ? and name like ?;
//---------------------分页查询---------------------//
Pageable pageable = new PageRequest(0, 10);
Page<DataDictionary> page = dictionaryCategoryDao.findAll(pageable,filters);
####状态删除@StateDelete注解
在大部分的业务系统中有某些表对于delete操作都有这么一个需求,就是不物理删除,只做状态删除。BasicJpaRepository<T,D>提供了这种功能。只要在实体类加上@StateDelete注解后调用delete方法,将会改变实体的某个字段做已删除的状态值。
@Entity
@Table(name="TB_DATA_DICTIONARY")
@StateDelete(propertyName = "state", value = "3")
public class DataDictionary extends UniversallyUniqueIdentifier{
//名称
private String name;
//值
private String value;
//类型
private String type = "S";
//备注
private String remark;
//所属类别
public DictionaryCategory category;
//五笔编码
private String wubiCode;
//拼音编码
private String pinYinCode;
//状态,1:启用,2:禁用,3:删除
private Integer state;
//----------GETTER/SETTER-----------//
}
public interface DataDictionaryDao extends BasicJpaRepository<DataDictionary, String> {
}
dataDictionaryDao.delete(entity);
//sql:update TB_DATA_DICTIONARY set state = ? where id = ?
如果要用到这个功能,记得把org.exitsoft.orm.core.spring.data.jpa.factory.BasicRepositoryFactoryBean类配置到jpa:repositories标签的factory-class属性中
@StateDelete属性说明:
属性名称 | 属性类型 | 描述 |
---|---|---|
propertyName | java.lang.String | 当delete时对实体的哪个属性值改变为删除后的状态值 |
value | java.lang.String | 当delete时要改变的值是什么,如:@StateDelete(propertyName = "state", value = "3")表示要改变的值为3 |
type | org.exitsoft.orm.core.PropertyType | 该属性表示propertyName的值类型是什么,有时候,状态值不一定是Integer类型,很有可能是其他类型,可以根据org.exitsoft.orm.core.PropertyType类指定值是什么 |
####字段转码@ConvertCode注解
在业务系统中,有时候会有这么一个业务需求,当保存某个对象的时候,将某个对象字段值转换成某个值,并赋值给某个属性在保存。比如一个字典类,当我保存时把name的值转换为五笔与拼音值后在保存该对象,这种需求可以解决用户在页面不管用户输入的是中文、英文、中文拼音、中文的五笔,都可以通过这种方式去查询出结果:
SELECT * FROM TB_DATA_DICTIONARY WHERE NAME LINKE '?%' OR WUBICODE LINKE '?%' OR PINYINCODE LINKE '?%'
那么现在有一个实体,当保存时候我要把name的值转换为五笔和拼音在赋值给pinyinCode wubiCode字段的话,可以写成这样:
@Entity
@Table(name="TB_DATA_DICTIONARY")
@ConvertCode(
convertPropertys={
@ConvertProperty(propertyNames={"wubiCode","pinYinCode"},
strategyClass=PinYinWuBiConvertStrategy.class)
},
fromProperty="name",
executeMehtod=ExecuteMehtod.Save
)
public class DataDictionary extends UniversallyUniqueIdentifier{
//名称
private String name;
//值
private String value;
//类型
private String type = "S";
//备注
private String remark;
//所属类别
public DictionaryCategory category;
//五笔编码
private String wubiCode;
//拼音编码
private String pinYinCode;
//状态,1:启用,2:禁用,3:删除
private Integer state;
//----------GETTER/SETTER-----------//
}
/**
* 拼音五笔转码策略
*
* @author vincent
*
*/
public class PinYinWuBiConvertStrategy implements CodeStrategy{
public Object convertCode(Object value,String propertyName) {
if (value == null) {
return "";
}
if (propertyName.equals("wubiCode")) {
return value.toString() + "的五笔";
} else {
return value.toString() + "的拼音";
}
}
}
public interface DataDictionaryDao extends BasicJpaRepository<DataDictionary, String> {
}
DataDictionary dd = new DataDictionary();
dd.setName("value");
dataDictionaryDao.save(dd);
调用save方法时,会先将实体DataDictionary的wubiCode赋值为"value的五笔"、pinYinCode赋值为"value的拼音"后在调用dataDictionaryDao自己本身的save方法。但要记得,使用@ConvertCode需要把org.exitsoft.orm.core.spring.data.jpa.factory.BasicRepositoryFactoryBean类配置到jpa:repositories标签的factory-class属性中.
@ConvertCode属性说明:
属性名称 | 属性类型 | 描述 |
---|---|---|
fromProperty | java.lang.String | 要转码的字段名,意思是根据哪个字段来转换值,如DataDictionary类就拿name作为转换值 |
convertPropertys | org.exitsoft.orm.strategy.annotation.ConvertProperty[] | 需要转码的字段注解,@ConvertProperty会在下面说明 |
executeMehtod | org.exitsoft.orm.enumeration.ExecuteMehtod |
需要在执行什么方法时做转码工作,ExecuteMehtod是个枚举
public enum ExecuteMehtod { Insert,//在插入时 Update,//在更新时 Save;//在保存时(插入或更新时) } |
@ConvertProperty属性说明:
属性名称 | 属性类型 | 描述 |
---|---|---|
propertyNames | java.lang.String[] | 被转码的字段名,意思是要在类中用那个字段来转码,如DataDictionary类就拿wubiCode和pinyinCode来转码 |
strategyClass | java.lang.Class | 转码策略实现类,CodeStrategy接口实体类,CodeStrategy接口会在下面说明 |
该接口是专门的转码策略接口,该接口需要实现一个方法public Object convertCode(Object value,String propertyName),在转码过程中通过该方法的返回值赋值到被转码的字段中,该方法的调用次数取决与,@ConvertProperty的propertyNames数组,如果propertyNames存在两个值,那么就调用两次,如DataDictionary配置了
@ConvertCode(
convertPropertys={
@ConvertProperty(propertyNames={"wubiCode","pinYinCode"},
strategyClass=PinYinWuBiConvertStrategy.class)
},
fromProperty="name",
executeMehtod=ExecuteMehtod.Save
)
那么public Object convertCode(Object value,String propertyName)在调用BasicHibernateDao的save方法时就会执行两次,如果DataDictionary的name值等于"dd"那么会调用convertCode("dd","pinyinCode")一次,convertCode("dd","wubiCode")一次。 CodeStrategy源码如下:
public interface CodeStrategy {
/**
* 通过该方法将 orm 对象的值和属性名传入进行转码
*
* @param value 值
* @param propertyName 被转码的属性名称
*/
public Object convertCode(Object value,String propertyName);
}
###对spring data jpa的PageableArgumentResolver的改动. 在使用PageableArgumentResolver做spring mvc的Pageable绑定时,发现一个问题.当我传入页数为1的时候.PageableArgumentResolver有那么一段话:
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
if (methodParameter.getParameterType().equals(Pageable.class)) {
assertPageableUniqueness(methodParameter);
Pageable request = getDefaultFromAnnotationOrFallback(methodParameter);
ServletRequest servletRequest = (ServletRequest) webRequest.getNativeRequest();
PropertyValues propertyValues = new ServletRequestParameterPropertyValues(servletRequest,
getPrefix(methodParameter), separator);
DataBinder binder = new ServletRequestDataBinder(request);
binder.initDirectFieldAccess();
binder.registerCustomEditor(Sort.class, new SortPropertyEditor("sort.dir", propertyValues));
binder.bind(propertyValues);
if (request.getPageNumber() > 0) {
request = new PageRequest(request.getPageNumber() - 1, request.getPageSize(), request.getSort());
}
return request;
}
return UNRESOLVED;
}
if (request.getPageNumber() > 0) {
request = new PageRequest(request.getPageNumber() - 1, request.getPageSize(), request.getSort());
}
当我传入页数为1的数字时.Pageable的number将会永远都是0,而在下面有一段话.
private static Pageable getDefaultPageRequestFrom(PageableDefaults defaults) {
// +1 is because we substract 1 later(加1,因为我们会减一)
int defaultPageNumber = defaults.pageNumber() + 1;
int defaultPageSize = defaults.value();
if (defaults.sort().length == 0) {
return new PageRequest(defaultPageNumber, defaultPageSize);
}
return new PageRequest(defaultPageNumber, defaultPageSize, defaults.sortDir(), defaults.sort());
}
至于为什么要加1又减1,这个问题.我还不明白spring为什么要这样做.为了避免我能够传入页数为1的分页.对于该类做了扩展.就把他的加1,减1,去掉.在spring mvc配置文件中配置即可:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.exitsoft.orm.core.spring.data.web.PageableArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
###spring data jpa的Specification<T>的扩展
对于以上两个功能(状态删除和转码),如果不需要使用时候就不需要配置jpa:repositories标签的factory-class属性,当去掉该属性后,其实一样也能够使用PropertyFilter进行查询和分页操作.
spring data jpa对于动态查询提供了一个非常规范的接口:Specification<T>,主要实现他的toPredicate方法就能够自定义你的查询语句.对于PropertyFilter和直接用属性名查询,exitsoft orm提供了两个实现类:PropertySpecification,PropertyFilterSpecification.如:
@Entity
@Table(name="TB_DATA_DICTIONARY")
public class DataDictionary extends UniversallyUniqueIdentifier{
//名称
private String name;
//值
private String value;
//类型
private String type = "S";
//备注
private String remark;
//所属类别
public DictionaryCategory category;
//五笔编码
private String wubiCode;
//拼音编码
private String pinYinCode;
//状态,1:启用,2:禁用,3:删除
private Integer state;
//----------GETTER/SETTER-----------//
}
//注意,继承的是JpaRepository和JpaSpecificationExecutor
public interface DataDictionaryDao extends JpaRepository<DataDictionary, String>, JpaSpecificationExecutor<DataDictionary> {
}
//通过属性名查询
dataDictionaryDao.findAll(Specifications.get("name","test"));
//通过属性名查询,但使用条件约束
dataDictionaryDao.findAll(Specifications.get("state","3",restrictionNames.NE));
//通过表达式查询
dataDictionaryDao.findAll(Specifications.get("EQS_name","test"));
//通过表达式查询
dataDictionaryDao.findAll(Specifications.get("NEI_state","3"));
List<PropertyFilter> filters = Lists.newArrayList(
PropertyFilters.build("LIKES_name", "t"),
PropertyFilters.build("NEI_state", "3")
);
//多条件查询
dictionaryCategoryDao.findAll(Specifications.get(filters));
//sql:select from TB_DATA_DICTIONARY where state <> ? and name like ?;
//分页查询
Pageable pageable = new PageRequest(0, 10);
Specification<DataDictionary> s = Specifications.get(filters);
Page<DataDictionary> page = dictionaryCategoryDao.findAll(pageable,s);
###扩展表达式的约束名称
在封装过程中,本人对一些常用的约束名称已经写好。如果你在项目开发时觉得表达式里面的约束名称不够用,可以对表达式做扩展处理。扩展约束名称主要关注这几个类:
- JpaRestrictionBuilder
- PredicateBuilder
- PredicateSingleValueSupport
- PredicateMultipleValueSupport
在PropertySpecification和PropertyFilterSpecification中,toPredicate方法首先会创建一个SpecificationModel类,该类只要的目的是将Root root, CriteriaQuery query,CriteriaBuilder builder,3个对象封装起来,成为一个载体,在调用JpaRestrictionBuilder的getRestriction方法时将该载体传入到PredicateBuilder接口中.
####PredicateBuilder接口
PredicateBuilder是一个构造Jpa Predicate的类,该类有一个方法是专门提供根据PropertyFilter是如何创建Predicate的:
/**
*
* 辅助JpaRestrictionBuilder类创建PropertyFilter后,
* 使用哪种约束条件向CriteriaBuilder添加Predicate进行条件过滤查询的接口
*
* @author vincent
*
*/
public interface PredicateBuilder {
/**
* 获取Jpa的约束标准
*
* @param filter 属性过滤器
* @param model jpa绑定模型
*
* @return Predicate
*
*/
public Predicate build(PropertyFilter filter,SpecificationModel model);
/**
* 获取Predicate标准的约束名称
*
* @return String
*/
public String getRestrictionName();
/**
* 获取Jpa的约束标准
*
* @param propertyName 属性名
* @param value 值
* @param builder CriteriaBuilder
*
* @return Predicate
*
*/
public Predicate build(String propertyName, Object value,SpecificationModel model);
}
而PredicateBuilder有两个实现某些方法的抽象类:PredicateMultipleValueSupport和PredicateSingleValueSupport
####PredicateSingleValueSupport抽象类 该类是PredicateBuilder的子类,该类实现了build(PropertyFilter filter,SpecificationModel model);实现体主要是对PropertyFilter的值模型做处理。并且逐个循环调用Predicate build(String propertyName, Object value,SpecificationModel model);方法给实现体做处理:
/**
* 处理PropertyFilter#getMatchValue()的基类,本类对3种值做处理
*
* 1.值等于正常值的,如:"amdin",会产生的squall为:property = 'admin'
* 2.值等于或值的,如:"admin_OR_vincent",会产生的sql为:property = 'admin' or property = 'vincent'
* 3.值等于与值的,如:"admin_AND_vincent",会产生的sql为:property = 'admin' and property = 'vincent'
*
* @author vincent
*
*/
public abstract class PredicateSingleValueSupport implements PredicateBuilder{
//or值分隔符
private String orValueSeparator = "|";
//and值分隔符
private String andValueSeparator = ",";
public PredicateSingleValueSupport() {
}
public Predicate build(PropertyFilter filter,SpecificationModel model) {
String matchValue = filter.getMatchValue();
Class<?> propertyType = filter.getPropertyType();
MatchValue matchValueModel = getMatchValue(matchValue, propertyType);
Predicate predicate = null;
if (matchValueModel.hasOrOperate()) {
predicate = model.getBuilder().disjunction();
} else {
predicate = model.getBuilder().conjunction();
}
for (Object value : matchValueModel.getValues()) {
if (filter.hasMultiplePropertyNames()) {
for (String propertyName:filter.getPropertyNames()) {
predicate.getExpressions().add(build(propertyName, value, model));
}
} else {
predicate.getExpressions().add(build(filter.getSinglePropertyName(), value, model));
}
}
return predicate;
}
public Predicate build(String propertyName, Object value,SpecificationModel model) {
return build(Specifications.getPath(propertyName, model.getRoot()),value,model.getBuilder());
}
/**
*
* 获取Jpa的约束标准
*
* @param expression 属性路径表达式
* @param value 值
* @param builder CriteriaBuilder
*
* @return Predicate
*/
public abstract Predicate build(Path<?> expression,Object value,CriteriaBuilder builder);
/**
* 获取值对比模型
*
* @param matchValue 值
* @param propertyType 值类型
*
* @return MatchValue
*/
public MatchValue getMatchValue(String matchValue,Class<?> propertyType) {
return MatchValue.createMatchValueModel(matchValue, propertyType,andValueSeparator,orValueSeparator);
}
/**
* 获取and值分隔符
*
* @return String
*/
public String getAndValueSeparator() {
return andValueSeparator;
}
/**
* 设置and值分隔符
* @param andValueSeparator and值分隔符
*/
public void setAndValueSeparator(String andValueSeparator) {
this.andValueSeparator = andValueSeparator;
}
}
该类是CriterionSingleValueSupport的子类。重写了CriterionSingleValueSupport类的public Criterion build(PropertyFilter filter)和public Criterion build(String propertyName, Object value)。并且添加了一个抽象方法public abstract Criterion buildRestriction(String propertyName,Object[] values)。该类主要作用是在多值的情况不逐个循环,而是全部都将参数组合成一个数组传递给抽象方法buildRestriction(String propertyName,Object[] values)中。这种情况在in或not in约束中就用得到。
/**
* 对PropertyFilter#getMatchValue()的特殊情况值做处理,例如 in, not in, between的多值情况,
* 该类值处理一种情况
*
* 例如:
*
* INI_property = "1,2,3,4";
* 会产生的sql为: property in (1,2,3,4)
*
* @author vincent
*
*/
public abstract class PredicateMultipleValueSupport extends PredicateSingleValueSupport{
/**
* 将得到值与指定分割符号,分割,得到数组
*
* @param value 值
* @param type 值类型
*
* @return Object
*/
public Object convertMatchValue(String value, Class<?> type) {
Assert.notNull(value,"值不能为空");
String[] result = StringUtils.splitByWholeSeparator(value, getAndValueSeparator());
return ConvertUtils.convertToObject(result,type);
}
public Predicate build(PropertyFilter filter, SpecificationModel model) {
Object value = convertMatchValue(filter.getMatchValue(), filter.getPropertyType());
Predicate predicate = null;
if (filter.hasMultiplePropertyNames()) {
Predicate orDisjunction = model.getBuilder().disjunction();
for (String propertyName:filter.getPropertyNames()) {
orDisjunction.getExpressions().add(build(propertyName,value,model));
}
predicate = orDisjunction;
} else {
predicate = build(filter.getSinglePropertyName(),value,model);
}
return predicate;
}
public Predicate build(Path<?> expression, Object value,CriteriaBuilder builder) {
return buildRestriction(expression,(Object[])value,builder);
}
/**
* 获取Jpa的约束标准
*
* @param expression root路径
* @param values 值
* @param builder CriteriaBuilder
*
* @return Predicate
*/
public abstract Predicate buildRestriction(Path<?> expression,Object[] values,CriteriaBuilder builder);
}
JpaRestrictionBuilder是装载所有PredicateBuilder子类的包装类,该类有一块静态局域。去初始化所有的约束条件。并提供两个方法去创建Jap的Predicate,该类是PropertyFilterSpecification和PropertySpecification类中条件表达式查询的关键类。所有通过条件创建的Predicate都是通过该类创建。
/**
* jpa约束捆绑者,将所有的PredicateBuilder实现类添加到getRestrictionsMap()中,
* 辅佐PropertyFilterSpecification和RestrictionNameSpecification
* 做创建Predicate操作。
*
* @author vincent
*
*/
public class JpaRestrictionBuilder{
private static Map<String, PredicateBuilder> predicateBuilders = new HashMap<String, PredicateBuilder>();
static {
PredicateBuilder eqRestriction = new EqRestriction();
PredicateBuilder neRestriction = new NeRestriction();
PredicateBuilder geRestriction = new GeRestriction();
PredicateBuilder gtRestriction = new GtRestriction();
PredicateBuilder inRestriction = new InRestriction();
PredicateBuilder lLikeRestriction = new LLikeRestriction();
PredicateBuilder leRestriction = new LeRestriction();
PredicateBuilder likeRestriction = new LikeRestriction();
PredicateBuilder ltRestriction = new LtRestriction();
PredicateBuilder notInRestriction = new NinRestriction();
PredicateBuilder rLikeRestriction = new RLikeRestriction();
predicateBuilders.put(eqRestriction.getRestrictionName(), eqRestriction);
predicateBuilders.put(neRestriction.getRestrictionName(), neRestriction);
predicateBuilders.put(geRestriction.getRestrictionName(), geRestriction);
predicateBuilders.put(inRestriction.getRestrictionName(), inRestriction);
predicateBuilders.put(gtRestriction.getRestrictionName(), gtRestriction);
predicateBuilders.put(lLikeRestriction.getRestrictionName(), lLikeRestriction);
predicateBuilders.put(leRestriction.getRestrictionName(), leRestriction);
predicateBuilders.put(likeRestriction.getRestrictionName(), likeRestriction);
predicateBuilders.put(ltRestriction.getRestrictionName(), ltRestriction);
predicateBuilders.put(rLikeRestriction.getRestrictionName(), rLikeRestriction);
predicateBuilders.put(notInRestriction.getRestrictionName(), notInRestriction);
}
/**
* 通过属性过滤器创建Predicate
*
* @param filter 属性过滤器
* @param restrictionModel jpa查询绑定载体
*
* @return Predicate
*/
public static Predicate getRestriction(PropertyFilter filter,SpecificationModel model) {
if (!predicateBuilders.containsKey(filter.getRestrictionName())) {
throw new IllegalArgumentException("找不到约束名:" + filter.getRestrictionName());
}
PredicateBuilder predicateBuilder = predicateBuilders.get(filter.getRestrictionName());
return predicateBuilder.build(filter,model);
}
/**
* 通过属性名称,值,约束条件创建Predicate
*
* @param propertyName 属性名称
* @param value 值
* @param restrictionName 约束条件
* @param model jpa查询绑定载体
*
* @return Predicate
*/
public static Predicate getRestriction(String propertyName, Object value,String restrictionName,SpecificationModel model) {
if (!predicateBuilders.containsKey(restrictionName)) {
throw new IllegalArgumentException("找不到约束名:" + restrictionName);
}
PredicateBuilder predicateBuilder = predicateBuilders.get(restrictionName);
return predicateBuilder.build(propertyName, value, model);
}
/**
* 获取所有的条件约束
*
* @return Map
*/
public static Map<String, PredicateBuilder> getPredicateBuilders() {
return predicateBuilders;
}
/**
* 设置所有的条件约束
*
* @param 条件约束
*/
public static void setPredicateBuilders(Map<String, PredicateBuilder> predicateBuilders) {
JpaRestrictionBuilder.predicateBuilders = predicateBuilders;
}
}
了解完以上几个类。那么假设现在有个需求。要写一个模糊约束 (rom object o where o.value like '%?%')来判断一些值,可以通过继承PredicateSingleValueSupport类,实现build(Path<?> expression,Object value,CriteriaBuilder builder),如:
/**
* 模糊约束 ( from object o where o.value like '%?%') RestrictionName:LIKE
* <p>
* 表达式:LIKE属性类型_属性名称[_OR_属性名称...]
* </p>
*
* @author vincent
*
*/
public class LikeRestriction extends PredicateSingleValueSupport{
public String getRestrictionName() {
return RestrictionNames.LIKE;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public Predicate build(Path expression, Object value,CriteriaBuilder builder) {
return builder.like(expression, "%" + value + "%");
}
}
通过某种方式(如spring的InitializingBean,或serlvet)将该类添加到JpaRestrictionBuilder的PredicateBuilder中。就可以使用约束名了。
PredicateBuilder nlikeRestriction= new NlikeRestriction();
JpaRestrictionBuilder.getCriterionMap().put(nlikeRestriction.getRestrictionName(), nlikeRestriction);
以上是exitsoft orm的使用说明。该jar在vcs-admin-jpa演示例子中的org.exitsoft.showcase.vcsadmin.dao包下都使用到。可以参考例子。