院后微信小程序登录和个人信息接口开发完成

This commit is contained in:
纪寒 2024-04-16 14:17:14 +08:00
parent f098cd7d26
commit 07a2b6177b
10 changed files with 437 additions and 2 deletions

View File

@ -103,7 +103,7 @@ token:
# 令牌有效期默认30分钟
expireTime: 30
# 请求拦截白名单
ant-matchers: /postDischarge/**,/testMobile/**
ant-matchers: /postDischarge/**,/testMobile/**,/postDischargeApplet/**
## MyBatis-Plus配置
mybatis-plus:

View File

@ -283,4 +283,34 @@ public class Constants {
* 成功
*/
public static final int SUCCESS_ERROR_CODE = 0;
/**
* 院后微信小程序登录接口地址
*/
public static final String APPLET_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
/**
* 微信小程序ACCESS_TOKEN前缀
*/
public static final String POST_DISCHARGE_APPLET_ACCESS_TOKEN = "POST_Discharge_APPLET_ACCESS_TOKEN_";
/**
* 返回成功状态码
*/
public static final int SUCCESS_CODE = 0;
/**
* 院后微信小程序获取用户手机号接口地址
*/
public static final String PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
/**
* 获取微信小程序access_token错误码
*/
public static final int ERROR_ACCESS_CODE = 40001;
/**
* 返回成功状态码
*/
public static final String OK = "ok";
}

View File

@ -1,6 +1,8 @@
package com.xinelu.manage.mapper.residentinfo;
import com.xinelu.manage.domain.residentinfo.ResidentInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -17,7 +19,7 @@ public interface ResidentInfoMapper {
* @param id 居民信息主键
* @return 居民信息
*/
public ResidentInfo selectResidentInfoById(Long id);
ResidentInfo selectResidentInfoById(Long id);
/**
* 查询居民信息列表
@ -58,4 +60,13 @@ public interface ResidentInfoMapper {
* @return 结果
*/
int deleteResidentInfoByIds(Long[] ids);
/**
* 根据电话号码和微信小程序openid查询居民基本信息
*
* @param phone 手机号
* @param openId 微信小程序openId
* @return 被护理人基本信息
*/
ResidentInfo getResidentInfoByPhoneAndOpenId(@Param("phone") String phone, @Param("openId") String openId);
}

View File

@ -183,4 +183,18 @@
#{id}
</foreach>
</delete>
<select id="getResidentInfoByPhoneAndOpenId" parameterType="string"
resultType="com.xinelu.manage.domain.residentinfo.ResidentInfo">
<include refid="selectResidentInfoVo" />
<where>
del_flag = 0
<if test="phone != null and phone != ''">
and patient_phone = #{phone}
</if>
<if test="openId != null and openId != ''">
and open_id = #{openId}
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,54 @@
package com.xinelu.mobile.controller.appletpersoncenter;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.mobile.service.appletpersoncenter.AppletPersonCenterService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Description 院后小程序个人中心控制器
* @Author 纪寒
* @Date 2024-04-16 10:49:14
* @Version 1.0
*/
@RestController
@RequestMapping("/postDischargeApplet")
public class AppletPersonCenterController {
@Resource
private AppletPersonCenterService appletPersonCenterService;
/**
* 院后微信小程序一键登录接口
*
* @param loginCode 登录凭证
* @param phoneCode 获取手机号登录凭证
* @return 微信小程序用户登录信息
*/
@GetMapping("/appletLogin")
public AjaxResult appletLogin(@RequestParam("loginCode") String loginCode, @RequestParam("phoneCode") String phoneCode) {
if (StringUtils.isBlank(loginCode)) {
return AjaxResult.error("登录凭证编码不能为空!");
}
if (StringUtils.isBlank(phoneCode)) {
return AjaxResult.error("用户手机号凭证不存在");
}
return appletPersonCenterService.appletLogin(loginCode, phoneCode);
}
/**
* 根据居民表id查询患者个人信息
*
* @param residentId 居民表id
* @return 个人信息
*/
@GetMapping("/getResidentInfoById")
public AjaxResult getResidentInfoById(Long residentId) {
return appletPersonCenterService.getResidentInfoById(residentId);
}
}

View File

@ -0,0 +1,29 @@
package com.xinelu.mobile.service.appletpersoncenter;
import com.xinelu.common.core.domain.AjaxResult;
/**
* @Description 院后小程序个人中心业务层
* @Author 纪寒
* @Date 2024-04-16 10:51:28
* @Version 1.0
*/
public interface AppletPersonCenterService {
/**
* 院后微信小程序一键登录接口
*
* @param loginCode 登录凭证
* @param phoneCode 获取手机号登录凭证
* @return 微信小程序用户登录信息
*/
AjaxResult appletLogin(String loginCode, String phoneCode);
/**
* 根据居民表id查询患者个人信息
*
* @param residentId 居民表id
* @return 个人信息
*/
AjaxResult getResidentInfoById(Long residentId);
}

View File

