MongoDB使用Query增删改查分页实战记录

需求:列表接口查询速度慢,需要用MongoDB每五分钟进行一次数据同步,原接口改用MongoDB查而不是用RestTemplate访问

此项目分:1.core公共模块,2.background背景任务模块,3.api模块

build-gradle添加依赖和yml配置

yml

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/local


build-gradle

api 'org.springframework.boot:spring-boot-starter-data-mongodb'

core

package com.umh.medicalbookingplatform.core.properties

import org.slf4j.LoggerFactory
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct

@Component
@ConfigurationProperties("app")
class ApplicationProperties {

    private val logger = LoggerFactory.getLogger(javaClass)

    var environment: String? = null
    var s3: S3Properties = S3Properties()
    var staticSmsVerificationEnabled: Boolean? = null
    var staticSmsVerificationValue: String? = null
    var keycloakAuthServerUrl: String? = null
    var keycloakGlobalCmsRealm: String? = null
    var keycloakGlobalCmsClient: String? = null
    var keycloakGlobalProfileRealm: String? = null
    var keycloakGlobalProfileClient: String? = null
    var keycloakBookingSystemRealm: String? = null
    var keycloakBookingSystemClient: String? = null
    var keycloakUmhBookingSystemRealm: String? = null
    var keycloakUmhBookingSystemClient: String? = null
    var keycloakApiUsername: String? = null
    var keycloakApiPassword: String? = null
    var globalCmsApiEndpoint: String? = null
    var globalGPApiEndpoint: String? = null
    var bookingSystemApiEndpoint: String? = null
    var umhBookingSystemAPIEndpoint: String? = null
    var twilioProperties: TwilioProperties = TwilioProperties()
    var firebaseAdminSdk: String? = null
    var wechatAppId: String? = null
    var wechatAppSecret: String? = null

    @PostConstruct
    fun postConstruct() {
        logger.debug("environment=$environment")
    }
}

 使用此类会自动搜索使用模块下的yml配置

core

package com.umh.medicalbookingplatform.core.datainitializer

import com.umh.medicalbookingplatform.core.model.background.BackgroundTask
import com.umh.medicalbookingplatform.core.model.background.BackgroundTaskLock
import com.umh.medicalbookingplatform.core.model.background.BackgroundTaskRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.*
import javax.persistence.EntityManager

@Service
class BackgroundTaskDataInitializer : DataInitializer {

    @Autowired
    private lateinit var em: EntityManager

    @Autowired
    private lateinit var backgroundTaskRepository: BackgroundTaskRepository

    @Transactional
    override fun initialize() {
        //测试时改为了1分钟
        createBackgroundTask(
            BackgroundTask.BackgroundTaskCode.GLOBAL_CMS_SYNCHRONIZATION_TASK,
            "Global CMS Synchronization",
            BackgroundTask.BackgroundTaskIntervalType.MINUTE,
            1,
            true
        )


    }

    private fun createBackgroundTask(
        code: BackgroundTask.BackgroundTaskCode,
        name: String,
        intervalType: BackgroundTask.BackgroundTaskIntervalType,
        interval: Int,
        enabled: Boolean
    ) {

        if (backgroundTaskRepository.findByCode(code) == null) {
            val currentDate = Date()
            val bt = BackgroundTask().apply bt@{
                this.code = code
                this.name = name
                this.intervalType = intervalType
                this.interval = interval;
                nextProcessTime = currentDate
                lastProcessStartTime = currentDate
                lastProcessEndTime = currentDate
                lastProcessStatus = BackgroundTask.LastProcessStatus.SUCCESS
                this.enabled = enabled
                backgroundTaskLock = BackgroundTaskLock().apply {
                    backgroundTask = this@bt
                }
            }

            em.merge(bt)
        }
    }
}

 当前模块的主启动类-background

package com.umh.medicalbookingplatform.background

