WxController.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. package com.ylx.web.controller.massage;
  2. import cn.binarywang.wx.miniapp.api.WxMaService;
  3. import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
  4. import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  5. import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
  6. import cn.hutool.core.io.FileUtil;
  7. import cn.hutool.core.net.url.UrlBuilder;
  8. import cn.hutool.http.HttpUtil;
  9. import com.alibaba.fastjson.JSON;
  10. import com.alibaba.fastjson2.JSONObject;
  11. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  12. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  13. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  14. import com.ylx.common.annotation.Log;
  15. import com.ylx.common.config.RuoYiConfig;
  16. import com.ylx.common.constant.Constants;
  17. import com.ylx.common.core.controller.BaseController;
  18. import com.ylx.common.core.domain.AjaxResult;
  19. import com.ylx.common.core.domain.R;
  20. import com.ylx.common.core.domain.model.WxLoginUser;
  21. import com.ylx.common.enums.BusinessType;
  22. import com.ylx.common.utils.MessageUtils;
  23. import com.ylx.common.utils.file.FileUploadUtils;
  24. import com.ylx.common.utils.file.FileUtils;
  25. import com.ylx.framework.config.ServerConfig;
  26. import com.ylx.framework.manager.AsyncManager;
  27. import com.ylx.framework.manager.factory.AsyncFactory;
  28. import com.ylx.framework.web.service.WxTokenService;
  29. import com.ylx.massage.domain.CouponReceive;
  30. import com.ylx.massage.domain.vo.TWxUserVo;
  31. import com.ylx.massage.service.CouponReceiveService;
  32. import com.ylx.massage.service.TCommentService;
  33. import com.ylx.massage.service.TbFileService;
  34. import com.ylx.massage.utils.LocationUtil;
  35. import com.ylx.massage.utils.WxQrCodeUtil;
  36. import com.ylx.massage.utils.WxUtil;
  37. import com.ylx.massage.domain.TWxUser;
  38. import com.ylx.massage.service.TWxUserService;
  39. import io.swagger.annotations.Api;
  40. import io.swagger.annotations.ApiOperation;
  41. import lombok.extern.slf4j.Slf4j;
  42. import me.chanjar.weixin.common.error.WxErrorException;
  43. import org.apache.commons.lang3.StringUtils;
  44. import org.springframework.beans.BeanUtils;
  45. import org.springframework.beans.factory.annotation.Autowired;
  46. import org.springframework.http.MediaType;
  47. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  48. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  49. import org.springframework.web.bind.annotation.*;
  50. import org.springframework.web.multipart.MultipartFile;
  51. import javax.annotation.Resource;
  52. import javax.servlet.http.HttpServletResponse;
  53. import java.io.File;
  54. import java.io.IOException;
  55. import java.util.HashMap;
  56. import java.util.List;
  57. import java.util.Map;
  58. /**
  59. * @author : YJR
  60. * @className : WxController
  61. * @description : [描述说明该类的功能]
  62. * @createTime : 2023/6/27 19:44
  63. */
  64. @RestController
  65. @Api(tags = {"微信"})
  66. @RequestMapping("/wx")
  67. @Slf4j
  68. public class WxController extends BaseController {
  69. @Resource
  70. private WxUtil wxUtil;
  71. @Autowired
  72. private ServerConfig serverConfig;
  73. @Resource
  74. private WxQrCodeUtil wxQrCodeUtil;
  75. @Resource
  76. private TWxUserService wxUserService;
  77. @Resource
  78. private WxTokenService wxTokenService;
  79. @Autowired
  80. private WxMaService wxMaService;
  81. @Autowired
  82. private TbFileService tbFileService;
  83. @Autowired
  84. private CouponReceiveService couponReceiveService;
  85. @Resource(name = "commonAsyncExecutor")
  86. private ThreadPoolTaskExecutor threadPoolTaskExecutor;
  87. /**
  88. * 获取二维码
  89. *
  90. * @param inviteUserId
  91. * @return AjaxResult
  92. */
  93. @ApiOperation("获取二维码")
  94. @PostMapping(value="getwxQrCode")
  95. public AjaxResult inviteCode(@RequestParam ("inviteUserId")String inviteUserId) throws WxErrorException, IOException {
  96. File file = wxMaService.getQrcodeService().createWxaCodeUnlimit(inviteUserId, null, 300, true, null, true);
  97. MultipartFile multipartFile = FileUploadUtils.getMultipartFile(file);
  98. return tbFileService.uploadFile(multipartFile);
  99. }
  100. /**
  101. * 小程序登录
  102. *
  103. * @param wxLoginUser
  104. * @return
  105. */
  106. @PostMapping("v0/login")
  107. @ApiOperation("小程序登录不用")
  108. public AjaxResult login(@RequestBody WxLoginUser wxLoginUser) {
  109. AjaxResult ajax = new AjaxResult();
  110. try {
  111. // 验证输入数据的合法性
  112. if (wxLoginUser == null || wxLoginUser.getCode() == null || wxLoginUser.getCode().isEmpty()) {
  113. return AjaxResult.error("输入数据不合法");
  114. }
  115. //todo 获取用户信息自测方法
  116. WxLoginUser wxUser = wxUtil.getUserOpenId(wxLoginUser.getCode());
  117. if (wxUser == null) {
  118. return AjaxResult.error("获取用户信息失败");
  119. }
  120. // 生成并返回令牌
  121. String token = wxTokenService.createToken(wxUser);
  122. if (token == null || token.isEmpty()) {
  123. return AjaxResult.error("生成令牌失败");
  124. }
  125. ajax.put(Constants.TOKEN, token);
  126. return ajax;
  127. } catch (Exception e) {
  128. // 捕获并处理异常,返回友好的错误信息
  129. JSONObject errorObj = new JSONObject();
  130. errorObj.put("message", "操作失败");
  131. errorObj.put("error", e.getMessage());
  132. return AjaxResult.error(JSON.toJSONString(errorObj));
  133. }
  134. }
  135. /**
  136. * 获取电话号
  137. *
  138. * @param param
  139. * @return
  140. */
  141. @ApiOperation("获取电话号")
  142. @RequestMapping(value = "getPhone", method = RequestMethod.POST)
  143. public R getPhone(@RequestBody JSONObject param) {
  144. String code = param.getString("code");
  145. String openId = param.getString("openId");
  146. if (StringUtils.isBlank(code)) {
  147. return R.fail("openId或者授权conde为空");
  148. }
  149. String phone = wxUtil.getUserPhone(openId, code);
  150. if (StringUtils.isBlank(phone)) {
  151. return R.fail("获取手机号信息失败,请重试");
  152. }
  153. return R.ok(phone);
  154. }
  155. /**
  156. * 获取用户信息
  157. *
  158. * @param
  159. * @return
  160. */
  161. @ApiOperation("获取用户信息")
  162. @Log(title = "获取用户信息", businessType = BusinessType.OTHER)
  163. @RequestMapping(value = "getUserInfo", method = RequestMethod.GET)
  164. public R getUserInfo() {
  165. WxLoginUser wxLoginUser = getWxLoginUser();
  166. // 检查wxLoginUser是否为null
  167. if (wxLoginUser == null) {
  168. return R.fail("用户登录信息不存在");
  169. }
  170. LambdaQueryWrapper<TWxUser> queryWrapper = new LambdaQueryWrapper<TWxUser>()
  171. .eq(TWxUser::getcOpenid, wxLoginUser.getCOpenid());
  172. TWxUser wxUser;
  173. try {
  174. wxUser = wxUserService.getOne(queryWrapper);
  175. } catch (Exception e) {
  176. log.error("获取用户信息失败", e);
  177. return R.fail("获取用户信息失败,系统异常");
  178. }
  179. if (wxUser == null) {
  180. return R.fail("用户信息不存在");
  181. }
  182. // 移除用户登录的session key
  183. wxUser.setcSessionKey(null);
  184. return R.ok(wxUser);
  185. }
  186. /**
  187. * 获取用户信息
  188. *
  189. * @param param
  190. * @return
  191. */
  192. @RequestMapping(value = "getUser", method = RequestMethod.POST)
  193. public List<TWxUser> getUser(@RequestBody JSONObject param) {
  194. QueryWrapper<TWxUser> wrapper = new QueryWrapper<>();
  195. return wxUserService.list(wrapper);
  196. }
  197. @RequestMapping(value = "select", method = RequestMethod.GET)
  198. public R select(Page<TWxUser> page, TWxUser user) {
  199. LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
  200. objectLambdaQueryWrapper.eq(StringUtils.isNotBlank(user.getcOpenid()), TWxUser::getcOpenid, user.getcOpenid()).
  201. like(StringUtils.isNotBlank(user.getcNickName()), TWxUser::getcNickName, user.getcNickName());
  202. // 获取查询返回结果
  203. Page<TWxUser> pageSelect = wxUserService.page(page, objectLambdaQueryWrapper);
  204. return R.ok(pageSelect);
  205. }
  206. /**
  207. * 登录接口
  208. * @param code
  209. * @param encryptedData
  210. * @param iv
  211. * @param parentOpenId
  212. * @return R<Object>
  213. */
  214. @ApiOperation("小程序登录")
  215. @Log(title = "小程序登录", businessType = BusinessType.OTHER)
  216. @PostMapping("/login")
  217. public R<Object> login(@RequestParam("code") String code, @RequestParam("encryptedData") String encryptedData,
  218. @RequestParam("iv") String iv, @RequestParam(required = false, value = "parentOpenId") String parentOpenId) {
  219. try {
  220. // 调用微信 API 获取用户的 openid 和 session_key
  221. WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
  222. String openid = session.getOpenid();
  223. // 调用微信 API 获取用户的手机号
  224. WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNoInfo(session.getSessionKey(), encryptedData, iv);
  225. String phoneNumber = phoneInfo.getPhoneNumber();
  226. // 调用微信 API 获取用户的详细信息
  227. WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
  228. // 获取用户昵称
  229. String nickName = userInfo.getNickName();
  230. // 获取用户头像
  231. String avatarUrl = userInfo.getAvatarUrl();
  232. // 获取用户国家
  233. String country = userInfo.getCountry();
  234. // 获取用户省份
  235. String province = userInfo.getProvince();
  236. // 获取用户城市
  237. String city = userInfo.getCity();
  238. // 将用户信息保存到数据库中
  239. LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
  240. objectLambdaQueryWrapper.eq(TWxUser::getcOpenid, openid);
  241. TWxUser user = wxUserService.getOne(objectLambdaQueryWrapper);
  242. if (user == null) {
  243. BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
  244. user = new TWxUser();
  245. user.setcOpenid(openid);
  246. user.setcNickName(nickName);
  247. user.setcIcon(avatarUrl);
  248. user.setcPhone(phoneNumber);
  249. user.setCPassword(encoder.encode("123456")) ;
  250. wxUserService.save(user);
  251. //异步 添加新人优惠卷
  252. TWxUser finalUser = user;
  253. // threadPoolTaskExecutor.submit(() -> couponReceiveService.submit(new CouponReceive().setOpenid(finalUser.getcOpenid()).setCouponId("1")));
  254. user.setId(user.getId());
  255. }
  256. WxLoginUser wxUser = new WxLoginUser();
  257. BeanUtils.copyProperties(user, wxUser);
  258. // 生成并返回令牌
  259. String token = wxTokenService.createToken(wxUser);
  260. if (token == null || token.isEmpty()) {
  261. return R.fail("生成令牌失败");
  262. }
  263. wxUser.setToken(token);
  264. // 返回用户信息
  265. // 记录登录信息
  266. AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
  267. return R.ok(wxUser);
  268. } catch (WxErrorException e) {
  269. log.error("登录失败:" + e.getMessage(), e);
  270. return R.fail("登录失败:" + e.getMessage());
  271. }
  272. }
  273. /**
  274. * 更新用户信息接口
  275. */
  276. @PostMapping("/update")
  277. public R updateUserInfo(@RequestBody TWxUser user) {
  278. try {
  279. // 前端校验后,再次进行后端的基础校验
  280. if (user == null || user.getcOpenid() == null || user.getcOpenid().isEmpty()) {
  281. return R.fail("用户信息不能为空");
  282. }
  283. // 保存或更新用户信息
  284. if (wxUserService.saveOrUpdate(user)) {
  285. return R.ok("用户信息更新成功");
  286. } else {
  287. return R.fail("更新用户信息失败");
  288. }
  289. } catch (Exception e) {
  290. // 异常处理,记录日志并返回友好的错误信息
  291. log.error("更新用户信息异常", e);
  292. return R.fail("更新用户信息异常,请稍后尝试");
  293. }
  294. }
  295. /**
  296. * 获取微信用户手机号
  297. *
  298. * @param code code值
  299. */
  300. public String getMobilePhoneByWeixin(String code) {
  301. try {
  302. String accessToken = wxMaService.getAccessToken();
  303. String url = UrlBuilder
  304. .of("https://api.weixin.qq.com/wxa/business/getuserphonenumber")
  305. .addQuery("access_token", accessToken)
  306. .build();
  307. Map<String, Object> paramBody = new HashMap<>(2);
  308. paramBody.put("code", code);
  309. String result = HttpUtil.post(url, JSON.toJSONString(paramBody));
  310. JSONObject jsonObject = JSONObject.from(JSON.parseObject(result));
  311. if ("40029".equals(jsonObject.getString("errcode"))) {
  312. throw new RuntimeException("code无效");
  313. }
  314. if ("-1".equals(jsonObject.getString("errcode"))) {
  315. throw new RuntimeException("微信系统繁忙");
  316. }
  317. JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
  318. return phoneInfo.getString("phoneNumber");
  319. } catch (WxErrorException e) {
  320. e.printStackTrace();
  321. throw new RuntimeException("获取手机号失败");
  322. }
  323. }
  324. /**
  325. * 查询微信用户列表
  326. *
  327. * @param page 分页参数
  328. * @param user
  329. * @return R<Page<TWxUser>> 微信用户列表
  330. */
  331. @GetMapping("pc/getUserList")
  332. @ApiOperation("查询微信用户列表")
  333. public R<Page<TWxUser>> getUserList(Page<TWxUser> page, TWxUser user) {
  334. Page<TWxUser> pageSelect = wxUserService.page(page, new LambdaQueryWrapper<TWxUser>()
  335. .like(StringUtils.isNotBlank(user.getcNickName()), TWxUser::getcNickName, user.getcNickName())
  336. .like(StringUtils.isNotBlank(user.getcPhone()), TWxUser::getcPhone, user.getcPhone())
  337. .orderByDesc(TWxUser::getCreateTime));
  338. return R.ok(pageSelect);
  339. }
  340. }