@ -0,0 +1,123 @@
package com.xinelu.mobile.service.appletpersoncenter.Impl;
import com.xinelu.common.config.WeChatAppletChatConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.manage.domain.residentinfo.ResidentInfo;
import com.xinelu.manage.mapper.residentinfo.ResidentInfoMapper;
import com.xinelu.mobile.service.appletpersoncenter.AppletPersonCenterService;
import com.xinelu.mobile.utils.WeChatAppletUtils;
import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletPhoneVO;
import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* @Description 院后小程序个人中心业务层实现类
* @Author 纪寒
* @Date 2024-04-16 10:52:09
* @Version 1.0
*/
@Service
@Slf4j
public class AppletPersonCenterServiceImpl implements AppletPersonCenterService {
@Resource
private WeChatAppletUtils weChatAppletUtils;
@Resource
private WeChatAppletChatConfig weChatAppletChatConfig;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private ResidentInfoMapper residentInfoMapper;
/**
* 院后微信小程序一键登录接口
*
* @param loginCode 登录凭证
* @param phoneCode 获取手机号登录凭证
* @return 微信小程序用户登录信息
*/
@Override
public AjaxResult appletLogin(String loginCode, String phoneCode) {
//根据code获取用户的微信unionId以及openId等信息
PostDischargeAppletVO appletLoginInfo = weChatAppletUtils.getPostDischargeAppletLogin(weChatAppletChatConfig.getAppletId(), weChatAppletChatConfig.getSecret(), loginCode, weChatAppletChatConfig.getGrantType());
if (Objects.isNull(appletLoginInfo)) {
return AjaxResult.error("获取院后微信小程序用户信息失败");
}
if (Objects.nonNull(appletLoginInfo.getErrcode()) && appletLoginInfo.getErrcode() != Constants.SUCCESS_CODE) {
return AjaxResult.error("获取院后微信小程序用户信息失败,失败信息为:" + appletLoginInfo.getErrmsg());
}
//获取微信accessToken
String accessToken;
String accessTokenKey = Constants.POST_DISCHARGE_APPLET_ACCESS_TOKEN + "accessToken";
//从Redis中取出accessToken
Object object = redisTemplate.opsForValue().get(accessTokenKey);
if (Objects.isNull(object)) {
accessToken = weChatAppletUtils.getWeChatAppletAccessToken();
} else {
accessToken = (String) object;
}
//获取用户手机号
PostDischargeAppletPhoneVO appletPhoneInfo = weChatAppletUtils.getPostDischargeAppletPhone(phoneCode, accessToken);
if (Objects.isNull(appletPhoneInfo)) {
return AjaxResult.error("获取用户手机号失败");
}
if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == Constants.ERROR_ACCESS_CODE) {
//当前Redis缓存中的access_token无效直接删除
if (Objects.nonNull(object)) {
redisTemplate.delete(accessTokenKey);
//删除之后重新获取获取accessToken
accessToken = weChatAppletUtils.getWeChatAppletAccessToken();
appletPhoneInfo = weChatAppletUtils.getPostDischargeAppletPhone(phoneCode, accessToken);
if (Objects.isNull(appletPhoneInfo)) {
return AjaxResult.error("获取用户手机号失败");
}
if (Objects.nonNull(appletPhoneInfo.getErrcode()) && appletPhoneInfo.getErrcode() == Constants.ERROR_ACCESS_CODE) {
return AjaxResult.error("登录失败!");
}
}
}
if (StringUtils.isNotBlank(appletPhoneInfo.getErrmsg()) && !Constants.OK.equals(appletPhoneInfo.getErrmsg())) {
return AjaxResult.error("获取用户手机号失败,失败信息为:" + appletPhoneInfo.getErrmsg());
}
//根据手机号和微信小程序openid判断当前用户是否存在
String phone = StringUtils.isBlank(appletPhoneInfo.getPhoneInfo().getPhoneNumber()) ? "" : appletPhoneInfo.getPhoneInfo().getPhoneNumber();
String openId = StringUtils.isBlank(appletLoginInfo.getOpenid()) ? "" : appletLoginInfo.getOpenid();
ResidentInfo residentInfoByPhone = residentInfoMapper.getResidentInfoByPhoneAndOpenId(null, openId);
ResidentInfo residentInfo = new ResidentInfo();
//居民信息为空新增个人信息
if (Objects.isNull(residentInfoByPhone)) {
residentInfo.setOpenId(openId);
residentInfo.setPatientPhone(phone);
residentInfo.setCreateTime(LocalDateTime.now());
residentInfoMapper.insertResidentInfo(residentInfo);
residentInfo.setId(residentInfo.getId());
return AjaxResult.success(residentInfo);
}
//更新居民信息的openid等微信标识信息
residentInfo.setId(residentInfoByPhone.getId());
residentInfo.setOpenId(openId);
residentInfo.setPatientPhone(StringUtils.isBlank(residentInfoByPhone.getPatientPhone()) ? "" : residentInfoByPhone.getPatientPhone());
residentInfo.setUpdateTime(LocalDateTime.now());
residentInfoMapper.updateResidentInfo(residentInfo);
return AjaxResult.success(residentInfo);
}
/**
* 根据居民表id查询患者个人信息
*
* @param residentId 居民表id
* @return 个人信息
*/
@Override
public AjaxResult getResidentInfoById(Long residentId) {
return AjaxResult.success(residentInfoMapper.selectResidentInfoById(residentId));
}
}