import com.umh.medicalbookingplatform.core.audit.StaticAuditorAware
import com.umh.medicalbookingplatform.core.config.CoreConfiguration
import com.umh.medicalbookingplatform.core.properties.ApplicationProperties
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import org.keycloak.OAuth2Constants
import org.keycloak.admin.client.Keycloak
import org.keycloak.admin.client.KeycloakBuilder
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.WebApplicationType
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Import
import org.springframework.data.domain.AuditorAware
import org.springframework.data.jpa.repository.config.EnableJpaAuditing
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.annotation.SchedulingConfigurer
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
import org.springframework.scheduling.config.ScheduledTaskRegistrar
import java.security.Security
import java.util.*


@EnableJpaAuditing
@EnableCaching
@EnableScheduling
@SpringBootApplication
@Import(CoreConfiguration::class)
open class BackgroundApplication : SchedulingConfigurer {

    @Bean
    internal fun auditorProvider(): StaticAuditorAware {
        return StaticAuditorAware()
    }

    @Autowired
    private lateinit var appProperties: ApplicationProperties
    //配置bean
    @Bean(name = ["keycloakGlobalCmsApi"])
    fun keycloakGlobalCmsApiInstance(): Keycloak {
        return KeycloakBuilder.builder()
            .serverUrl(appProperties.keycloakAuthServerUrl)
            .realm(appProperties.keycloakGlobalCmsRealm)
            .clientId(appProperties.keycloakGlobalCmsClient)
            .username(appProperties.keycloakApiUsername)
            .password(appProperties.keycloakApiPassword)
            .grantType(OAuth2Constants.PASSWORD)
            .resteasyClient(
                ResteasyClientBuilder()
                    .connectionPoolSize(10).build()
            ).build()
    }

    override fun configureTasks(taskRegistrar: ScheduledTaskRegistrar) {
        val taskScheduler = ThreadPoolTaskScheduler()
        taskScheduler.poolSize = 200
        taskScheduler.initialize()
        taskRegistrar.setTaskScheduler(taskScheduler)
    }

}

fun main(args: Array<String>) {
    Security.setProperty("crypto.policy", "unlimited")

    val app = SpringApplication(BackgroundApplication::class.java)
//    app.webApplicationType = WebApplicationType.NONE

    val ctx = app.run(*args)

}

background-service

package com.umh.medicalbookingplatform.background.service

import com.umh.medicalbookingplatform.core.error.ErrorCode
import com.umh.medicalbookingplatform.core.exception.ApplicationException
import com.umh.medicalbookingplatform.core.properties.ApplicationProperties
import com.umh.medicalbookingplatform.core.utils.RestTemplateUtils
import com.alibaba.fastjson.JSONObject
import com.umh.medicalbookingplatform.core.model.i18n.I18nString
import com.umh.medicalbookingplatform.core.utils.LocaleUtils
import org.apache.commons.lang3.StringUtils
import org.keycloak.admin.client.Keycloak
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Pageable
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Service
import org.springframework.web.util.UriComponentsBuilder
import java.lang.StringBuilder
import java.util.*
import com.alibaba.fastjson.JSON
import com.umh.medicalbookingplatform.core.model.doctor.*
import com.umh.medicalbookingplatform.core.utils.ApplicationJsonObjectMapper
import org.bson.Document
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query


/**
 * @Description :
 * @Author xiaomh
 * @create 2021/9/8 14:27
 */

@Service
class ApiCmsInvokeService {

    private val dayArray = arrayOf("mon", "tue", "wed", "thu", "fri", "sat", "sun", "gong")

    private val logger = LoggerFactory.getLogger(this.javaClass)

    @Autowired
    private lateinit var keycloakGlobalCmsApi: Keycloak

    @Autowired
    private lateinit var applicationProperties: ApplicationProperties

    @Autowired
    private lateinit var mongoTemplate: MongoTemplate


