Browse Source

微信支付接口

chenyongxing 6 years ago
parent
commit
35a835c45e

+ 107 - 0
common/common-entity/src/main/java/com/yihu/jw/entity/base/wx/WxPayLogDO.java

@ -0,0 +1,107 @@
package com.yihu.jw.entity.base.wx;
import com.yihu.jw.entity.IntegerIdentityEntity;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.Date;
/**
 * Created by Trick on 2018/11/8.
 */
@Entity(name = "WxPayLogDO")
@Table(name = "wlyy_wx_pay_log")
public class WxPayLogDO extends IntegerIdentityEntity {
    private String seqNo;//支付订单号',
    private String openId;//openid,
    private Integer type;//支付的类型(预留字段) 0:服务包签约
    private String orderParams;//统一下单参数XML',
    private String orderResponse;//统一下单返回XML',
    private Integer orderStatus;//统一下单状态,1为成功。0为默认,-1为失败',
    private String payResponse;//支付回调XML',
    private Date createTime;//'统一下单时间',
    private Date payTime;//支付回调时间',
    private Integer payStatus;//支付回调状态1为成功,0为默认,-1为失败',
    public String getSeqNo() {
        return seqNo;
    }
    public void setSeqNo(String seqNo) {
        this.seqNo = seqNo;
    }
    public String getOpenId() {
        return openId;
    }
    public void setOpenId(String openId) {
        this.openId = openId;
    }
    public Integer getType() {
        return type;
    }
    public void setType(Integer type) {
        this.type = type;
    }
    public String getOrderParams() {
        return orderParams;
    }
    public void setOrderParams(String orderParams) {
        this.orderParams = orderParams;
    }
    public String getOrderResponse() {
        return orderResponse;
    }
    public void setOrderResponse(String orderResponse) {
        this.orderResponse = orderResponse;
    }
    public Integer getOrderStatus() {
        return orderStatus;
    }
    public void setOrderStatus(Integer orderStatus) {
        this.orderStatus = orderStatus;
    }
    public String getPayResponse() {
        return payResponse;
    }
    public void setPayResponse(String payResponse) {
        this.payResponse = payResponse;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getPayTime() {
        return payTime;
    }
    public void setPayTime(Date payTime) {
        this.payTime = payTime;
    }
    public Integer getPayStatus() {
        return payStatus;
    }
    public void setPayStatus(Integer payStatus) {
        this.payStatus = payStatus;
    }
}

+ 30 - 0
common/common-entity/src/main/java/com/yihu/jw/entity/base/wx/WxWechatDO.java

@ -33,6 +33,9 @@ public class WxWechatDO extends UuidIdentityEntityWithOperator implements java.i
    private String password;//用户密码
    private String publicType;//1.自运营,2.外接
    private String remark;//'备注'
    private String mchId;//商户id
    private String cerfiticate;//商户证书(预留字段,保存证书路径??) 目前暂未使用到
    private String appKey;//appKey
    @Transient
@ -188,4 +191,31 @@ public class WxWechatDO extends UuidIdentityEntityWithOperator implements java.i
    public void setPublicType(String publicType) {
        this.publicType = publicType;
    }
    @Column(name = "mch_id")
    public String getMchId() {
        return mchId;
    }
    public void setMchId(String mchId) {
        this.mchId = mchId;
    }
    @Column(name = "cerfiticate")
    public String getCerfiticate() {
        return cerfiticate;
    }
    public void setCerfiticate(String cerfiticate) {
        this.cerfiticate = cerfiticate;
    }
    @Column(name="app_key")
    public String getAppKey() {
        return appKey;
    }
    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }
}

+ 5 - 0
common/common-request-mapping/src/main/java/com/yihu/jw/rm/patient/PatientRequestMapping.java