View File

@ -6,11 +6,15 @@ import com.xinelu.common.constant.Constants;
import com.xinelu.common.entity.AccessToken;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.http.HttpUtils;
import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletPhoneVO;
import com.xinelu.mobile.vo.appletpersoncenter.PostDischargeAppletVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@ -68,4 +72,50 @@ public class WeChatAppletUtils {
}
return accessToken;
}
/**
* 根据登录编码获取微信小程序用户信息
*
* @param appletId 小程序id
* @param secret 小程序秘钥
* @param code 登录凭证码
* @param grantType 授权类型
* @return 登录信息
*/
public PostDischargeAppletVO getPostDischargeAppletLogin(String appletId, String secret, String code, String grantType) {
//请求地址
String appletLoginUrl = Constants.APPLET_LOGIN_URL
+ "?appid=" + appletId
+ "&secret=" + secret
+ "&js_code=" + code
+ "&grant_type=" + grantType;
//发送请求
String result = HttpUtils.sendGet(appletLoginUrl);
if (StringUtils.isBlank(result)) {
throw new ServiceException("获取院后微信小程序用户信息失败", 201);
}
return JSON.parseObject(result, PostDischargeAppletVO.class);
}
/**
* 获取院后微信小程序的手机号码
*
* @param code 登录凭证
* @param accessToken 小程序accessToken
* @return 手机信息
*/
public PostDischargeAppletPhoneVO getPostDischargeAppletPhone(String code, String accessToken) {
//请求地址
String phoneUrl = Constants.PHONE_NUMBER_URL + accessToken;
//请求参数
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("code", code);
String param = JSON.toJSONString(paramMap);
//发送POST请求
String result = HttpUtils.sendPostJson(phoneUrl, param);
if (StringUtils.isBlank(result)) {
throw new ServiceException("获取院后微信小程序手机号失败", 201);
}
return JSON.parseObject(result, PostDischargeAppletPhoneVO.class);
}
}

View File

@ -0,0 +1,85 @@
package com.xinelu.mobile.vo.appletpersoncenter;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Description 获取小程序用户手机号实体类
* @Author 纪寒
* @Date 2024-04-16 11:15:53
* @Version 1.0
*/
@NoArgsConstructor
@Data
public class PostDischargeAppletPhoneVO implements Serializable {
private static final long serialVersionUID = 7053513139462975391L;
/**
* 错误编码
* 0成功
* -1系统繁忙此时请开发者稍候再试
* 40029不合法的codecode不存在已过期或者使用过
*/
@JsonProperty("errcode")
private Integer errcode;
/**
* 返回提示信息ok成功
*/
@JsonProperty("errmsg")
private String errmsg;
/**
* 电话信息实体类
*/
@JsonProperty("phone_info")
private PhoneInfoDTO phoneInfo;
@NoArgsConstructor
@Data
public static class PhoneInfoDTO {
/**
* 用户绑定的手机号国外手机号会有区号
*/
@JsonProperty("phoneNumber")
private String phoneNumber;
/**
* 没有区号的手机号
*/
@JsonProperty("purePhoneNumber")
private String purePhoneNumber;
/**
* 区号
*/
@JsonProperty("countryCode")
private Integer countryCode;
/**
* 数据水印
*/
@JsonProperty("watermark")
private WatermarkDTO watermark;
@NoArgsConstructor
@Data
public static class WatermarkDTO {
/**
* 用户获取手机号操作的时间戳
*/
@JsonProperty("timestamp")
private Integer timestamp;
/**
* 小程序appid
*/
@JsonProperty("appid")
private String appid;
}
}
}

View File

@ -0,0 +1,39 @@
package com.xinelu.mobile.vo.appletpersoncenter;
import lombok.Data;
import java.io.Serializable;
/**
* @Description 院后微信小程序用户信息实体类
* @Author 纪寒
* @Date 2024-04-16 10:56:22
* @Version 1.0
*/
@Data
public class PostDischargeAppletVO implements Serializable {
private static final long serialVersionUID = 9163624256938346478L;
/**
* 小程序unionid
*/
private String unionid;
/**
* 小程序openid
*/
private String openid;
/**
* 错误状态码40029js_code无效45011API 调用太频繁请稍候再试
* 40226高风险等级用户小程序登录拦截 -1系统繁忙此时请开发者稍候再试
*/
private Integer errcode;
/**
* 状态信息取值有40029code 无效
* 45011api minute-quota reach limit mustslower retry next minute
* 40226code blocked
* -1system error
*/
private String errmsg;
}