    fun getDoctorList(param: DoctorListParam): DoctorListDto {
        val p = parseDoctorsRequest(param)
        val headers = HttpHeaders()
        val listDto = DoctorListDto()
        headers.set("Accept", "application/json")
        headers.set("version", "v1")
        headers.set("x-umhappweb-authorization", keycloakGlobalCmsApi.tokenManager().accessToken.token)
        val entity = HttpEntity(null, headers)
        val apiCmsInvokeUri = "/v1/api/onlinebookingdoctors_list?channel_id=4"

        val response: ResponseEntity<Object>
        try {
            logger.info("[START] Call globalcms '$apiCmsInvokeUri$p'")
            response = RestTemplateUtils.getRestTemplate().exchange(
                "${applicationProperties.globalCmsApiEndpoint}$apiCmsInvokeUri$p",
                HttpMethod.GET,
                entity,
                Object::class.java,
            )
            logger.info("[END] Call globalcms '$apiCmsInvokeUri$p'")
        } catch (e: Exception) {
            logger.error(e.message, e)
            throw ApplicationException(ErrorCode.ERR_GLOBAL_CMS_DOCTOR_LIST_API)
        }

        val body = response.body ?: return listDto
        val doctorList = mutableListOf<DoctorsDto>()
        val mongodbIds = mutableListOf<String>()
        val jsonBody = JSONObject.toJSONString(body)
        val jsonObject = JSONObject.parseObject(jsonBody)

        if (jsonObject["result_code"].toString() != "0") {
            logger.error("Failed To Call CMS API: 'doctors_list' ")
            logger.error("error_code: ${jsonObject["result_code"]}, error_msg: ${jsonObject["result_msg"]}")
            throw ApplicationException(ErrorCode.ERR_GLOBAL_CMS_DOCTOR_LIST_API)
        }

        val resultObject = jsonObject.getJSONObject("result")
        val resultArray = resultObject.getJSONArray("result")

        val iterator = resultArray.iterator()
        val objectMapper = ApplicationJsonObjectMapper()
        while (iterator.hasNext()) {
            val next = iterator.next() as JSONObject
            val doctor = DoctorsDto()
            doctor._id = next["therapistid"]?.toString()
            doctor.doctorId = next["therapistid"]?.toString()
            doctor.personnelId = next["personnel_id"]?.toString()
            doctor.version = next["version"]?.toString()
            doctor.hospitalFee = (next["hospital_fee"]?.toString())?.toDoubleOrNull()
            doctor.medicalTicket = next["medical_ticket"]?.toString() ?: "0"
            doctor.doctorCode = next["staffcode"]?.toString() ?: next["username"]?.toString()
            val cnName = if (StringUtils.isNotBlank(next["cn_name"]?.toString())) next["cn_name"] else next["name"]
            val tcName = if (StringUtils.isNotBlank(next["tc_name"]?.toString())) next["tc_name"] else next["name"]
            val enName = if (StringUtils.isNotBlank(next["en_name"]?.toString())) next["en_name"] else next["name"]
            doctor.gender = if ("1" == next["sex"]) "M" else "F"
            doctor.doctorName.add(I18nString(LocaleUtils.SIMPLIFIED_CHINESE, cnName.toString() ?: ""))
            doctor.doctorName.add(I18nString(LocaleUtils.TRADITIONAL_CHINESE, tcName.toString() ?: ""))
            doctor.doctorName.add(I18nString(LocaleUtils.ENGLISH, enName.toString() ?: ""))

            val languages = next.getJSONArray("language_list")
            val languagesIterator = languages.iterator()
            while (languagesIterator.hasNext()) {
                val languagesNext = languagesIterator.next() as JSONObject
                val language = Language()
                language.languageId = languagesNext["language_id"]?.toString()
                language.language.add(I18nString(LocaleUtils.SIMPLIFIED_CHINESE, languagesNext["cn_name"].toString()))
                language.language.add(I18nString(LocaleUtils.TRADITIONAL_CHINESE, languagesNext["tc_name"].toString()))
                language.language.add(I18nString(LocaleUtils.ENGLISH, languagesNext["en_name"].toString()))
                doctor.languages.add(language)
            }

            val labelListObj = next.getJSONArray("label_list")
            val labelListIterator = labelListObj.iterator()
            while (labelListIterator.hasNext()) {
                val labelListNext = labelListIterator.next() as JSONObject
                val label = Label()
                label.labelId = labelListNext["label_id"].toString()
                label.label.add(I18nString(LocaleUtils.SIMPLIFIED_CHINESE, labelListNext["cn_name"].toString() ?: ""))
                label.label.add(I18nString(LocaleUtils.TRADITIONAL_CHINESE, labelListNext["tc_name"].toString() ?: ""))
                label.label.add(I18nString(LocaleUtils.ENGLISH, labelListNext["en_name"].toString() ?: ""))
                doctor.labels.add(label)
            }
            val specialtiesJsonObject = next.getJSONArray("specialty_name_list")
            val specialtiesIterator = specialtiesJsonObject.iterator()
            while (specialtiesIterator.hasNext()) {
                val specialtyNext = specialtiesIterator.next() as JSONObject
                val specialtyDto = SpecialtyDto()
                specialtyDto.specialtyId = specialtyNext["specialty_id"].toString()
                specialtyDto.specialtyDoctor.add(
                    I18nString(
                        LocaleUtils.SIMPLIFIED_CHINESE,
                        parseSyTitle(specialtyNext["doctor_short_cn_name"]?.toString())
                    )
                )
                specialtyDto.specialtyDoctor.add(
                    I18nString(
                        LocaleUtils.TRADITIONAL_CHINESE,
                        parseSyTitle(specialtyNext["doctor_short_tc_name"]?.toString())
                    )
                )
                specialtyDto.specialtyDoctor.add(
                    I18nString(
                        LocaleUtils.ENGLISH,
                        parseSyTitle(specialtyNext["doctor_short_en_name"]?.toString())
                    )
                )
                doctor.specialties.add(specialtyDto)
            }

            val brandJsonObject = next.getJSONArray("brand_list")
            val brandIterator = brandJsonObject.iterator()
            while (brandIterator.hasNext()) {
                val brandNext = brandIterator.next() as JSONObject
                val brandDto = BrandDto()
                brandDto.brandId = brandNext["brand_id"].toString()
                brandDto.brandName.add(
                    I18nString(
                        LocaleUtils.SIMPLIFIED_CHINESE,
                        parseSyTitle(brandNext["cn_name"]?.toString())
                    )
                )
                brandDto.brandName.add(
                    I18nString(
                        LocaleUtils.TRADITIONAL_CHINESE,
                        parseSyTitle(brandNext["tc_name"]?.toString())
                    )
                )
                brandDto.brandName.add(
                    I18nString(
                        LocaleUtils.ENGLISH,
                        parseSyTitle(brandNext["en_name"]?.toString())
                    )
                )
                doctor.brands.add(brandDto)
            }

            val regionJsonObject = next["region_list"]
            if (regionJsonObject is JSONObject) {
                val jsonObj = JSON.parseObject(regionJsonObject.toString())
                for ((key, value) in jsonObj) {
                    val regionList = (regionJsonObject as JSONObject).getJSONArray(key)
                    val regionListIterator = regionList.iterator()
                    while (regionListIterator.hasNext()) {
                        val regionListNext = regionListIterator.next() as JSONObject
                        val shop = MongoDBShopsDto()
                        shop.shopId = regionListNext["shopid"]?.toString()
                        shop.shopCode = regionListNext["shopcode"]?.toString()
                        shop.regionId = regionListNext["x_id"]?.toString()
                        shop.locations.add(
                            I18nString(
                                LocaleUtils.SIMPLIFIED_CHINESE, regionListNext["atitle"]?.toString() ?: ""
                            )
                        )
                        shop.locations.add(
                            I18nString(
                                LocaleUtils.TRADITIONAL_CHINESE,
                                regionListNext["tc_atitle"]?.toString() ?: ""
                            )
                        )
                        shop.locations.add(
                            I18nString(
                                LocaleUtils.ENGLISH,
                                regionListNext["en_atitle"]?.toString() ?: ""
                            )
                        )
                        shop.clinics.add(
                            I18nString(
                                LocaleUtils.SIMPLIFIED_CHINESE,
                                regionListNext["cn_name"].toString()
                            )
                        )
                        shop.clinics.add(
                            I18nString(
                                LocaleUtils.TRADITIONAL_CHINESE,
                                regionListNext["tc_name"].toString()
                            )
                        )
                        shop.clinics.add(I18nString(LocaleUtils.ENGLISH, regionListNext["en_name"].toString()))
                        shop.address.add(
                            I18nString(
                                LocaleUtils.SIMPLIFIED_CHINESE,
                                parseAddress(regionListNext["cn_address"]?.toString() ?: "")
                            )
                        )
                        shop.address.add(
                            I18nString(
                                LocaleUtils.TRADITIONAL_CHINESE,
                                parseAddress(regionListNext["tc_address"]?.toString() ?: "")
                            )
                        )
                        shop.address.add(
                            I18nString(
                                LocaleUtils.ENGLISH,
                                parseAddress(regionListNext["en_address"]?.toString() ?: "")
                            )
                        )
                        shop.mail = regionListNext["mail"]?.toString()
                        shop.phone = parsePhone(regionListNext["phone"]?.toString())
                        shop.businessDays = parseBusinessDays(regionListNext["business_hours"]?.toString())
                        doctor.shops.add(shop)
                    }
                }
            }
            //此处开始看
            //把doctorId都存起来,把本次更新数据没有的doctor的清除掉
            doctor.doctorId?.let { mongodbIds.add(it) }
            //查询集合,有数据则更新,没有数据则添加。注意,创建的时候如果有_id,则_id为MongoDB的ObjectId(主键)
            val query = Query()
            query.addCriteria(Criteria.where("_id").`is`(doctor.doctorId))
            val json = objectMapper.writeValueAsString(doctor)
            val doc = Document.parse(json)
            if (!mongoTemplate.exists(query,"doctors")){
                mongoTemplate.insert(doc,"doctors")
            }
            mongoTemplate.findAndReplace(query,doc,"doctors")

            doctorList.add(doctor)
        }
        //把本次更新数据没有的doctor的清除掉
        //结束
        val query = Query()
        query.addCriteria(Criteria.where("_id").nin(mongodbIds))
        mongoTemplate.remove(query,"doctors")


        listDto.content = doctorList
        listDto.total = resultObject["count"]?.toString()?.toInt()
        return listDto
    }

