xiao547607 пре 4 година
родитељ
комит
718ec17266

+ 67 - 0
web/src/main/java/com/jpsoft/employment/modules/pay/properties/AliPayProperties.java

@@ -0,0 +1,67 @@
+package com.jpsoft.employment.modules.pay.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 墨鱼_mo
+ * @date 2019-11-26 9:37
+ */
+
+@Data
+@ConfigurationProperties(prefix = "alipay")
+@Component
+public class AliPayProperties {
+
+
+    /**
+     * 支付宝网关
+     */
+    private String serviceUrl;
+
+    /**
+     * 应用appid
+     */
+    private String appId;
+
+    /**
+     * 应用私钥
+     */
+    private String privateKey;
+
+    /**
+     * 支付宝公钥
+     */
+    private String zfbPublicKey;
+
+    /**
+     * 编码
+     */
+    private String inputCharset;
+
+    /**
+     * 服务商id
+     */
+    private String mchId;
+
+    /**
+     * 授权token
+     */
+    private String appAuthToken;
+
+    /**
+     * 加密方式
+     */
+    private String signType;
+
+    /**
+     * 支付回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 商品描述
+     */
+    private String body;
+}

+ 68 - 0
web/src/main/java/com/jpsoft/employment/modules/pay/properties/ParkAliPayProperties.java

@@ -0,0 +1,68 @@
+package com.jpsoft.employment.modules.pay.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 墨鱼_mo
+ * @date 2020-4-16 15:05
+ */
+@Data
+@ConfigurationProperties(prefix = "parkalipay")
+@Component
+public class ParkAliPayProperties {
+
+    /**
+     * 支付宝网关
+     */
+    private String serviceUrl;
+
+    /**
+     * 应用appid
+     */
+    private String appId;
+
+    /**
+     * 应用私钥
+     */
+    private String privateKey;
+
+    /**
+     * 支付宝公钥
+     */
+    private String zfbPublicKey;
+
+    /**
+     * 编码
+     */
+    private String inputCharset;
+
+    /**
+     * 服务商id
+     */
+    private String mchId;
+
+    /**
+     * 授权token
+     */
+    private String appAuthToken;
+
+    /**
+     * 加密方式
+     */
+    private String signType;
+
+    /**
+     * 支付回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 商品描述
+     */
+    private String body;
+
+    private String format;
+
+}

+ 71 - 0
web/src/main/java/com/jpsoft/employment/modules/pay/properties/WxJpsoftProperties.java

@@ -0,0 +1,71 @@
+package com.jpsoft.employment.modules.pay.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 墨鱼_mo
+ * @date 2019-11-26 9:35
+ */
+
+@Data
+@ConfigurationProperties(prefix = "wx.jpsoft")
+@Component
+public class WxJpsoftProperties {
+
+    /**
+     * 设置微信公众号或者小程序等的appid
+     */
+    private String appId;
+
+    /**
+     * 设置微信公众号或者小程序等的appSecret
+     */
+    private String appSecret;
+
+    /**
+     * 微信支付商户号
+     */
+    private String mchId;
+
+    /**
+     * 微信支付商户密钥
+     */
+    private String mchKey;
+
+    /**
+     * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
+     */
+    private String subAppId;
+
+    /**
+     * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
+     */
+    private String subMchId;
+
+    /**
+     * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
+     */
+    private String keyPath;
+
+    /**
+     * 回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 发起ip
+     */
+    private String ip;
+
+    /**
+     * 商品描述
+     */
+    private String body;
+
+    /**
+     * 页面跳转标识
+     */
+    private String urlKey;
+}

+ 71 - 0
web/src/main/java/com/jpsoft/employment/modules/pay/properties/WxPayProperties.java

