Spring boot JPA QueryDSL多條件分頁查詢衙传,只更新傳過來的值嘱支,實現(xiàn)動態(tài)綁定

實現(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)
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末风罩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子舵稠,更是在濱河造成了極大的恐慌超升,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哺徊,死亡現(xiàn)場離奇詭異室琢,居然都是意外死亡,警方通過查閱死者的電腦和手機落追,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門研乒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淋硝,你說我怎么就攤上這事雹熬】聿耍” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵竿报,是天一觀的道長铅乡。 經(jīng)常有香客問我,道長烈菌,這世上最難降的妖魔是什么阵幸? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮芽世,結(jié)果婚禮上挚赊,老公的妹妹穿的比我還像新娘。我一直安慰自己济瓢,他們只是感情好荠割,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旺矾,像睡著了一般蔑鹦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上箕宙,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天嚎朽,我揣著相機與錄音,去河邊找鬼柬帕。 笑死哟忍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的陷寝。 我是一名探鬼主播锅很,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盼铁!你這毒婦竟也來了粗蔚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤饶火,失蹤者是張志新(化名)和其女友劉穎鹏控,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肤寝,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡当辐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鲤看。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缘揪。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出找筝,到底是詐尸還是另有隱情蹈垢,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布袖裕,位于F島的核電站曹抬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏急鳄。R本人自食惡果不足惜谤民,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疾宏。 院中可真熱鬧张足,春花似錦、人聲如沸坎藐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顺饮。三九已至吵聪,卻和暖如春凌那,著一層夾襖步出監(jiān)牢的瞬間兼雄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工帽蝶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赦肋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓励稳,卻偏偏與公主長得像佃乘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驹尼,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,860評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理趣避,服務(wù)發(fā)現(xiàn),斷路器新翎,智...
    卡卡羅2017閱讀 134,638評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法程帕,類相關(guān)的語法,內(nèi)部類的語法地啰,繼承相關(guān)的語法愁拭,異常的語法,線程的語...
    子非魚_t_閱讀 31,602評論 18 399
  • 大家有沒有發(fā)現(xiàn):互聯(lián)網(wǎng)上比較牛的大咖們惜论,使用頻率最高的工具是什么许赃? 思維導(dǎo)圖。 大咖們使用頻率最多的工具就是思維導(dǎo)...
    軟文掘金一阿曲閱讀 498評論 0 0
  • 最進國家關(guān)于網(wǎng)約車的政策出臺,已經(jīng)有了一段時間蹦掐。關(guān)于出租車的承包費問題技羔,國家還是鼓勵駕駛員與承包企業(yè)協(xié)商。到目前為...
    難得糊涂abc閱讀 2,659評論 0 1