    private fun parseBusinessDays(businessHoursStr: String?): MutableList<BusinessHourDto> {
        val jsonObject = JSONObject.parseObject(businessHoursStr)
        return parseBusinessHours(jsonObject)

    }

    private fun parseBusinessHours(jsonObject: JSONObject?): MutableList<BusinessHourDto> {
        val businessHours = mutableListOf<BusinessHourDto>()
        for (i in dayArray.indices) {
            val hoursJson = jsonObject?.getJSONArray(dayArray[i])
            val iterator = hoursJson?.iterator() ?: mutableListOf<BusinessHourDto>().iterator()
            val hourDto = BusinessHourDto()
            while (iterator.hasNext()) {
                val next = iterator.next() as JSONObject
                hourDto.periods!!.add(
                    BusinessHourPeriodDto().apply {
                        this.startTime = next["starttime"]?.toString() ?: ""
                        this.endTime = next["endtime"]?.toString() ?: ""
                    }
                )
            }
            if (dayArray[i] == "gong") {
                hourDto.day = "holiday"
            } else {
                hourDto.day = dayArray[i]
            }
            businessHours.add(hourDto)
        }
        return businessHours
    }

    fun parseSyTitle(syTitle: String?): String {
        val joiner = StringJoiner(",")
        syTitle?.split(",")?.forEach {
            if (StringUtils.isNotBlank(it)) {
                joiner.add(it)
            }
        }
        return joiner.toString()
    }