@@ -0,0 +1,71 @@
+package com.jpsoft.employment.modules.pay.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author 墨鱼_mo
+ * @date 2019-11-26 9:35
+ */
+
+@Data
+@ConfigurationProperties(prefix = "wx.pay")
+@Component
+public class WxPayProperties {
+
+    /**
+     * 设置微信公众号或者小程序等的appid
+     */
+    private String appId;
+
+    /**
+     * 设置微信公众号或者小程序等的appSecret
+     */
+    private String appSecret;
+
+    /**
+     * 微信支付商户号
+     */
+    private String mchId;
+
+    /**
+     * 微信支付商户密钥
+     */
+    private String mchKey;
+
+    /**
+     * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
+     */
+    private String subAppId;
+
+    /**
+     * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
+     */
+    private String subMchId;
+
+    /**
+     * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
+     */
+    private String keyPath;
+
+    /**
+     * 回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 发起ip
+     */
+    private String ip;
+
+    /**
+     * 商品描述
+     */
+    private String body;
+
+    /**
+     * 前端页面url
+     */
+    private String portalUrl;
+}

+ 85 - 0
web/src/main/java/com/jpsoft/employment/modules/wechat/callback/EventCallback.java

@@ -0,0 +1,85 @@
+package com.jpsoft.employment.modules.wechat.callback;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Data
+public class EventCallback {
+    private String code;
+    private String callbackUrl;
+    private String message;
+
+    public EventCallback(){
+
+    }
+
+    public EventCallback(String code, String callbackUrl){
+        this.code = code;
+        this.callbackUrl = callbackUrl;
+//        this.message = message;
+    }
+
+    public boolean process(String wechatId, String openId, String eventKey){
+        boolean result = false;
+
+        try {
+            StringBuilder urlBuilder = new StringBuilder();
+
+            urlBuilder.append(this.callbackUrl);
+
+            HttpPost httpPost = new HttpPost(urlBuilder.toString());
+
+            RequestConfig requestConfig = RequestConfig.custom()
+                    .setSocketTimeout(5000)
+                    .setConnectTimeout(5000)
+                    .setConnectionRequestTimeout(5000)
+                    .build();
+
+            CloseableHttpClient httpClient = HttpClientBuilder.create()
+                    .setDefaultRequestConfig(requestConfig)
+                    .build();
+
+            List<NameValuePair> list = new ArrayList<NameValuePair>();
+            list.add(new BasicNameValuePair("eventKey", eventKey));
+            list.add(new BasicNameValuePair("wechatId", wechatId));
+            list.add(new BasicNameValuePair("openId", openId));
+
+            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
+            httpPost.setEntity(entity);
+
+            HttpResponse res = httpClient.execute(httpPost);
+
+            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                String content = EntityUtils.toString(res.getEntity());
+                this.setMessage(content);
+
+                result = true;
+            }
+            else{
+                this.setMessage("发送请求到业务平台失败!");
+            }
+        }
+        catch (Exception ex){
+            log.error(ex.getMessage(),ex);
+
+            result = false;
+            this.setMessage(ex.getMessage());
+        }
+
+        return result;
+    }
+}

+ 419 - 0
web/src/main/java/com/jpsoft/employment/modules/wechat/controller/WxController.java

