實現(xiàn)
PagingAndSortingRepository,
QueryDslPredicateExecutor,
JpaSpecificationExecutor
寫了一個封裝類蚓胸,封裝了查詢通用條件
1、實現(xiàn)動態(tài)綁定entity任意屬性去查詢或者排序
2除师、也適用于update的話沛膳,只更新請求傳過來的值去update,其他不變
3汛聚、動態(tài)構(gòu)建PageRequest锹安,實現(xiàn)多重排序條件
4、動態(tài)構(gòu)建Specification倚舀, 實現(xiàn)多重條件查詢
下面實例代碼:
package base
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.querydsl.core.types.ExpressionUtils
import com.querydsl.core.types.Ops
import com.querydsl.core.types.Predicate
import com.querydsl.core.types.dsl.BooleanExpression
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.core.types.dsl.StringPath
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import org.springframework.web.bind.annotation.ExceptionHandler
import java.io.BufferedReader
import java.lang.reflect.Method
import java.util.ArrayList
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Root
/**
* Created by liushuhua on 25/03/2017.
*
* @ControllerAdvice will only kick in if an exception is thrown from within a controller method
*
**/
internal class EntityBuilder {
companion object Factory {
/**
* 構(gòu)造query條件的Expression
* 將傳遞的參數(shù)自動綁定到Entity上
*
* @param Any
* @return BooleanExpression
*/
@ExceptionHandler(Throwable::class)
fun matchSelectiveAttrExpressions(obj: Any): BooleanExpression? {
val c = obj.javaClass
var rv: BooleanExpression? = null
val fs = c.getDeclaredFields()
for (i in fs.indices) {
val f = fs[i]
f.isAccessible = true //設(shè)置些屬性是可以訪問的
val `val` = f.get(obj)//得到此屬性的值
if (`val` != null) {
val ce1 = Expressions.stringPath(lowerCaseClassName(c.getSimpleName()) + "." + f.name)
val ce2 = ExpressionUtils.toExpression(`val`)
val pred = Expressions.booleanOperation(Ops.EQ, ce1, ce2)
rv = if (rv != null) rv.and(pred) else pred
}
}
return rv
}
/**
* 構(gòu)造update的Enity
* 將傳遞的參數(shù)綁定到該id的Entity上叹哭,
* 設(shè)置成新的Entity,id不變痕貌,再到數(shù)據(jù)庫update
*
* @param Any1, Any2
* @return Any2
*/
@Throws(Exception::class)
fun matchSelectiveEntity(obj1: Any, obj2: Any): Any {
val fields = obj1.javaClass.declaredFields
// 遍歷所有屬性
for (j in fields.indices) {
val name = fields[j].name
if (fields[j].get(obj1) != null && !"createdAt".equals(name) && !"createdBy".equals(name)) {
val args = arrayOfNulls<Class<*>>(1)
args[0] = fields[j].type
val c = obj1.javaClass
val methodName = "set" + upperCaseClassName(name)
var method: Method? = null
method = c.getMethod(methodName, *args)
method!!.invoke(obj2, fields[j].get(obj1))
}
}
return obj2
}
/**
* 創(chuàng)建分頁請求.
* pageNumber 從 1 開始
*/
@Throws(Exception::class)
fun buildPageRequest(jsonObject: JSONObject): PageRequest {
val pageNumber = Integer.parseInt(jsonObject["pageNumber"].toString())
val pagzSize = Integer.parseInt(jsonObject["pageSize"].toString())
val sortArray = jsonObject.getJSONArray("sort")
val sortList = ArrayList<Sort.Order>()
for (i in sortArray.indices) {
val ascFlag = sortArray.getJSONObject(i)["asc"].toString()
var order: Sort.Order? = null
if ("true" == ascFlag) {
order = Sort.Order(Sort.Direction.ASC, sortArray.getJSONObject(i)["field"].toString())
} else {
order = Sort.Order(Sort.Direction.DESC, sortArray.getJSONObject(i)["field"].toString())
}
sortList.add(order)
}
return PageRequest(pageNumber - 1, pagzSize, Sort(sortList))
}
/**
* 創(chuàng)建動態(tài)查詢條件組合.
*/
@Throws(Exception::class)
fun <T> buildSpecification(jsonObject: JSONObject): Specification<T> {
val criteriaArray = jsonObject.getJSONArray("criteria")
val spec = Specification<T> { root, criteriaQuery, criteriaBuilder ->
val predicates = ArrayList<javax.persistence.criteria.Predicate>()
for (i in criteriaArray.indices) {
val field = criteriaArray.getJSONObject(i)["field"].toString()
val value = criteriaArray.getJSONObject(i)["value"].toString()
val operator = criteriaArray.getJSONObject(i)["operator"].toString()
if ("eq" == operator) {
predicates.add(criteriaBuilder.equal(root.get<Any>(field), value))
}
}
criteriaBuilder.and(*predicates.toTypedArray())
}
return spec
}
private fun lowerCaseClassName(name: String): String {
return name.substring(0, 1).toLowerCase() + name.substring(1)
}
private fun upperCaseClassName(name: String): String {
return name.substring(0, 1).toUpperCase() + name.substring(1)
}
}
}
調(diào)用查詢方法
override fun listCustomer(jsonObject: JSONObject): MutableIterable<Customer> {
val pageable = EntityBuilder.buildPageRequest(jsonObject)
val spec = EntityBuilder.buildSpecification<Customer>(jsonObject)
return customerRepository.findAll(spec, pageable)
}
其中jsonObject是:
{
"pageNumber": "1",
"pageSize": "10",
"criteria": [{"operator": "like", "field": "name", "value": "aaa"}],
"sort": [{"field":"id","asc":"true"}]
}
調(diào)用更新方法
override fun save(customer: Customer) : Customer {
if(customer.id == null){
return customerRepository.save(customer)
}else{
val oldCustomer = findById(customer.id)
if(oldCustomer == null){
throw Exception("The entity not found")
}
val customer = EntityBuilder.matchSelectiveEntity(customer, oldCustomer!!) as Customer
return customerRepository.save(customer)
}
}