    fun parsePersonnel(location: String): String {
        val builder = StringBuilder()
        val split = location.split("\n")
        split.forEach {
            if (!builder.contains(it)) {
                builder.append(it).append(", ")
            }
        }

        if (builder.isNotEmpty()) {
            builder.deleteCharAt(builder.length - 2)

        }

        return builder.toString()
    }

    fun parseAddress(location: String): String {
        val builder = StringBuilder()

        val split = location.split("\"],[\"")
        split.forEach {
            if (!builder.contains(it)) {
                builder.append(it).append(", ")
            }
        }

        if (builder.isNotEmpty()) {
            builder.delete(builder.length - 4, builder.length)
            builder.delete(0, 2)
        }

        val builderSecond = StringBuilder()
        val splitSecond = builder.split("\",\"")
        splitSecond.forEach {
            if (!builderSecond.contains(it)) {
                builderSecond.append(it)
            }
        }

        return builderSecond.toString()
    }

    fun parsePhone(phoneStr: String?): MutableList<Phone> {
        val jsonBody = JSONObject.toJSONString(phoneStr)
        val jsonObject = JSONObject.parseObject("{\"phone\": " + jsonBody + "}")
        val phoneList = mutableListOf<Phone>()
        val phones = jsonObject.getJSONArray("phone")
        val iteratorPhone = phones?.iterator()
        if (iteratorPhone != null) {
            while (iteratorPhone.hasNext()) {
                val next = iteratorPhone.next() as JSONObject
                val phone = Phone()
                phone.mobileNoAreaCode = next["phonearea"]?.toString()
                phone.mobileNo = next["phoneval"]?.toString()

                phoneList.add(phone)
            }
        }
        return phoneList

    }

