美文网首页
Spring boot JPA QueryDSL多条件分页查询,

Spring boot JPA QueryDSL多条件分页查询,

作者: huarda | 来源:发表于2017-04-14 15:40 被阅读0次

    实现

    PagingAndSortingRepository,
    QueryDslPredicateExecutor,
    JpaSpecificationExecutor

    写了一个封装类,封装了查询通用条件
    1、实现动态绑定entity任意属性去查询或者排序
    2、也适用于update的话,只更新请求传过来的值去update,其他不变
    3、动态构建PageRequest,实现多重排序条件
    4、动态构建Specification, 实现多重条件查询
    下面实例代码:

    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 {
    
            /**
             * 构造query条件的Expression
             * 将传递的参数自动绑定到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 //设置些属性是可以访问的
                    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
            }
    
            /**
             * 构造update的Enity
             * 将传递的参数绑定到该id的Entity上,
             * 设置成新的Entity,id不变,再到数据库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
            }
    
            /**
             * 创建分页请求.
             * 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))
            }
    
            /**
             * 创建动态查询条件组合.
             */
            @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)
            }
        }
    }
    
    
    

    调用查询方法

    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"}]
    }
    

    调用更新方法

    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)
        }
    }
    

    相关文章

      网友评论

          本文标题:Spring boot JPA QueryDSL多条件分页查询,

          本文链接:https://www.haomeiwen.com/subject/kbnwattx.html