123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- package com.rf.psychological.wxpay.controller;
- import cn.hutool.core.date.DateUtil;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.google.gson.Gson;
- import com.google.gson.internal.LinkedTreeMap;
- import com.rf.psychological.base.rest.BaseController;
- import com.rf.psychological.enums.UserRole;
- import com.rf.psychological.group.service.GroupInfoService;
- import com.rf.psychological.security.AesEncryptUtils;
- import com.rf.psychological.security.SafetyProcess;
- import com.rf.psychological.user.dao.model.OpenIdEntity;
- import com.rf.psychological.user.dao.model.UserEntity;
- import com.rf.psychological.user.service.OpenidService;
- import com.rf.psychological.user.service.UserService;
- import com.rf.psychological.utils.Constant;
- import com.rf.psychological.utils.IPUtiles;
- import com.rf.psychological.utils.JWTUtil;
- import com.rf.psychological.utils.Result;
- import com.rf.psychological.wxpay.config.WxPayConfig;
- import com.rf.psychological.wxpay.service.WxPayService;
- import com.rf.psychological.wxpay.utils.HttpUtils;
- import com.rf.psychological.wxpay.utils.WechatPay2ValidatorForRequest;
- import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang.StringUtils;
- import org.apache.http.client.methods.CloseableHttpResponse;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.entity.StringEntity;
- import org.apache.http.impl.client.CloseableHttpClient;
- import org.apache.http.util.EntityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.web.bind.annotation.*;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * @Description:微信支付接口
- * @Author: zsf
- * @Date: 2022/6/21
- */
- @CrossOrigin //跨域
- @RestController
- @RequestMapping("/api/wx-pay")
- @Api(tags = "网站微信支付APIv3")
- @Slf4j
- @ConditionalOnProperty(prefix="wx.pay",name = "is_lan", havingValue = "false")
- public class WxPayController extends BaseController {
- @Autowired
- private WxPayService wxPayService;
- @Autowired
- private WxPayConfig wxPayConfig;
- @Autowired
- private Verifier verifier;
- @Autowired
- private OpenidService openidService;
- @Resource
- private CloseableHttpClient wxPayClient;
- @Autowired
- private UserService userService;
- @Autowired
- private GroupInfoService groupInfoService;
- /**
- * 调用统一下单API,生成支付二维码
- * @return
- */
- @SafetyProcess
- @ApiOperation(value = "调用统一下单API,生成支付二维码",notes = "json字符串形式传参(加密)," +
- "data参数中包括(必传):productId:量表id,userId:用户id,resultId:测试结果id,description:订单描述信息," +
- "total:订单总金额,单位为分;")
- @PostMapping("/native")
- public Result<Map<String,Object>> nativePay(@RequestBody String paramJson){
- try {
- log.info(paramJson);
- String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(paramJson).getString("data"));
- log.info(paramData);
- if (StringUtils.isEmpty(paramData)){
- return fail(null,"参数不能为空");
- }
- Map<String,Object> map = wxPayService.nativePay(JSON.parseObject(paramData));
- return success(map);
- }catch (Exception e){
- e.printStackTrace();
- return fail("二维码生成失败");
- }
- }
- /**
- * h5下单API,生成支付二维码
- * @return
- */
- @SafetyProcess
- @ApiOperation(value = "h5下单API,生成支付二维码",notes = "json字符串形式传参(加密)," +
- "data参数中包括(必传):productId:量表id,userId:用户id,resultId:测试结果id,description:订单描述信息," +
- "payerClientIp:用户的客户端IP,支持IPv4和IPv6两种格式的IP地址,sceneType:场景类型ios、Android," +
- "total:订单总金额,单位为分")
- @PostMapping("/h5Pay")
- public Result h5Pay(@RequestBody String paramJson, HttpServletRequest request) throws Exception {
- try {
- String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(paramJson).getString("data"));
- log.info("paramData:"+paramData);
- if (StringUtils.isEmpty(paramData)){
- return fail(null,"参数不能为空");
- }
- //获取必要参数
- JSONObject paramObject = JSONObject.parseObject(paramData);
- //获取ip
- String payerClientIp = IPUtiles.getRealIp(request);
- paramObject.put("payerClientIp",payerClientIp);
- Map result = wxPayService.h5Pay(paramObject);
- return success(result);
- }catch (Exception e){
- e.printStackTrace();
- return fail("h5_url生成失败");
- }
- }
- @SafetyProcess
- @ApiOperation(value = "小程序预下单",notes = "参数同native下单")
- @PostMapping("/aspiPay")
- public Result aspiPay(@RequestBody String json){
- log.info("json请求参数:{}",json);
- try {
- String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data"));
- if (StringUtils.isEmpty(paramData)){
- return fail(null,"参数不能为空");
- }
- //获取必要参数
- JSONObject paramObject = JSONObject.parseObject(paramData);
- if(!paramObject.containsKey("openId")||StringUtils.isBlank(paramObject.getString("openId"))){
- UserEntity userEntity = userService.findUserById(paramObject.getString("userId"));
- // OpenIdEntity openIdEntity = this.openidService.findByUserId(paramObject.getString("userId"));
- if(userEntity == null){
- return fail("用户未登录");
- }
- paramObject.put("openId",userEntity.getPhone());
- }
- Map result = wxPayService.aspiPay(paramObject);
- return success(result);
- }catch (Exception e){
- e.printStackTrace();
- return fail("生成失败");
- }
- }
- @SafetyProcess
- @ApiOperation(value = "JSAPI支付",notes = "参数同native下单")
- @PostMapping("/jsapiPay")
- public Result jsapiPay(@RequestBody String json){
- log.info("json请求参数:{}",json);
- try {
- String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data"));
- if (StringUtils.isEmpty(paramData)){
- return fail(null,"参数不能为空");
- }
- //获取必要参数
- JSONObject paramObject = JSONObject.parseObject(paramData);
- Map result = wxPayService.jsapiPay(paramObject);
- return success(result);
- }catch (Exception e){
- e.printStackTrace();
- return fail("生成失败");
- }
- }
- /**
- * 支付通知 微信支付通过支付通知接口将用户支付成功消息通知给商户
- * @param request
- * @param response
- * @return
- */
- @ApiOperation("支付通知")
- @PostMapping("/native/notify")
- public String nativeNotify(HttpServletRequest request, HttpServletResponse response){
- log.info("支付通知====================================================");
- Gson gson = new Gson();
- Map<String,Object> map = new HashMap<>();
- //处理通知参数
- try {
- String body = HttpUtils.readData( request);
- Map<String,Object> bodyMap = gson.fromJson(body, HashMap.class);
- String requestId = (String)bodyMap.get("id");
- log.info("支付通知的id ===> {}", requestId);
- log.info("支付通知的完整数据 ===> {}", body);
- //签名的验证
- WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
- = new WechatPay2ValidatorForRequest(verifier, requestId, body);
- if(!wechatPay2ValidatorForRequest.validate(request)){
- log.error("通知验签失败");
- //失败应答
- response.setStatus(500);
- map.put("code", "ERROR");
- map.put("message", "通知验签失败");
- return gson.toJson(map);
- }
- log.info("通知验签成功");
- //处理订单
- wxPayService.processOrder(bodyMap);
- //成功应答
- response.setStatus(200);
- map.put("code", "SUCCESS");
- map.put("message", "成功");
- return gson.toJson(map);
- }catch (Exception e){
- e.printStackTrace();
- //失败应答
- response.setStatus(500);
- map.put("code", "ERROR");
- map.put("message", "失败");
- return gson.toJson(map);
- }
- }
- /**
- * 用户取消订单
- * @param orderNo
- * @return
- * @throws Exception
- */
- @ApiOperation("用户取消订单-PC")
- @GetMapping("/cancel/{orderNo}")
- public Result cancel(@PathVariable String orderNo) throws Exception {
- log.info("取消订单");
- wxPayService.cancelOrder(orderNo);
- return success(null,"订单已取消");
- }
- @SafetyProcess
- @ApiOperation("查询订单")
- @GetMapping("/queryOrder/{orderNo}")
- public Result queryOrder(@PathVariable String orderNo) throws Exception {
- log.info("查询订单订单");
- return success( wxPayService.queryOrder(orderNo));
- }
- @ApiOperation("交易账单--暂未开发")
- @GetMapping("/queryTradeBill/{billDate}/{type}")
- public Result queryTradeBill(@PathVariable String billDate, @PathVariable String type){
- return success();
- }
- @GetMapping("/refund/{orderNo}")
- public Result refund(@PathVariable String orderNo) throws IOException {
- wxPayService.refund(orderNo);
- return success();
- }
- // @PostMapping("/code2openid")
- // @ApiOperation(value = "code 换 opernid",notes = "modelPhone:手机号;code:临时code,获取openid;petName:用户名")
- // @SafetyProcess
- // public Result<JSONObject> code2id(@RequestBody String json) throws Exception {
- // JSONObject resultJson = new JSONObject();
- // JSONObject data = JSONObject.parseObject(AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data")));
- // OpenIdEntity openIdEntity = this.openidService.findByPhone(data.getString("modelPhone"));
- // if(openIdEntity == null){
- // CloseableHttpResponse response = getToken(data.getString("code"));
- // int statusCode = response.getStatusLine().getStatusCode();//响应状态码
- // String body = EntityUtils.toString(response.getEntity());
- // Gson gson = new Gson();
- // HashMap resultBody = gson.fromJson(body, HashMap.class);
- // if(statusCode == 200 || statusCode == 204){
- // openIdEntity = new OpenIdEntity();
- // openIdEntity.setOpenId((String) resultBody.get("openid"));
- // openIdEntity.setAuthType("vx");
- // }else{
- // log.error("获取openid失败:错误码 "+resultBody.get("errcode")+" "+resultBody.get("errmsg"));
- // log.error("错误码:{}",resultBody.get("errcode"));
- // log.error("错误消息:{}",resultBody.get("errmsg"));
- // return fail();
- // }
- // }
- // //静默注册登录
- // UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(data.getString("modelPhone"), Constant.WEB_INSTITUTION_CODE, UserRole.COMMON.getType());
- // if(userEntity != null){
- // openIdEntity.setUserId(userEntity.getId());
- // openIdEntity.setPhone(data.getString("modelPhone"));
- // openIdEntity = this.openidService.save(openIdEntity);
- //
- // if(StringUtils.isNotBlank(data.getString("petName"))&&(!userEntity.getPetName().equals(data.getString("petName")))){
- // userEntity.setPetName(data.getString("petName"));
- // this.userService.save(userEntity);
- // }
- // userEntity.setPassword("-");
- // resultJson.put("user", userEntity);
- // resultJson.put("type", userEntity.getRoleType());
- // resultJson.put("improve",false);
- // }else{
- // //注册
- // userEntity = new UserEntity();
- // userEntity.setPassword("-");
- // userEntity.setModelPhone(data.getString("modelPhone"));
- // userEntity.setGId(this.groupInfoService.findGroupByInstitutionNoAndName(Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_GROUP_NAME).getId());
- // userEntity.setInstitutionName(Constant.WEB_INSTITUTION_NAME);
- // userEntity.setInstitutionNo(Constant.WEB_INSTITUTION_CODE);
- // userEntity.setUserStatus(Constant.USER_STATUS_NORMAL);
- // userEntity.setBirthday("-");
- // userEntity.setGender("-");
- // userEntity.setPetName(data.getString("petName"));
- // userEntity.setProfession("-");
- // userEntity.setAdditionInfo("微信小程序注册用户");
- // userEntity.setPhone(data.getString("modelPhone"));
- // userEntity.setRoleType(UserRole.COMMON.getType());
- // userEntity = this.userService.save(userEntity);
- // resultJson.put("improve",true);
- // //保存三方授权信息 openid
- // openIdEntity.setUserId(userEntity.getId());
- // openIdEntity.setPhone(data.getString("modelPhone"));
- // openIdEntity = this.openidService.save(openIdEntity);
- // //登录
- //// TODO 将登录用户放入redis已登录用户信息,统计在线人数
- // }
- //
- // resultJson.put("token", JWTUtil.getTokenByUserInfo(userEntity));
- // resultJson.put("user",userEntity);
- // resultJson.put("type",userEntity.getRoleType());
- // resultJson.put("openId",openIdEntity);
- // log.info("响应消息:"+resultJson.toJSONString());
- // return success(resultJson);
- // }
- @PostMapping("/code2openid2")
- @ApiOperation(value = "code 换 opernid",notes = "code:临时code,获取openid;petName:用户名")
- @SafetyProcess
- public Result<JSONObject> code2openid2(@RequestBody String json) throws Exception {
- JSONObject resultJson = new JSONObject();
- JSONObject data = JSONObject.parseObject(AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data")));
- String openId;
- CloseableHttpResponse response = getToken(data.getString("code"));
- int statusCode = response.getStatusLine().getStatusCode();//响应状态码
- String body = EntityUtils.toString(response.getEntity());
- Gson gson = new Gson();
- HashMap resultBody = gson.fromJson(body, HashMap.class);
- if(statusCode == 200 || statusCode == 204){
- openId = (String) resultBody.get("openid");
- }else{
- log.error("获取openid失败:错误码 "+resultBody.get("errcode")+" "+resultBody.get("errmsg"));
- log.error("错误码:{}",resultBody.get("errcode"));
- log.error("错误消息:{}",resultBody.get("errmsg"));
- return fail();
- }
- //静默注册登录
- UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(openId, Constant.WEB_INSTITUTION_CODE, UserRole.COMMON.getType());
- if(userEntity != null){
- // if(StringUtils.isNotBlank(data.getString("petName"))&&(!userEntity.getPetName().equals(data.getString("petName")))){
- // userEntity.setPetName(data.getString("petName"));
- // this.userService.save(userEntity);
- // }
- userEntity.setPassword("-");
- resultJson.put("user", userEntity);
- resultJson.put("type", userEntity.getRoleType());
- resultJson.put("improve",false);
- }else{
- //注册
- userEntity = new UserEntity();
- userEntity.setPassword("-");
- userEntity.setGId(this.groupInfoService.findGroupByInstitutionNoAndName(Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_GROUP_NAME).getId());
- userEntity.setInstitutionName(Constant.WEB_INSTITUTION_NAME);
- userEntity.setInstitutionNo(Constant.WEB_INSTITUTION_CODE);
- userEntity.setUserStatus(Constant.USER_STATUS_NORMAL);
- userEntity.setBirthday("-");
- userEntity.setGender("-");
- userEntity.setPetName("微信用户");
- userEntity.setProfession(DateUtil.now());
- userEntity.setAdditionInfo("微信小程序注册用户");
- userEntity.setPhone(openId);
- userEntity.setRoleType(UserRole.COMMON.getType());
- userEntity = this.userService.save(userEntity);
- resultJson.put("improve",true);
- }
- resultJson.put("token", JWTUtil.getTokenByUserInfo(userEntity));
- resultJson.put("user",userEntity);
- resultJson.put("type",userEntity.getRoleType());
- resultJson.put("openId",openId);
- log.info("响应消息:"+resultJson.toJSONString());
- return success(resultJson);
- }
- @GetMapping("/getPhone/{code}")
- @SafetyProcess
- @ApiOperation(value = "获取用户手机号",notes = "code :临时code")
- public Result getPhone(@PathVariable String code) throws IOException {
- // 1、获取access_token
- String access_token = wxPayService.getAccessToken();
- // 2、获取用户手机号
- HashMap map = getPhoneNumber(code,access_token);
- int errcode = ((Number) map.get("errcode")).intValue();
- if(errcode == 0){
- //{"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"19138984495","purePhoneNumber":"19138984495","countryCode":"86","watermark":{"timestamp":1661308946,"appid":"wx2f422a2a1cb24c3c"}}}
- LinkedTreeMap map2 = (LinkedTreeMap) map.get("phone_info");
- String phoneNumber = String.valueOf(map2.get("phoneNumber"));
- if(StringUtils.isBlank(phoneNumber)){
- phoneNumber = String.valueOf(map2.get("purePhoneNumber"));
- }
- JSONObject resultJson = new JSONObject();
- resultJson.put("phone",phoneNumber);
- UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(phoneNumber,Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_VALUE_ONE);
- if(userEntity != null){
- resultJson.put("newer","0");
- }else {
- resultJson.put("newer","1");
- }
- return success(resultJson);
- }else if (errcode == -1){
- return fail("系统繁忙");
- }else if (errcode == 40029){
- log.info("code 不合法");
- return fail("获取手机号失败");
- }else {
- log.info("获取手机号失败错误码:{},错误消息{}",errcode,map.get("errmsg"));
- return fail("获取手机号失败");
- }
- }
- /**
- * 获取
- * @param code
- * @param access_token
- * @return
- */
- private HashMap getPhoneNumber(String code, String access_token) throws IOException {
- String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+access_token;
- HttpPost httpPost = new HttpPost(url);
- httpPost.setHeader("Accept", "application/json");
- Map<String,Object> paramsMap = new HashMap<>();
- paramsMap.put("code",code);
- Gson gson = new Gson();
- String jsonParams = gson.toJson(paramsMap);
- StringEntity entity = new StringEntity(jsonParams,"utf-8");
- entity.setContentType("application/json");
- httpPost.setEntity(entity);
- httpPost.setHeader("Accept","application/json");
- CloseableHttpResponse response = wxPayClient.execute(httpPost);
- String body = EntityUtils.toString(response.getEntity());//获取响应体
- log.info("获取手机号:响应体{}",body);
- //响应结果
- return gson.fromJson(body,HashMap.class);
- }
- /**
- * 获取access_token
- * @return
- * @throws IOException
- */
- // public String getAccessToken() throws IOException {
- // String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+wxPayConfig.getAspi_appid()+"&secret="+wxPayConfig.getAspi_secret() ;
- // HttpGet httpGet = new HttpGet(url);
- // CloseableHttpResponse response = wxPayClient.execute(httpGet);
- // String body = EntityUtils.toString(response.getEntity());
- // Gson gson = new Gson();
- // HashMap resultBody = gson.fromJson(body, HashMap.class);
- // if(resultBody.containsKey("errcode")){
- // log.error("获取token异常:");
- // log.error("errcode:"+resultBody.get("errcode"));
- // log.error("errmsg:"+resultBody.get("errmsg"));
- // }else{
- // return (String) resultBody.get("access_token");
- // }
- // return null;
- // }
- public CloseableHttpResponse getToken(String code) throws IOException {
- String url = wxPayConfig.getAspi_url() +
- "?appid=" + wxPayConfig.getAspi_appid() +
- "&secret=" + wxPayConfig.getAspi_secret() +
- "&js_code=" + code +
- "&grant_type=authorization_code";
- log.info("code2openid URL :"+url);
- HttpGet httpGet = new HttpGet(url);
- httpGet.setHeader("Accept", "application/json");
- return wxPayClient.execute(httpGet);
- }
- @GetMapping("/generateShortLink")
- @ApiOperation(value = "获取到分享链接",notes = "path:跳转路径和参数")
- public Result generateShortLink(@RequestParam String path,@RequestParam String query){
- try {
- if (StringUtils.isEmpty(path)){
- return fail(null,"参数不能为空");
- }
- String link = wxPayService.generateLink(path,query);
- return success(link);
- }catch (Exception e){
- e.printStackTrace();
- return fail("操作失败");
- }
- }
- @GetMapping("/generateWxCode")
- @SafetyProcess
- @ApiOperation(value = "获取到小程序",notes = "page:跳转路径scene参数envVersion环境")
- public Result generateWxCode(@RequestParam String page,@RequestParam String scene,@RequestParam(required = false) String envVersion){
- try {
- if (StringUtils.isEmpty(page)){
- return fail(null,"参数不能为空");
- }
- String link = wxPayService.generateWxCode(page,scene,envVersion);
- return success(link);
- }catch (Exception e){
- e.printStackTrace();
- return fail("操作失败");
- }
- }
- }
|