    private fun parseDoctorsRequest(param: DoctorListParam): String {
        val searchKey = param.searchKey?.let { "&search_key=${it}" } ?: ""
        val shopId = param.shopId?.let { "&shop_id=${it}" } ?: ""
        val brandId = param.brandId?.let { "&brand_id=${it}" } ?: ""
        val specialtyId = param.specialtyId?.let { "&specialty_id=${it}" } ?: ""
        val region = param.regionId?.let { "&region=${it}" } ?: ""
        val startTime = param.startTime?.let { "&start_time=${it}" } ?: ""
        val endTime = param.endTime?.let { "&end_time=${it}" } ?: ""
        val medicalTicket = param.medicalTicket?.let { "&medical_ticket=${it}" } ?: ""
        val startHospitalFee = param.startHospitalFee?.let { "&start_hospital_fee=${it}" } ?: ""
        val endHospitalFee = param.endHospitalFee?.let { "&end_hospital_fee=${it}" } ?: ""
        val languageId = param.languageId?.let { "&language_id=${it}" } ?: ""
        val gender = param.gender?.let {
            "&sex=${it}"
                .replace("%2C", ",")
                .replace("M", "1")
                .replace("F", "2")
        } ?: ""
        val orderby = param.orderby?.let { "&orderby=${it}" } ?: ""
        val page = param.page.let { "&page=${it?.plus(1) ?: 1}" }
        val pageSize = param.pageSize.let { "&page_size=${it ?: 0}" }
        return "$searchKey$shopId$brandId$specialtyId$region$startTime$endTime$medicalTicket$startHospitalFee$endHospitalFee$languageId$gender$orderby$page$pageSize"
    }

}

时间数据处理

class BusinessHourDto {
    @Schema(description = "星期几")
    var day = ""

    @Schema(description = "时段")
    var periods: MutableList<BusinessHourPeriodDto>? = mutableListOf()
}