@ -31,6 +31,11 @@ public class PatientRequestMapping {
        public static final String getWxWechatConfig ="/getWxWechatConfig";
    }
    public abstract static class WechatPay extends Basic{
        public static final String PRE_URL =  "/wechatPay";
        public static final String Notify =  "/notify";
    }
    /**
     * signPackage
     */

+ 52 - 16
common/common-util/src/main/java/com/yihu/jw/util/wechat/WeiXinPayUtils.java

@ -16,6 +16,31 @@ public class WeiXinPayUtils {
    private static final Random RANDOM = new SecureRandom();
    /**
     * 获取 微信支付,统一下单 前的报文
     * @param param
     * @param appKey
     * @return
     * @throws Exception
     */
    public static String getXmlBeforUnifiedorder(Map<String, String> param,String appKey) throws Exception {
        synchronized (WeiXinPayUtils.class) {
            param.put("nonce_str",generateNonceStr());
            WXPayConstants.SignType  wxSignType = WXPayConstants.SignType.MD5;
            String signType = param.get("sign_type");
            if("HMAC-SHA256".equalsIgnoreCase(signType)){
                wxSignType = WXPayConstants.SignType.HMACSHA256;
            }
            //获取微信签名
            String signature = WeiXinPayUtils.generateSignature(param, appKey, wxSignType);
            param.put("sign",signature);
            //参数转化XML
            String params = XMLUtil.map2xmlForWx(param);
            return params;
        }
    }
    /**
     *
@ -25,28 +50,39 @@ public class WeiXinPayUtils {
     *
     * @param param
     * @param appKey
     * @return
     * @return  返回的map为微信返回报文转换成的map,
     *            此外map中 有个属性 wxPayResult.该属性放着微信返回的原始报文数据
     * @throws Exception
     */
    public static Map<String,Object> unifiedorder(Map<String, String> param,String appKey) throws Exception {
        param.put("nonce_str",generateNonceStr());
        WXPayConstants.SignType  wxSignType = WXPayConstants.SignType.MD5;
        String signType = param.get("sign_type");
        if("HMAC-SHA256".equalsIgnoreCase(signType)){
            wxSignType = WXPayConstants.SignType.HMACSHA256;
        synchronized (WeiXinPayUtils.class) {
            String xml = getXmlBeforUnifiedorder(param, appKey);
            String result = HttpUtil.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);
            Map<String,Object> wxrs =  XMLUtil.xmltoMap(result);
            wxrs.put("wxPayResult",wxrs);
            return wxrs;
        }
        //获取微信签名
        String signature = WeiXinPayUtils.generateSignature(param, appKey, wxSignType);
        param.put("sign",signature);
        //参数转化XML
        String params = XMLUtil.map2xmlForWx(param);
        String result = HttpUtil.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", params);
        Map<String,Object> wxrs =  XMLUtil.xmltoMap(result);
        return wxrs;
    }
    /**
     *
     * 微信支付,统一下单
     *
     * param 对应的key值参见文档 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1 (sign,nonce_str两个参数,此接口会自动生成)
     *
     * @param param
     * @return  返回的map为微信返回报文转换成的map,
     *            此外map中 有个属性 wxPayResult.该属性放着微信返回的原始报文数据
     * @throws Exception
     */
    public static Map<String,Object> unifiedorder(String param) throws Exception {
        synchronized (WeiXinPayUtils.class) {
            String result = HttpUtil.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", param);
            Map<String,Object> wxrs =  XMLUtil.xmltoMap(result);
            wxrs.put("wxPayResult",wxrs);
            return wxrs;
        }
    }
    /**
     * 获取随机字符串 Nonce Str

+ 15 - 15
svr/svr-patient/src/main/java/com/yihu/jw/patient/endpoint/wechat/WechatInfoEndPoint.java

@ -70,21 +70,21 @@ public class WechatInfoEndPoint extends EnvelopRestEndpoint {
                           @RequestParam(value = "wxId", required = true)String wxId) {
        String ticket = getJsapi_ticketByToken(wxId);
            Map<Object, Object> map = new HashMap<Object, Object>();
            if (ticket != null) {
                String noncestr = UUID.randomUUID().toString();
                long timestamp = System.currentTimeMillis() / 1000;
                String url = pageUrl;
                String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
                // sha1加密
                String signature = SHA1(str);
                map.put("noncestr", noncestr);
                map.put("timestamp", timestamp);
                map.put("signature", signature);
                return success(PatientRequestMapping.Wechat.api_success,map);
            }
        Map<Object, Object> map = new HashMap<Object, Object>();
        if (ticket != null) {
            String noncestr = UUID.randomUUID().toString();
            long timestamp = System.currentTimeMillis() / 1000;
            String url = pageUrl;
            String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
            // sha1加密
            String signature = SHA1(str);
            map.put("noncestr", noncestr);
            map.put("timestamp", timestamp);
            map.put("signature", signature);
            return success(PatientRequestMapping.Wechat.api_success,map);
        }
        return failed(PatientRequestMapping.Wechat.api_error);
    }

+ 61 - 0
svr/svr-patient/src/main/java/com/yihu/jw/patient/endpoint/wechat/WechatPayController.java

@ -0,0 +1,61 @@
package com.yihu.jw.patient.endpoint.wechat;
import com.yihu.jw.patient.service.wechat.WechatPayService;
import com.yihu.jw.restmodel.web.endpoint.EnvelopRestEndpoint;
import com.yihu.jw.rm.patient.PatientRequestMapping;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@Controller
@RequestMapping(value = PatientRequestMapping.WechatPay.PRE_URL)
@Api(value = "微信支付等相关接口", description = "微信支付等相关接口", tags = {"居民端 - 微信支付等相关接口"})
public class WechatPayController extends EnvelopRestEndpoint {
    @Autowired
    private WechatPayService wechatPayService;
    @Value("${wechat.id}")
    private String wxId;
    @ApiOperation("服务包下单")
    @RequestMapping(value = "createPayOrder", method = RequestMethod.POST)
    @ResponseBody
    public Map<String,Object> unifiedorder(@ApiParam(name = "openid", value = "openid", required = true)
                             @RequestParam(required = true)String openid,
                                           @ApiParam(name = "ip", value = "终端IP(患者)", required = true)
                             @RequestParam(required = true)String ip,
                                           @ApiParam(name = "orderId", value = "订单号[base_service_package_sign_record 的id字段用作与订单id]", required = true)
                             @RequestParam(required = true)String orderId) throws Exception {
        return wechatPayService.unifiedorder(wxId,openid,ip,orderId);
    }
    @ResponseBody
    @ApiOperation("微信支付结果通知")
    @RequestMapping(value = PatientRequestMapping.WechatPay.Notify, method = {RequestMethod.GET, RequestMethod.POST})
    public Map<String, String> wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String result = "";
        String inputLine;
        while ((inputLine = request.getReader().readLine()) != null) {
            result += inputLine;
        }
        request.getReader().close();
        Map<String, String> map = wechatPayService.getWxPayResultNotify(result);
        return map;
    }
}

+ 130 - 0
svr/svr-patient/src/main/java/com/yihu/jw/patient/service/wechat/WechatPayService.java

@ -0,0 +1,130 @@
package com.yihu.jw.patient.service.wechat;
import com.yihu.jw.entity.base.servicePackage.ServicePackageSignRecordDO;
import com.yihu.jw.entity.base.wx.WxWechatDO;
import com.yihu.jw.patient.dao.servicepackage.ServicePackageSignRecordDao;
import com.yihu.jw.rm.patient.PatientRequestMapping;
import com.yihu.jw.util.common.XMLUtil;
import com.yihu.jw.util.wechat.WeiXinPayUtils;
import com.yihu.jw.wechat.dao.WechatDao;
import com.yihu.jw.wechat.service.WxPayLogService;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
@Service
public class WechatPayService {
    @Autowired
    private WechatDao wechatDao;
    @Autowired
    private ServicePackageSignRecordDao servicePackageSignRecordDao;
    @Autowired
    private WxPayLogService wxPayLogService;
    /**
     * 微信统一下单接口
     *
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> unifiedorder(Map<String,String> par,String appKey) throws Exception {
        String xml = WeiXinPayUtils.getXmlBeforUnifiedorder(par, appKey);
        Map<String, Object> map = WeiXinPayUtils.unifiedorder(xml);
        //创建日志记录
        wxPayLogService.createLog(par,xml,map);
        return map;
    }
    /**
     * 微信下单 服务包下单
     * @param wxId
     * @param openid
     * @param ip
     * @param orderId  服务包id
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> unifiedorder(String wxId, String openid, String ip, String orderId) throws Exception {
        Map<String, String> map = new HashMap<>();
        WxWechatDO wxWechat = wechatDao.findOne(wxId);
        if(wxWechat==null){
            throw new Exception("can't find wechat:the wxId is "+wxId);
        }
        String url = wxWechat.getBaseUrl();
        if(StringUtils.isBlank(url)){
            throw new Exception("wechat url is null:the wechatId is "+wxId);
        }
        String mchId = wxWechat.getMchId();
        if(StringUtils.isBlank(mchId)){
            throw new Exception("can't find mch_id from wecht: the wxId is "+wxId);
        }
        String appKey = wxWechat.getAppKey();
        if(StringUtils.isBlank(appKey)){
            throw new Exception("can't find app_key from wecht: the wxId is "+wxId);
        }
        ServicePackageSignRecordDO spsr = servicePackageSignRecordDao.findOne(orderId);
        if(spsr == null){
            throw new Exception("can't find ServicePackageSignRecor by "+orderId);
        }
        //拼接商品名
        String body ="";
        String hospitalName = spsr.getHospitalName();
        if(StringUtils.isNotBlank(hospitalName)){
            body += hospitalName +"-";
        }
        String servicePackageName = spsr.getServicePackageName();
        if(StringUtils.isEmpty(servicePackageName)){
            servicePackageName = "服务包";
        }
        body += servicePackageName;
        //需要支付的总金额
        Long price = spsr.getPrice();
        if(price == null){
            throw new Exception("the price is not correct,the base_service_package_sign_record is "+orderId);
        }
        long pric = price * 100;
        map.put("appid",wxWechat.getAppId());
        map.put("mch_id",wxWechat.getMchId());
        map.put("body",body);
        map.put("trade_type","JSAPI");
        map.put("spbill_create_ip",ip);
        map.put("out_trade_no",orderId);
        map.put("total_fee",pric+"");
        map.put("openid",openid);
        map.put("notify_url",url+PatientRequestMapping.WechatPay.PRE_URL+PatientRequestMapping.WechatPay.Notify);
        return unifiedorder(map,appKey);
    }
    public Map<String,String> getWxPayResultNotify(String result) {
        Map<String,String> rs = new HashedMap();
        Map<String,Object> wxrs =  XMLUtil.xmltoMap(result);
        if("SUCCESS".equals(wxrs.get("return_code").toString())){
            // 我方 订单号+时间差
            String seqNo = wxrs.get("out_trade_no")+"";
            // 微信充值流水号
            String wxSeqNo = wxrs.get("transaction_id")+"";
            // 微信分配的终端设备号
            String wxDeviceInfo = wxrs.get("device_info")+"";
            //更改业务状态,做日志保存等操作
            ServicePackageSignRecordDO spsr = servicePackageSignRecordDao.findOne(seqNo);
            spsr.setStatus(2);
            servicePackageSignRecordDao.save(spsr);
            rs.put("code","1");
            rs.put("message","支付成功");
        }else{
            rs.put("code","-1");
            rs.put("return_msg","FAIL");
        }
        return rs;
    }
}