package cn.flightfeather.supervision.lightshare.service.Impl
|
|
import cn.flightfeather.supervision.common.net.WXHttpService
|
import cn.flightfeather.supervision.common.wx.SHA1
|
import cn.flightfeather.supervision.common.wx.WxConfig
|
import cn.flightfeather.supervision.domain.entity.LogMsgSubscribeWx
|
import cn.flightfeather.supervision.domain.entity.MsgSubscribeWx
|
import cn.flightfeather.supervision.domain.entity.UserInfoWx
|
import cn.flightfeather.supervision.domain.entity.Userinfo
|
import cn.flightfeather.supervision.domain.mapper.*
|
import cn.flightfeather.supervision.lightshare.service.WxUserService
|
import cn.flightfeather.supervision.lightshare.vo.AccessToken
|
import cn.flightfeather.supervision.lightshare.vo.AccessTokenPW
|
import cn.flightfeather.supervision.lightshare.vo.AccessTokenWX
|
import cn.flightfeather.supervision.lightshare.vo.BaseResponse
|
import com.alibaba.fastjson.JSON
|
import com.alibaba.fastjson.JSONArray
|
import com.alibaba.fastjson.JSONObject
|
import org.slf4j.LoggerFactory
|
import org.springframework.stereotype.Service
|
import tk.mybatis.mapper.entity.Example
|
import java.util.*
|
|
@Service
|
class WxUserServiceImpl(
|
val userinfoMapper: UserinfoMapper,
|
val userInfoWxMapper: UserInfoWxMapper,
|
val userMapMapper: UserMapMapper,
|
val baseInfoMapper: BaseInfoMapper,
|
private val msgSubscribeWxMapper: MsgSubscribeWxMapper,
|
private val logMsgSubscribeWxMapper: LogMsgSubscribeWxMapper
|
): WxUserService {
|
|
private val LOGGER = LoggerFactory.getLogger(WxUserServiceImpl::class.java)
|
|
override fun loginWx(accessTokenWX: AccessTokenWX): BaseResponse<Userinfo> {
|
accessTokenWX.code ?: return BaseResponse(false, "登录凭证不能为空")
|
|
// return BaseResponse(false)
|
WXHttpService.code2Session(accessTokenWX.code!!)?.let {
|
val openid = it.first
|
val unionid = it.second
|
val user = userInfoWxMapper.selectByPrimaryKey(openid)
|
return if (user == null || user.uiOpenId == null) {
|
val newUserWx = UserInfoWx().apply {
|
// uiGuid = UUIDGenerator.generate16ShortUUID()
|
uiOpenId = openid
|
uiNickName = accessTokenWX.nickName
|
uiGender
|
uiCountry
|
uiProvince
|
uiCity
|
uiAvatarUrl = accessTokenWX.avatarUrl
|
uiUnionid = unionid
|
}
|
// val newUser = Userinfo().apply {
|
// guid = newUserWx.uiGuid
|
// headIconUrl = newUserWx.uiAvatarUrl
|
// acountname
|
// realname = newUserWx.uiNickName
|
// password
|
// usertypeid = UserType.Enterprise.value.toByte()
|
// usertype = UserType.Enterprise.des
|
// isenable = true
|
// wechatid = newUserWx.uiOpenId
|
// }
|
var r = userInfoWxMapper.insert(newUserWx)
|
// r += userinfoMapper.insert(newUser)
|
return if (r == 1) {
|
BaseResponse(true, "微信用户注册成功")
|
} else {
|
BaseResponse(false, "微信用户注册失败")
|
}
|
} else {
|
if (user.uiGuid != null) {
|
val userinfo = userinfoMapper.selectByPrimaryKey(user.uiGuid)
|
BaseResponse(true, "微信用户登录成功", data = userinfo)
|
} else {
|
BaseResponse(true, "微信用户未绑定企业")
|
}
|
}
|
}
|
|
return BaseResponse(false, "请求失败, 无法访问微信接口")
|
}
|
|
override fun loginPw(accessTokenPW: AccessTokenPW): AccessToken {
|
//1. 账号密码登录时,将附带的微信id与账号绑定
|
if (!accessTokenPW.userName.isNullOrBlank() && !accessTokenPW.password.isNullOrBlank()) {
|
val user = userinfoMapper.selectByExample(Example(Userinfo::class.java).apply {
|
createCriteria().andEqualTo("acountname", accessTokenPW.userName)
|
.andEqualTo("password",accessTokenPW.password)
|
})
|
if (user.isEmpty()) return AccessToken()
|
|
val result = AccessToken()
|
//1.1 微信id为空,直接登录; 微信id不为空,绑定至账号
|
if (!accessTokenPW.code.isNullOrBlank()) {
|
val baseInfo = baseInfoMapper.selectByPrimaryKey(user[0].guid)
|
WXHttpService.code2Session(accessTokenPW.code!!)?.let {
|
val openid = it.first
|
val unionid = it.second
|
val userWx = userInfoWxMapper.selectByPrimaryKey(openid)
|
result.openId = openid
|
return@let if (userWx == null || userWx.uiOpenId == null) {
|
val newUserWx = UserInfoWx().apply {
|
uiGuid = user[0].guid
|
ciGuid = baseInfo?.ciGuid
|
uiOpenId = openid
|
uiNickName = accessTokenPW.nickName
|
uiGender
|
uiCountry
|
uiProvince
|
uiCity
|
uiAvatarUrl = accessTokenPW.avatarUrl
|
uiUnionid = unionid
|
}
|
userInfoWxMapper.insert(newUserWx)
|
} else if (userWx.uiGuid != user[0].guid) {
|
userWx.uiGuid = user[0].guid
|
userWx.ciGuid = baseInfo?.ciGuid
|
userInfoWxMapper.updateByPrimaryKey(userWx)
|
} else {
|
return@let
|
}
|
}
|
}
|
return result.apply {
|
userId = user[0].guid
|
val sUser = userMapMapper.selectByPrimaryKey(userId)
|
sUserId = sUser?.svUserId
|
success = true
|
}
|
}
|
//2. 当微信一键登录时,判断账号绑定情况
|
else if (!accessTokenPW.code.isNullOrBlank()) {
|
WXHttpService.code2Session(accessTokenPW.code!!)?.let {
|
val openid = it.first
|
val unionid = it.second
|
val userWx = userInfoWxMapper.selectByPrimaryKey(openid)
|
return if (userWx == null || userWx.uiOpenId == null) {
|
AccessToken()
|
} else {
|
val user = userinfoMapper.selectByPrimaryKey(userWx.uiGuid)
|
AccessToken().apply {
|
if (user?.guid == null) {
|
success = false
|
} else {
|
userId = user.guid
|
val sUser = userMapMapper.selectByPrimaryKey(userId)
|
sUserId = sUser?.svUserId
|
openId = openid
|
success = true
|
}
|
}
|
}
|
}
|
return AccessToken()
|
} else {
|
return AccessToken()
|
}
|
}
|
|
override fun subscribeCheck(signature: String, timestamp: String, nonce: String, echostr: String): String {
|
val s = SHA1.getSHA1(WxConfig.TOKEN, timestamp, nonce, "")
|
LOGGER.info("微信服务器验证,sha1:${s}")
|
return if (signature == s) {
|
LOGGER.info("success")
|
echostr
|
} else {
|
LOGGER.info("fail")
|
"fail"
|
}
|
}
|
|
override fun subscribeResult(msg: String): String{
|
println(msg)
|
|
val json = JSON.parseObject(msg)
|
//小程序原始id,不是APP_ID
|
val appName = (json["ToUserName"] as String?) ?: throw NullPointerException("微信服务器发送的订阅返回消息ToUserName字段为null")
|
if (appName != WxConfig.USER_NAME) throw IllegalStateException("小程序原始ID不匹配,微信[${appName}],服务器记录[${WxConfig.USER_NAME}]")
|
//用户openid
|
val openId = (json["FromUserName"] as String?) ?: throw NullPointerException("微信服务器发送的订阅返回消息FromUserName字段为null")
|
//时间戳
|
var createTime = (json["CreateTime"] as Int?)?.toLong() ?: throw NullPointerException("微信服务器发送的订阅返回消息CreateTime字段为null")
|
createTime = createTime.times(1000)//此处传过来的时间戳只精确到秒,转换为毫秒
|
//事件类型,此处应该都是event
|
val msgType = json["MsgType"] as String?
|
|
//各消息模板返回结果
|
val results = mutableListOf<JSONObject>()
|
val list = json["List"]
|
if (list is JSONArray) {
|
list.forEach {
|
if (it is JSONObject) {
|
results.add(it)
|
}
|
}
|
} else if (list is JSONObject) {
|
results.add(list)
|
}
|
val event = json["Event"]
|
if (event is String) {
|
when (event) {
|
//用户触发订阅消息弹框后的行为时间结果
|
//用户在手机端服务通知消息卡片右上角管理消息时的操作结果
|
"subscribe_msg_popup_event" ,
|
"subscribe_msg_change_event" -> {
|
results.forEach {
|
val templateId = it["TemplateId"] as String?
|
val sStatus = it["SubscribeStatusString"] as String?
|
//根据时间和用户openId,判断此次操作是否重复
|
val time = Date(createTime.toLong())
|
val records = msgSubscribeWxMapper.selectByExample(Example(MsgSubscribeWx::class.java).apply {
|
createCriteria().andEqualTo("msOpenId", openId)
|
.andEqualTo("msTemplateId", templateId)
|
})
|
//用户无订阅记录
|
if (records.isEmpty()) {
|
val m = MsgSubscribeWx().apply {
|
msTemplateId = templateId
|
msOpenId = openId
|
msUpdateTime = time
|
if (sStatus == WxConfig.S_ACCEPT) {
|
msCount = 1
|
msAccept = true
|
}else if (sStatus == WxConfig.S_REJECT) {
|
msCount = 0
|
msAccept = false
|
}
|
}
|
msgSubscribeWxMapper.insert(m)
|
}
|
//用户有订阅记录
|
else if (records.size == 1) {
|
//先排重
|
val r = records[0]
|
if (r != null && createTime > (r.msUpdateTime?.time ?: 0)) {
|
r.msUpdateTime = time
|
if (sStatus == WxConfig.S_ACCEPT) {
|
r.msCount += 1
|
r.msAccept = true
|
} else if (sStatus == WxConfig.S_REJECT) {
|
r.msAccept = false
|
}
|
msgSubscribeWxMapper.updateByPrimaryKey(r)
|
}
|
}
|
//用户单个模板有多条记录,错误
|
else {
|
throw IllegalStateException("用户[${openId}]微信订阅单条消息记录大于1")
|
}
|
}
|
}
|
//发送给用户订阅消息的返回结果
|
"subscribe_msg_sent_event" -> {
|
results.forEach {
|
val templateId = it["TemplateId"] as String?
|
val msgId = it["MsgID"] as String?
|
val eCode = it["ErrorCode"] as String?
|
val eStatus = it["ErrorStatus"] as String?
|
//推送成功后,该用户该条模板可用次数减一,并且记录推送日志
|
if (eCode == "0") {
|
val records = msgSubscribeWxMapper.selectByExample(Example(MsgSubscribeWx::class.java).apply {
|
createCriteria().andEqualTo("msOpenId", openId)
|
.andEqualTo("msTemplateId", templateId)
|
})
|
if (records.size != 1) throw IllegalStateException("微信用户[${openId}]模板[${templateId}]订阅次数记录缺失")
|
records[0]?.let { ms ->
|
ms.msCount--
|
msgSubscribeWxMapper.updateByPrimaryKey(ms)
|
}
|
|
//查找返回消息24小时之内的记录
|
// 一般情况下,主动推送消息后,微信服务器会立即返回对应的推送结果,所以应该只查询到一条没有lmsMsgId的记录,
|
// 或者在微信服务器重复发送的情况下,只查询到一条有对应lmsMsgId的记录,
|
val logs = logMsgSubscribeWxMapper.selectByExample(Example(LogMsgSubscribeWx::class.java).apply {
|
createCriteria().andEqualTo("lmsOpenId", openId)
|
.andEqualTo("lmsTemplateId", templateId)
|
and(
|
createCriteria().orIsNull("lmsMsgId").orEqualTo("lmsMsgId", msgId)
|
)
|
}).let { list->
|
var result = list
|
for (l in list) {
|
if (l?.lmsMsgId == msgId) {
|
result = emptyList()
|
break
|
}
|
}
|
result
|
}
|
if (logs.isNotEmpty()) {
|
val l = logs[0]
|
l?.lmsTime = Date()
|
l?.lmsMsgId = msgId
|
l?.lmsResult = true
|
logMsgSubscribeWxMapper.updateByPrimaryKey(l)
|
}
|
}
|
}
|
}
|
}
|
return "success"
|
} else {
|
return "fail"
|
}
|
}
|
}
|