class BusinessHourPeriodDto {

    @Schema(description = "时段 start")
    var startTime = ""

    @Schema(description = "时段 end")
    var endTime = ""
}

 background-controller

package com.umh.medicalbookingplatform.background.task.globalcmssynchronization

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.umh.medicalbookingplatform.background.service.ApiCmsInvokeService
import com.umh.medicalbookingplatform.background.task.BackgroundTaskExecutor
import com.umh.medicalbookingplatform.core.error.ErrorCode
import com.umh.medicalbookingplatform.core.exception.ApplicationException
import com.umh.medicalbookingplatform.core.model.background.BackgroundTask
import com.umh.medicalbookingplatform.core.model.doctor.*
import com.umh.medicalbookingplatform.core.model.i18n.I18nString
import com.umh.medicalbookingplatform.core.properties.ApplicationProperties
import com.umh.medicalbookingplatform.core.utils.ApplicationJsonObjectMapper
import com.umh.medicalbookingplatform.core.utils.LocaleUtils
import com.umh.medicalbookingplatform.core.utils.RestTemplateUtils
import org.apache.commons.lang3.StringUtils
import org.bson.Document
import org.keycloak.admin.client.Keycloak
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.ResponseEntity
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext

@Component
class GlobalCmsSynchronizationTask : BackgroundTaskExecutor() {
    private val logger = LoggerFactory.getLogger(this.javaClass)

    @PersistenceContext
    private lateinit var em: EntityManager

    @Autowired
    private lateinit var apiCmsInvokeService: ApiCmsInvokeService

    @Scheduled(fixedRate = 1000 * 1)
    @Transactional(rollbackFor = [Exception::class])
    fun startTask() {
        super.startTask(BackgroundTask.BackgroundTaskCode.GLOBAL_CMS_SYNCHRONIZATION_TASK)
    }

    override fun run() {
        val param = DoctorListParam()
        apiCmsInvokeService.getDoctorList(param)
    }
}

api模块-service(如果输入特殊字符,tomcat会拦截并报错,此时需要后端转义!!!!)

package com.umh.medicalbookingplatform.api.service

import com.umh.medicalbookingplatform.api.model.*
import com.umh.medicalbookingplatform.core.model.doctor.DoctorListDto
import com.umh.medicalbookingplatform.core.model.doctor.DoctorListParam
import com.umh.medicalbookingplatform.core.model.doctor.DoctorsDto
import com.umh.medicalbookingplatform.core.model.doctor.Language
import io.swagger.v3.oas.annotations.Operation
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Pageable
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.stereotype.Service
import java.util.regex.Pattern

/**
 * @Description :
 * @Author xiaomh
 * @create 2021/9/8 14:22
 */

@Service
class ApiDoctorService {

    @Autowired
    private lateinit var apiCmsInvokeService: ApiCmsInvokeService

    @Autowired
    private lateinit var apiBookingInvokeService: ApiBookingInvokeService

    @Autowired
    private lateinit var mongoTemplate: MongoTemplate

