package com.agentdriving.user.modular.system.service.impl; import com.agentdriving.user.core.common.constant.JwtConstants; import com.agentdriving.user.core.shiro.ShiroKit; import com.agentdriving.user.core.shiro.ShiroUser; import com.agentdriving.user.core.util.JwtTokenUtil; import com.agentdriving.user.core.util.ToolUtil; import com.agentdriving.user.modular.system.dao.AppUserMapper; import com.agentdriving.user.modular.system.model.*; import com.agentdriving.user.modular.system.service.*; import com.agentdriving.user.modular.system.warpper.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.agentdriving.user.modular.system.util.PayMoneyUtil; import com.agentdriving.user.modular.system.util.RedisUtil; import com.agentdriving.user.modular.system.util.ResultUtil; import com.agentdriving.user.modular.system.util.UUIDUtil; import com.agentdriving.user.modular.system.util.weChat.WXCore; import com.agentdriving.user.modular.system.util.weChat.WeChatUtil; import com.agentdriving.user.modular.system.util.weChat.model.Code2Session; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; /** * 用户 */ @Service public class AppUserServiceImpl extends ServiceImpl implements IAppUserService { @Autowired private WeChatUtil weChatUtil; @Autowired private RedisUtil redisUtil; private final String salt = "s5d1"; @Autowired private ICouponService couponService; @Autowired private IUserToCouponService userToCouponService; @Autowired private IRechargeRecordService rechargeRecordService; @Autowired private PayMoneyUtil payMoneyUtil; @Autowired private IAccountChangeDetailService accountChangeDetailService; @Value("${callbackPath}") private String callbackPath;//支付回调网关地址 @Value("${wx.appletsAppid}") private String appletsAppid; @Override public ResultUtil appUserLogin(String jscode) throws Exception { Code2Session code2Session = weChatUtil.code2Session(jscode); if(null != code2Session.getErrcode() && code2Session.getErrcode() != 0){ return ResultUtil.error(code2Session.getErrmsg()); } String openid = code2Session.getOpenid(); AppUser appUser = this.selectOne(new EntityWrapper().eq("openid", openid).eq("status", 1)); if(null == appUser){ return ResultUtil.error("无效的账号"); } String token = getToken(appUser); if(ToolUtil.isEmpty(token)){ return ResultUtil.error("获取身份凭证失败"); } return ResultUtil.success(token); } /** * 获取身份凭证 * @return */ public String getToken(AppUser appUser){ //封装请求账号密码为shiro可验证的token String phone = appUser.getPhone(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(phone, phone.toCharArray()); String credentials = ShiroKit.md5(phone, salt); ByteSource credentialsSalt = new Md5Hash(salt); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo( new ShiroUser(), credentials, credentialsSalt, ""); //校验用户账号密码 HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher(); md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName); md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations); boolean passwordTrueFlag = md5CredentialsMatcher.doCredentialsMatch( usernamePasswordToken, simpleAuthenticationInfo); if (passwordTrueFlag) { String token = JwtTokenUtil.generateToken(phone); String key = token; if(token.length() > 16){ key = token.substring(token.length() - 16); } redisUtil.setStrValue(key, appUser.getId().toString(), 7 * 24 * 60 * 60); redisUtil.setStrValue("USER_" + appUser.getPhone(), key, 7 * 24 * 60 * 60); return token; } return null; } /** * 微信授权注册登录 * @param signInToRegister * @return * @throws Exception */ @Override public ResultUtil signInToRegister(SignInToRegister signInToRegister) throws Exception { SignInToRegisterWarpper warpper = new SignInToRegisterWarpper(); if(ToolUtil.isEmpty(signInToRegister.getJscode())){ return ResultUtil.paranErr("jscode"); } if(ToolUtil.isEmpty(signInToRegister.getEncryptedDataPhone())){ return ResultUtil.paranErr("encryptedDataPhone"); } if(ToolUtil.isEmpty(signInToRegister.getIvPhone())){ return ResultUtil.paranErr("ivPhone"); } Code2Session code2Session = weChatUtil.code2Session(signInToRegister.getJscode()); if(null != code2Session.getErrcode() && code2Session.getErrcode() != 0){ return ResultUtil.error(code2Session.getErrmsg()); } String openid = code2Session.getOpenid(); String session_key = code2Session.getSession_key(); String decrypt = WXCore.decrypt(signInToRegister.getEncryptedDataPhone(), session_key, signInToRegister.getIvPhone()); if(ToolUtil.isEmpty(decrypt)){ return ResultUtil.error("获取手机号失败"); } JSONObject phone = JSON.parseObject(decrypt); String purePhoneNumber = phone.getString("purePhoneNumber"); AppUser appUser = this.selectOne(new EntityWrapper().eq("phone", purePhoneNumber).ne("status", 3)); if(null == appUser){ appUser = new AppUser(); appUser.setNickname("亲爱的用户"); appUser.setAvatar("https://fanghuadaijia.obs.cn-southwest-2.myhuaweicloud.com:443/img%2Fc68f32a7e78e4ef1b0c018fd2c15d7a7.png"); appUser.setPhone(purePhoneNumber); appUser.setOpenid(openid); appUser.setUnionid(code2Session.getUnionid()); appUser.setAccountBalance(0D); appUser.setStatus(1); appUser.setCreateTime(new Date()); appUser.setIsException(1); appUser.setInviterId(signInToRegister.getInviterId()); appUser.setInviterType(signInToRegister.getInviterType()); this.insert(appUser); //发送优惠券 boolean lock = redisUtil.lock(5); if(!lock){ int num1 = 1; while (num1 <= 10){ Thread.sleep(3000);//等待3秒 lock = redisUtil.lock(5); if(lock){ break; }else{ num1++; } } } if(lock){ List list = pushCoupon(appUser.getId()); redisUtil.unlock(); warpper.setCoupons(list); } } if(appUser.getStatus() == 2){ return ResultUtil.error("账号被冻结"); } String token = getToken(appUser); if(ToolUtil.isEmpty(token)){ return ResultUtil.error("获取身份凭证失败"); } warpper.setToken(token); return ResultUtil.success(warpper); } /** * 发送优惠券 * @param userId */ public List pushCoupon(Integer userId){ List coupons = couponService.selectList(new EntityWrapper().eq("coupon_type", 2) .eq("coupon_state", 1).eq("status", 1).gt("remaining_quantity", 0)); List list = new ArrayList<>(); for (Coupon coupon : coupons) { UserToCoupon userToCoupon = new UserToCoupon(); userToCoupon.setCouponId(coupon.getId()); userToCoupon.setCreateTime(new Date()); userToCoupon.setUserId(userId); userToCoupon.setStatus(1); userToCoupon.setCouponTotal(coupon.getCouponSendQuantity() > coupon.getRemainingQuantity() ? coupon.getRemainingQuantity() : coupon.getCouponSendQuantity()); userToCoupon.setValidCount(userToCoupon.getCouponTotal()); userToCoupon.setExpireTime(new Date(System.currentTimeMillis() + (coupon.getCouponValidity().longValue() * 24L * 60L * 60L * 1000L))); userToCouponService.insert(userToCoupon); coupon.setRemainingQuantity(coupon.getCouponSendQuantity() > coupon.getRemainingQuantity() ? 0 : coupon.getRemainingQuantity() - coupon.getCouponSendQuantity()); couponService.updateById(coupon); CouponWarpper couponWarpper = new CouponWarpper(); couponWarpper.setCouponConditionalAmount(coupon.getCouponConditionalAmount()); couponWarpper.setCouponPreferentialAmount(coupon.getCouponPreferentialAmount()); couponWarpper.setCouponName(coupon.getCouponName()); couponWarpper.setNumber(userToCoupon.getValidCount()); couponWarpper.setExpirationDate(userToCoupon.getExpireTime().getTime()); list.add(couponWarpper); } return list; } @Override public Integer getUserByRequest() throws Exception { ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = servletRequestAttributes.getRequest(); String requestHeader = request.getHeader(JwtConstants.AUTH_HEADER); if (ToolUtil.isNotEmpty(requestHeader) && requestHeader.startsWith("Bearer ")) { requestHeader = requestHeader.substring(requestHeader.indexOf(" ") + 1); String key = null; int length = requestHeader.length(); if(length > 16){ key = requestHeader.substring(length - 16); }else{ key = requestHeader; } String value = redisUtil.getValue(key); return null != value ? Integer.valueOf(value) : null; }else{ return null; } } /** * 修改个人信息 * @param userInfo * @return * @throws Exception */ @Override public ResultUtil updateUserInfo(Integer uid, UserInfo userInfo) throws Exception { AppUser appUser = this.selectById(uid); if(ToolUtil.isNotEmpty(userInfo.getAvatar())){ appUser.setAvatar(userInfo.getAvatar()); } if(ToolUtil.isNotEmpty(userInfo.getEmergencyContact())){ appUser.setEmergencyContact(userInfo.getEmergencyContact()); } if(ToolUtil.isNotEmpty(userInfo.getEmergencyPhone())){ appUser.setEmergencyPhone(userInfo.getEmergencyPhone()); } if(ToolUtil.isNotEmpty(userInfo.getNickname())){ appUser.setNickname(userInfo.getNickname()); } if(ToolUtil.isNotEmpty(userInfo.getPhone())){ if(userInfo.getPhone().equals(appUser.getPhone())){ return ResultUtil.error("新手机不能和原手机号相同"); } String value = redisUtil.getValue("+86" + userInfo.getPhone()); if(ToolUtil.isEmpty(value) || !value.equals(userInfo.getCode())){ return ResultUtil.error("验证码无效"); } appUser.setPhone(userInfo.getPhone()); } this.updateById(appUser); return ResultUtil.success(); } /** * 余额充值 * @param uid * @param amount * @return * @throws Exception */ @Override public ResultUtil rechargeBalance(Integer uid, Double amount) throws Exception { if(0 >= amount){ return ResultUtil.error("充值金额必须大于0"); } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); String out_trade_no = sdf.format(new Date()) + UUIDUtil.getNumberRandom(3); AppUser appUser = this.selectById(uid); RechargeRecord rechargeRecord = new RechargeRecord(); rechargeRecord.setType(1); rechargeRecord.setUserId(uid); rechargeRecord.setCode(out_trade_no); rechargeRecord.setAmount(amount); rechargeRecord.setCreateTime(new Date()); rechargeRecord.setPayStatus(1); rechargeRecord.setPayType(1); rechargeRecordService.insert(rechargeRecord); ResultUtil weixinpay = payMoneyUtil.weixinpay("余额充值", "", out_trade_no, amount.toString(), "/base/appUser/rechargeBalanceCallback", "JSAPI", appUser.getOpenid()); if(weixinpay.getCode() == 200){ new Thread(new Runnable() { @Override public void run() { try { int num = 1; int wait = 0; while (num <= 10) { int min = 5000; wait += (min * num); RechargeRecord rechargeRecord1 = rechargeRecordService.selectById(rechargeRecord.getId()); if (rechargeRecord1.getPayStatus() == 2) { return; } ResultUtil> resultUtil = payMoneyUtil.queryWXOrder(out_trade_no, ""); if (resultUtil.getCode() == 200) { /** * 订单状态 * SUCCESS—支付成功, * REFUND—转入退款, * NOTPAY—未支付, * CLOSED—已关闭, * REVOKED—已撤销(刷卡支付), * USERPAYING--用户支付中, * PAYERROR--支付失败(其他原因,如银行返回失败) */ Map data2 = resultUtil.getData(); String s = data2.get("state"); String transaction_id = data2.get("transaction_id"); if ("REFUND".equals(s) || "NOTPAY".equals(s) || "CLOSED".equals(s) || "REVOKED".equals(s) || "PAYERROR".equals(s)) { //回退 return; } if ("SUCCESS".equals(s)) { rechargeRecord1.setPayStatus(2); rechargeRecord1.setPayTime(new Date()); rechargeRecord1.setOrderNumber(transaction_id); rechargeRecordService.updateById(rechargeRecord1); AppUser appUser1 = AppUserServiceImpl.this.selectById(rechargeRecord1.getUserId()); AccountChangeDetail accountChangeDetail = new AccountChangeDetail(); accountChangeDetail.setCode(System.currentTimeMillis() + UUIDUtil.getNumberRandom(3)); accountChangeDetail.setUserType(1); accountChangeDetail.setUserId(appUser1.getId()); accountChangeDetail.setCreateTime(new Date()); accountChangeDetail.setOldData(appUser1.getAccountBalance()); accountChangeDetail.setType(1); accountChangeDetail.setChangeType(3); accountChangeDetail.setExplain("余额充值"); appUser1.setAccountBalance(appUser1.getAccountBalance() + rechargeRecord1.getAmount()); accountChangeDetail.setNewData(appUser1.getAccountBalance()); AppUserServiceImpl.this.updateById(appUser1); accountChangeDetailService.insert(accountChangeDetail); return; } if ("USERPAYING".equals(s)) { Thread.sleep(wait); num++; } }else{ Thread.sleep(wait); num++; } if(10 == num){ rechargeRecordService.deleteById(rechargeRecord1.getId()); } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } return weixinpay; } /** * 余额充值回调 * @param out_trade_no * @param transaction_id * @return * @throws Exception */ @Override public void rechargeBalanceCallback(String out_trade_no, String transaction_id) throws Exception { RechargeRecord rechargeRecord1 = rechargeRecordService.selectOne(new EntityWrapper().eq("code", out_trade_no)); if(rechargeRecord1.getPayStatus() != 1){ return; } AppUser appUser = this.selectById(rechargeRecord1.getUserId()); AccountChangeDetail accountChangeDetail = new AccountChangeDetail(); accountChangeDetail.setUserType(1); accountChangeDetail.setUserId(rechargeRecord1.getUserId()); accountChangeDetail.setCode(System.currentTimeMillis() + UUIDUtil.getNumberRandom(3)); accountChangeDetail.setChangeType(3); accountChangeDetail.setType(1); accountChangeDetail.setCreateTime(new Date()); accountChangeDetail.setExplain("余额充值"); accountChangeDetail.setOldData(appUser.getAccountBalance()); appUser.setAccountBalance(appUser.getAccountBalance() + rechargeRecord1.getAmount()); accountChangeDetail.setNewData(appUser.getAccountBalance()); this.updateById(appUser); accountChangeDetailService.saveData(accountChangeDetail); rechargeRecord1.setPayTime(new Date()); rechargeRecord1.setPayStatus(2); rechargeRecord1.setOrderNumber(transaction_id); rechargeRecordService.updateById(rechargeRecord1); } /** * 获取用户优惠券列表 * @param uid * @param state * @param pageNum * @param pageSize * @return * @throws Exception */ @Override public List queryMyCoupons(Integer uid, Integer state, Integer pageNum, Integer pageSize) throws Exception { return null; } }