@@ -0,0 +1,419 @@
+package com.jpsoft.employment.modules.wechat.controller;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.alipay.api.domain.CompanyInfo;
+import com.jpsoft.employment.config.WxConfig;
+import com.jpsoft.employment.modules.common.dto.MessageResult;
+import com.jpsoft.employment.modules.common.service.impl.RedisServiceImpl;
+import com.jpsoft.employment.modules.common.utils.Generator.CaptchaUtilA;
+import com.jpsoft.employment.modules.common.utils.Generator.CircleCaptchaA;
+import com.jpsoft.employment.modules.common.utils.SMSUtil;
+import com.jpsoft.employment.modules.common.utils.Sign;
+import com.jpsoft.employment.modules.common.utils.WeixinUtil;
+import com.jpsoft.employment.modules.job.entity.JobUser;
+import com.jpsoft.employment.modules.job.service.JobUserService;
+import com.jpsoft.employment.modules.pay.properties.WxPayProperties;
+import com.jpsoft.employment.modules.sys.entity.User;
+import com.jpsoft.employment.modules.sys.service.UserService;
+import com.jpsoft.employment.modules.wechat.callback.EventCallback;
+import com.jpsoft.employment.modules.wechat.entity.AccessToken;
+import com.jpsoft.employment.modules.wechat.vo.UserInfo;
+import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author 墨鱼_mo
+ * @date 2019-12-3 15:08
+ */
+
+@Slf4j
+@RequestMapping("/wechat")
+@RestController
+public class WxController {
+
+
+    @Autowired
+    private WxConfig wxConfig;
+
+
+    @Autowired
+    private ValueOperations<String, Object> valueOperations;
+
+    @Autowired
+    private RedisServiceImpl redisService;
+
+    @Autowired
+    private WxPayProperties wxPayProperties;
+
+    @Autowired
+    private JobUserService jobUserService;
+
+    @Autowired
+    private UserService userService;
+
+    @ApiOperation(value = "获取微信配置")
+    @GetMapping(value = "/getConfig")
+    public MessageResult getConfig(String url) {
+
+        int code = 200;
+        String message = "获取成功";
+        Object data = "";
+        boolean result = true;
+
+        try {
+            AccessToken token = WeixinUtil.getAccessToken(wxPayProperties.getAppId(), wxPayProperties.getAppSecret());
+
+            Map<String, String> wxMap = Sign.sign(WeixinUtil.getJsAPI(token.getToken()), url);
+
+            wxMap.put("appId", wxPayProperties.getAppId());
+
+            log.warn(JSONObject.toJSONString(wxMap));
+
+            HashMap<String, Object> dataMap = new HashMap<String, Object>();
+
+            dataMap.put("wxConfig", wxMap);
+
+            data = dataMap;
+        } catch (Exception ex) {
+            log.error(ex.getMessage(),ex);
+
+            code = 500;
+            result = false;
+            message = "系统错误";
+        }
+
+        return new MessageResult(result, message, data, code);
+    }
+
+    @ApiOperation(value = "获取微信code")
+    @PostMapping(value = "findWechatUrl")
+    public MessageResult findWechatUrl(@RequestBody String url) {
+
+        String newpath = WeixinUtil.getCodeRequest(wxPayProperties.getAppId(), url, "snsapi_userinfo");
+
+        HashMap<String, Object> dataMap = new HashMap<String, Object>();
+
+        dataMap.put("wechatUrl", newpath);
+
+        return new MessageResult(true, "获取成功", dataMap, 200);
+    }
+
+    @ApiOperation(value = "获取公众号用户信息")
+    @GetMapping(value = "findUserInfo/{code}")
+    public MessageResult findUserInfo(@PathVariable String code) {
+        try {
+            log.warn("code=" + code);
+            log.warn("appId=" + wxPayProperties.getAppId());
+            log.warn("appSecret=" + wxPayProperties.getAppSecret());
+
+            AccessToken at = WeixinUtil.getAccessToken(wxPayProperties.getAppId(), wxPayProperties.getAppSecret(), code);
+
+
+            if (at != null && StringUtils.isNotBlank(at.getOpenid())) {
+                String openId = at.getOpenid();
+                System.out.println("openId:" + openId);
+
+                UserInfo userInfo = WeixinUtil.getUserInfo(openId, at.getToken());
+
+                HashMap<String, Object> dataMap = new HashMap<String, Object>();
+
+                dataMap.put("userInfo", userInfo);
+
+                return new MessageResult(true, "获取微信信息成功", userInfo, 200);
+
+            } else {
+                return new MessageResult(false, "获取微信信息失败", "", 400);
+            }
+
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return new MessageResult(false, "系统错误", "", 500);
+        }
+    }
+
+    @GetMapping(value = "getAppId/{id}")
+    @ResponseBody
+    public MessageResult getAppId(@PathVariable("id") String id) {
+
+        int code = 200;
+        String message = "获取成功";
+        Object data = "";
+        boolean result = true;
+
+        try {
+
+            HashMap<String, Object> wxMap = new HashMap<>();
+
+            wxMap.put("appId", wxPayProperties.getAppId());
+
+            HashMap<String, Object> dataMap = new HashMap<String, Object>();
+
+            dataMap.put("wxConfig", wxMap);
+
+            data = dataMap;
+
+        } catch (Exception ex) {
+            code = 500;
+            message = "系统错误";
+            result = false;
+        }
+
+        return new MessageResult(result, message, data, code);
+    }
+
+    @ApiOperation(value = "获取图片验证码信息")
+    @GetMapping("/getVerifyPic")
+    public MessageResult getVerifyPic(String openId, HttpServletResponse response) {
+        int code = 200;
+        String message = "获取验证码成功";
+        Object data = "";
+        boolean result = true;
+
+        try {
+
+            if (StringUtils.isBlank(openId)) {
+                throw new Exception("openId为空");
+            }
+
+            CircleCaptchaA captcha = CaptchaUtilA.createCircleCaptcha(200, 100, 4, 0);
+            captcha.write(response.getOutputStream());
+            String verifyPic = captcha.getCode();
+            redisService.put("code", openId, verifyPic, 120);
+
+
+            response.getOutputStream().close();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            code = 500;
+            message = e.getMessage();
+            result = false;
+        }
+
+        return new MessageResult(result, message, data, code);
+    }
+
+
+    @ApiOperation(value = "管理员绑定微信openid")
+    @PostMapping(value = "/bindWechat")
+    public MessageResult<String> bindWechat(String eventKey,String openId){
+        MessageResult<String> messageResult = new MessageResult<>();
+
+        try{
+            String[] arr = eventKey.split(",");
+
+            String userId = arr[1];
+            User user = userService.get(userId);
+
+            if (user!=null) {
+                user.setOpenId(openId);
+                user.setUpdateTime(new Date());
+                user.setUpdateBy(userId);
+                userService.update(user);
+            }
+            else{
+                throw new Exception("用户不存在!");
+            }
+
+            messageResult.setMessage(user.getUserName() + "绑定微信成功!");
+            messageResult.setResult(true);
+        }
+        catch (Exception ex){
+            messageResult.setResult(false);
+            messageResult.setMessage(ex.getMessage());
+
+            log.error(ex.getMessage(),ex);
+        }
+
+        return messageResult;
+    }
+
+    @ApiOperation(value = "用户绑定微信openid")
+    @PostMapping(value = "/bindPersonWechat")
+    public MessageResult<String> bindPersonWechat(String eventKey,String openId){
+        MessageResult<String> messageResult = new MessageResult<>();
+
+        try{
+            String[] arr = eventKey.split(",");
+
+            String userId = arr[1];
+            String phone = arr[2];
+
+            JobUser jobUser = jobUserService.get(userId);
+
+            //多传一个电话号码避免,测试环境和正式环境混淆
+            if (jobUser!=null) {
+                if(jobUser.getTel().equals(phone)) {
+                    jobUser.setOpenId(openId);
+                    jobUser.setUpdateTime(new Date());
+                    jobUser.setUpdateBy(userId);
+                    jobUserService.update(jobUser);
+                }
+                else{
+                    throw new Exception("用户手机号错误!");
+                }
+            }
+            else{
+                throw new Exception("用户不存在!");
+            }
+
+            messageResult.setMessage(jobUser.getRealName() + "绑定微信成功!");
+            messageResult.setResult(true);
+        }
+        catch (Exception ex){
+            messageResult.setResult(false);
+            messageResult.setMessage(ex.getMessage());
+
+            log.error(ex.getMessage(),ex);
+        }
+
+        return messageResult;
+    }
+
+    @ApiOperation(value = "验证服务器地址的有效性")
+    @GetMapping("/get")
+    @ResponseBody
+    public String index(@RequestParam(defaultValue = "") String signature,
+                        @RequestParam(defaultValue = "") String timestamp,
+                        @RequestParam(defaultValue = "") String nonce,
+                        @RequestParam(defaultValue = "") String echostr) {
+        log.warn("signature=" + signature);
+        log.warn("timestamp=" + timestamp);
+        log.warn("nonce=" + nonce);
+        log.warn("echostr=" + echostr);
+
+        if (WeixinUtil.checkSignature(wxConfig.getToken(), signature, timestamp, nonce)) {
+            return echostr;
+        } else {
+            return "index";
+        }
+    }
+
+
+    @ResponseBody
+    @ApiOperation(value = "创建二维码")
+    @PostMapping("/qrcode/create")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "expire_seconds", paramType = "query", required = true, value = "该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。"),
+            @ApiImplicitParam(name = "action_name", paramType = "query", required = true, value = "二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值"),
+            @ApiImplicitParam(name = "scene_id", paramType = "query", value = "场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)"),
+            @ApiImplicitParam(name = "scene_str", paramType = "query", value = "场景值ID(字符串形式的ID),字符串类型,长度限制为1到64")
+    })
+    public cn.hutool.json.JSONObject createQrcode(@RequestParam(name = "expire_seconds", defaultValue = "300") long expireSeconds,
+                                                  @RequestParam(name = "action_name", defaultValue = "QR_STR_SCENE") String actionName,
+                                                  @RequestParam(name = "scene_id", required = false) String sceneId,
+                                                  @RequestParam(name = "scene_str", required = false) String sceneStr) {
+        cn.hutool.json.JSONObject resultObj = new cn.hutool.json.JSONObject();
+
+        try {
+            StringBuilder urlBuilder = new StringBuilder();
+            AccessToken accessToken = WeixinUtil.getAccessToken(wxConfig.getAppId(), wxConfig.getAppSecret());
+
+            urlBuilder.append(wxConfig.getCreateQrCodeUrl())
+                    .append("?access_token=")
+                    .append(URLEncoder.encode(accessToken.getToken(), "UTF-8"));
+
+            cn.hutool.json.JSONObject jsonObject = new cn.hutool.json.JSONObject();
+            jsonObject.put("expire_seconds", expireSeconds);
+            jsonObject.put("action_name", actionName);
+
+            cn.hutool.json.JSONObject actionInfo = new cn.hutool.json.JSONObject();
+            cn.hutool.json.JSONObject scene = new cn.hutool.json.JSONObject();
+
+            StringBuilder keyBuilder = new StringBuilder();
+
+            keyBuilder.append(accessToken);
+
+            if (StringUtils.isNotEmpty(sceneId)) {
+                scene.put("scene_id", sceneId);
+                keyBuilder.append(sceneId);
+            }
+
+            if (StringUtils.isNotEmpty(sceneStr)) {
+                scene.put("scene_str", sceneStr);
+                keyBuilder.append(sceneStr);
+            }
+
+            String qrcodeUrl = (String) valueOperations.get("QRCODE_" + keyBuilder.toString());
+
+            if (StringUtils.isNotEmpty(qrcodeUrl)) {
+                resultObj.put("data", qrcodeUrl);
+                resultObj.put("result", true);
+            } else {
+                actionInfo.put("scene", scene);
+
+                jsonObject.put("action_info", actionInfo);
+
+                StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
+
+                entity.setContentType("application/json");//发送json数据需要设置contentType
+
+                HttpPost httpPost = new HttpPost(urlBuilder.toString());
+                CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+
+                httpPost.setEntity(entity);
+
+                HttpResponse res = httpClient.execute(httpPost);
+
+                if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                    String content = EntityUtils.toString(res.getEntity());// 返回json格式:
+                    cn.hutool.json.JSONObject ret = new cn.hutool.json.JSONObject(content);
+
+                    if (ret.containsKey("errcode")) {
+                        resultObj.put("result", false);
+                        resultObj.put("message", ret.getStr("errmsg"));
+                        resultObj.put("code", ret.getInt("errcode"));
+                    } else {
+                        String ticket = ret.getStr("ticket");
+                        long expire_seconds = ret.getLong("expire_seconds");
+
+                        qrcodeUrl = wxConfig.getShowQrCodeUrl() + "?ticket=" + URLEncoder.encode(ticket, "UTF-8");
+
+                        valueOperations.set("QRCODE_" + keyBuilder, qrcodeUrl, expire_seconds - 5, TimeUnit.SECONDS);
+
+                        resultObj.put("data", qrcodeUrl);
+                        resultObj.put("result", true);
+                    }
+                } else {
+                    resultObj.put("result", false);
+                    resultObj.put("message", "weixin服务器未正常返回!");
+                }
+            }
+        } catch (Exception ex) {
+            log.error(ex.getMessage(), ex);
+
+            resultObj.put("message", ex.getMessage());
+            resultObj.put("result", false);
+        }
+
+        return resultObj;
+    }
+}