    fun getDoctorListToMongoDB(param: DoctorListParam): DoctorListDto {
        val query = Query()
        val dto = DoctorListDto()
        /*  关键字  */
        if (param.searchKey?.isNotEmpty() == true){
            //val pattern=Pattern.compile("^.*${param.searchKey}.*$", Pattern.CASE_INSENSITIVE)//此处代码是有问题的,当有特殊字符如[等,会报错,需进行转换!!!
            val pattern=Pattern.compile("^.*${Pattern.quote(param.searchKey)}.*$", Pattern.CASE_INSENSITIVE)
            query.addCriteria(Criteria.where("doctorName.value").regex(pattern))
        }
        /*  商店id  */
        if (param.shopId?.isNotEmpty() == true){
            query.addCriteria(Criteria.where("shops.shopId").`is`(param.shopId))
        }
        /*  品牌id  */
        if (param.brandId?.isNotEmpty() == true){
            query.addCriteria(Criteria.where("brands.brandId").`is`(param.brandId))
        }

        /*  专科id  */
        if (param.specialtyId?.isNotEmpty() == true) {
            val ids = param.specialtyId!!.replace("%2C",",")
            val split = ids.split(",")
            query.addCriteria(Criteria.where("specialties.specialtyId").`in`(split))
        }
        /*  地区id  */
        if (param.regionId?.isNotEmpty() == true) {
            val ids = param.regionId!!.replace("%2C",",")
            val split = ids.split(",")
            query.addCriteria(Criteria.where("shops.regionId").`in`(split))
        }
        /*  医疗劵id  */
        if (param.medicalTicket?.isNotEmpty() == true) {
            query.addCriteria(Criteria.where("medicalTicket").`is`(param.medicalTicket))
        }
        /*  起始诊金id  */
        if (param.startHospitalFee?.isNotEmpty() == true) {
            query.addCriteria(Criteria.where("hospitalFee").gt(param.startHospitalFee!!.toInt()))
        }
        /*  语言id  */
        if (param.languageId?.isNotEmpty() == true) {
            val ids = param.languageId!!.replace("%2C",",")
            val split = ids.split(",")
            query.addCriteria(Criteria.where("languages.languageId").`in`(split))
        }
        /*  医生性别  */
        if (param.gender?.isNotEmpty() == true) {
            val ids = param.gender!!.replace("%2C",",")
            val split = ids.split(",")
            query.addCriteria(Criteria.where("gender").`in`(split));
        }
        //此处一定要先查总数再放置分页条件
        val count = mongoTemplate.count(query ,DoctorsDto::class.java, "doctors")
        /*  分页  */
        if (param.page != null && param.pageSize != null) {
            query.skip((param.page!!) * (param.pageSize!!))
            query.limit(param.pageSize!!)
        }
        query.with(Sort.by(Sort.Order.desc("doctorName.value")))

        val list = mongoTemplate.find(query , DoctorsDto::class.java, "doctors")
        dto.content = list
        dto.total = count.toInt()
        return dto
    }

}
Criteria criteria = new Criteria();
criteria.andOperator(Criteria.where("create_time").gte(beginDate),Criteria.where("create_time").lte(endDate));
query.addCriteria(criteria);
>=和<=的查询写法

在自测的情况下,输入[]等特殊字符串还是会报错,但如果把特殊字符“[”变成同等意思的%5B,就可以实现转义

字段查询:db.getCollection("doctors").find({"doctorId":"32"}) 

 注意!!如果浮点数为字符串,使用大于小于等查询会不准确

 

 数组查询:db.getCollection("doctors").find({"specialties.specialtyId":"32"})   

非常谢谢“Felix”哥(客户)提供的测试demo

    @RequestMapping(value = ["/test"], method = [RequestMethod.GET])
    @Throws(Exception::class)
    fun test(page : Long,size : Int): Any {

        val objectMapper = ApplicationJsonObjectMapper()

        /*
        插入數據
         */
//        val obj = mapOf(
//            "test" to "test",
//            "inner_test" to mapOf(
//                "value" to "123456"
//            )
//        )
//        val json = objectMapper.writeValueAsString(obj)
//        val doc = Document.parse(json)
//        mongoTemplate.insert(doc, "doctors")

        /*
        搜索
         */
//        val query = Query()
//        query.addCriteria(Criteria.where("inner_test.value").regex(".*345.*", "i"));
//        val list = mongoTemplate.find(query, Object::class.java, "doctors")


        var name = "刘"
        val query = Query()
//        val ids = arrayListOf<String>()
//        ids.add(id)
        val pattern= Pattern.compile("^.*${name}.*$", Pattern.CASE_INSENSITIVE)
        query.addCriteria(Criteria.where("doctorName.value").regex(pattern))
        val list = mongoTemplate.find(query ,Object::class.java, "doctors")


        return list


    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值