精华内容
下载资源
问答
  • Thinkphp内核2020最新微信支付服务商专用整站源码 微信服务商集成系统
  • 微信支付服务商jsapi支付demo.zip
  • 微信支付服务商jsapi支付demo
  • 微信支付服务商接入指引 本文主要针对服务商下特约商户的小程序支付进行讲解。(扫码支付, h5支付大致流程都差不多,了解了小程序支付能够很快接入其他支付类型) 说明:本文中的支付都是指在服务商模式下 支付主体...
  • 微信支付服务商的支付功能开发,扫码支付实例,已经调式好的代码
  • 微信支付服务商平台Api V3版PHP Demo 已实现功能特约商户进件、查询、上传等 注:微信支付服务商平台,小微进件好像还是用不了
  • 支付之家网(ZFZJ.CN)7月21日,微信支付推出《微信支付成长计划-智慧经营系列课堂》,同时对外透露,微信支付智慧经营产品支付分正式宣布支持服务商模式。首期“政策与产品能力专场”中,官方团队公布了最新的激励...

    支付之家网(ZFZJ.CN)7月21日,微信支付推出《微信支付成长计划-智慧经营系列课堂》,同时对外透露,微信支付智慧经营产品支付分正式宣布支持服务商模式。

    首期“政策与产品能力专场”中,官方团队公布了最新的激励政策及产品能力升级——

    返佣、流量、营销增值等多种激励措施及3大重点激励场景正式上线,助力服务商生态发展。

    经营管理工具和营销服务工具两方面产品能力迎来深度升级,并为支付分、电子发票两大重磅能力开通服务商模式,有效帮助服务商降低运营成本。

    对于在微信支付体系内做经营的服务商来说,如何通过朋友圈引流、小程序发券、电子发票、支付分等智慧经营能力为商户及用户提供更全面、更深度的服务,将成为自身新的核心竞争力。

    以支付为经营起点,拓宽“智慧边界”

    随着商户数字化转型的需求推动,“以支付为交易终点”向商家提供传统收单服务的服务商,逐步转型为 “以支付为经营起点”,向商家提供复合型服务的经营服务商了。

    透过微信支付开放生态中人、货、场的数字化链接和流量转化,经营服务商可以为商户提供例如用户管理、数据管理、甚至供应链管理等全链路的技术和经营服务不断深入商家经营,并结合门店小程序、扫码购、扫码点餐等行业经营产品,提供专业且更具个性化的服务。

    某零售服务商在为自己的商户做经营外,还整合了当地食品、快消品、餐饮店等营销资源,搭配出不同的商品组合做营销发券与直播。不仅帮助商家降低了营销成本,也建立了优质的引流渠道,与商家一同谋求长远发展。

    自去年合作伙伴大会以来,经营服务商的群体日渐扩大。除了支付收单服务商,小程序电商服务商、品牌营销服务商、商圈服务商、ERP服务商、CRM服务商等也加入到经营服务商的行列中。

    提供深入商家经营的解决方案及更精细化个性化的服务,将成为经营服务商发展的新趋势。

    多方面激励措施,助力生态发展

    为保证服务商体系健康发展,微信支付为服务商及商户开放百亿级支付流量,帮助商家实现私域流量的培育和转化。

    此外,在提供行业返佣、基础返佣、流量激励、硬件返佣、营销补贴、增值政策等激励措施的基础上,还提出了重点激励场景——

    刷脸设备

    -覆盖更多设备及场景

    包括自助收银大屏、双屏POS、自助点餐大屏、售货机等。

    -鼓励覆盖优质点位,设备补贴力度加大

    支付笔数越多,单台设备的激励越大。

    营销激励

    -鼓励拓展新商户

    新增商家券返佣,并提升封顶值:单商户返佣封顶值提升50%、单服务商返佣封顶值提升100%。

    -小程序扶优

    小程序的券核销激励翻倍,还将得到朋友圈流量的重点扶持。

    点金计划2.0

    -支付后页面开辟商家小票空间

    服务商可为商户进行高度配置和外跳配置

    -支付后页面配置广告banner

    广告位banner所产生的收入,将会作为服务商的增值奖励,返还给服务商。

    新能力迭代发布,基础产品再升级

    在此次系列课中,微信支付智慧经营产品支付分正式宣布支持服务商模式。

    在服务商开通支付分受理权限,且子商户同意授权并签约的情况下,服务商即可邀请商户授权支付分权限,使用覆盖70+场景,降低商户坏账91%的先押先享能力,又或是高效拉新拉复购的先享卡或支付分名片,为商户带来更多社交玩法及场景。

    除了支付分,全新的商户工具箱将升级推出电子发票能力。

    升级后,商户工具箱将微信支付与税务局发票管理系统打通,并提供商户在线开具电子发票的全系产品(优先支持服务商模式)。除了基本的税务注册和信息管理之外,商户还可以在微信支付平台进行历史发票管理、发票库存查询、自动申领发票、自动抄报税等能力,有效为服务商减负。

    电子发票服务商模式将以开票接口+开放式体系推出,让服务商能够更深入地集成到自己的产品系统中去。

    在与微信支付智慧经营场景充分结合后,借助对商户、对垂直行业的深度理解,无论是酒店、餐饮、停车场及无人零售等线下场景,还是小程序电商、小程序外卖等线上场景,服务商都能为商户及用户提供舒适便捷的开票体验,完成购物闭环。

    除了以上两种,在经营管理工具与营销服务工具两方面,微信支付都做出了重点的产品能力升级:

    经营管理工具

    品牌连锁能力,帮助品牌方收银提速,建设品牌+门店的归属关系,同一小程序可集合支付及营销为一体;

    智慧商圈能力,基于地理位置,关联商圈与门店,由商圈统一进行营销和经营。

    分账产品2.0能力,实现了供应链分账,帮助商户提高资金分配的效能,满足了像电商、连锁加盟行业、商圈等行业分账需求;针对电商行业,推出的电商收付通产品,能满足不同模式电商分账诉求。

    营销服务工具

    支付即会员,用户在支付后流量入口一键开卡,并通过开卡有礼促进用户的开卡率,帮助商家沉淀优质用户及进行用户管理。

    支付即服务,即在支付后页面引导用户与门店导购建立联系,通过导购提供个性化专属服务。

    商家券,可打通商家自营优惠体系与微信支付体系,满足多元化营销需求,与支付券一起帮助商家营销发券。

    为用户和商家提供更好的服务,提升社会生产效率,也是微信支付的初心。

    不断发展服务商体系,丰富微信支付生态,协助商户转型智慧经营,不仅能为用户提供精细化服务,用户也能快速反馈需求,达成服务商-商户-用户之间的良性循环,最终促进整个生态的共同发展。

    展开全文
  • 微擎插件,服务商进件,微信支付
  • 微信支付服务商模式采坑记录 微信支付小程序服务商模式的实现,官方文档写的简直格外坑爹.开发文档地址:微信支付小程序服务商模式开发文档 统一下单 几个注意点: 非沙箱环境的下单请求地址是:...

    微信支付服务商模式采坑记录

    微信支付小程序服务商模式的实现,官方文档写的简直格外坑爹.开发文档地址:微信支付小程序服务商模式开发文档

    统一下单

    几个注意点:

    1. 非沙箱环境的下单请求地址是:https://api.mch.weixin.qq.com/pay/unifiedorder
    2. 不需要证书
    3. 统一下单的几个需要注意的参数,下边是参数列表
    描述变量名必填类型
    你申请服务商模式公众号的appidappidString(32)
    你申请服务商模式的商户号mch_idString(32)
    特约服务商的小程序appid或者公众号appid(也可以是服务商自己的小程序appid,前提是特约商户是这个服务商的特约商户)sub_appidString(32)
    特约商户号(去服务商的账号的特约商户管理里边看)sub_mch_idString(32)
    统一用MD5sign_typeString(32)
    自己系统的订单号out_trade_noString(32)
    需要支付的金额,单位是total_feeint
    支付异步通知回调地址,注意长度notify_urlString(256)
    交易类型,小程序的是JSAPItrade_typeString(16)
    什么也不说了,这个不传openidString(128)
    trade_type=JSAPI,此参数必传,特别需要注意: 这个是sub_appid对应的小程序或者公众号下的openidsub_openidString(128)
    服务商账号的api keykeystring
    1. 参数需要加密,加密的时候不包含sign字段,这个是加密其他参数以后补充进去的,再有就是一定要在通过ASCII码从小到大排序的字符串最后加上&key=xxx这个值再进行加密.自己看开发文档就行,这个说的挺清楚的.
    2. 返回的时候return_code和result_code都是SUCCESS才算成功
    3. 除了返回的prepay_id有大用,其他的都可以直接忽略,千万记住,不要用除了prepay_id以外的任何返回值充当下一个接口的参数.

    支付异步通知

    1. 一定要能调通!一定要能调通!一定要能调通!重要的事情说三遍
    2. 回调地址检查仔细,比如说开发人员不知道服务器那边配置的负载或者代理配置了其他前缀而忽略了,就会造成开发环境可以,一上生产就完蛋!
    3. 一定要做签名验证和金额效验以及其他的验证,最后保留transaction_id到数据库
    4. 通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)

    申请退款

    1. 需要证书,证书下载去服务商账号下自己去按照要求配置并下载就行,证书的密码默认就是服务商的appid,分布式项目中不要将证书进行RPC传输
    2. 请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次,错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次.
    3. 入参的要求和统一下单的那些基本参数一样,额外多了transaction_id的传入而已,没什么可说的,只不过参数不一样而已,基本参数还是一样的.金额也是分
    4. 需要注意的是:服务商必须给特约商户开通退款平台权限和退款API权限才能正常退款,比较恶心,操作起来挺繁琐的.
    展开全文
  • 微信支付服务商模式说明

    千次阅读 2020-06-11 15:29:35
    微信支付服务商模式 如果把服务商模式比作公司的话,普通商户就好比个人。公司可以聘请很多“个人”(员工)。也就是说,服务商可以发展很多自己的子商户。并且在费率上面服务商也是有优势的。 服务商模式比普通...

    微信支付分为普通商户版,服务商版以及银行服务商版,我们主讲服务商版。

    官方地址:https://pay.weixin.qq.com/wiki/doc/api/sl.html

    微信支付服务商模式

    如果把服务商模式比作公司的话,普通商户就好比个人。公司可以聘请很多“个人”(员工)。也就是说,服务商可以发展很多自己的子商户。并且在费率上面服务商也是有优势的。

    服务商模式比普通商户模式,从下单参数上面来看,主要多了子商户号:sub_mch_id(必填),sub_appid和sub_openId(非必填)。

    这里我们选择JSAPI支付。

     

    1. 支付主要会用到5个参数

    appid:微信公众号(服务号)appid

    appsecret:微信公众平台的 AppSecret(应用密钥),用于获取用户openId

    mchId:微信商户ID

    apiKey: 微信商户平台设置的 API密钥-用于签名验证

    sub_mchId:子商户ID

    点击查看如何获取支付参数,未更新,仅供参考

    子商户从通过商户平台,进件审核通过之后,微信分配。

     

    准备请求参数

    ScanPayReqDataSp.java

    package com.pay.wechat.protocol.pay_protocol;
    
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    import com.pay.wechat.util.Config;
    import com.pay.wechat.util.RandomStringGenerator;
    import com.pay.wechat.util.Signature;
    import com.pay.wechat.util.xmlstream.XStreamCDATA;
    import com.tenet.util.DateUtil;
    
    /**
     * 统一下单请求数据模型-- 服务商版本<br>
     * 
     * API接口地址说明:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
     * 
     * 是否需要证书: 不需要
     * 
     * @author libaibai
     * @version 1.0 2017年11月2日
     */
    public class ScanPayReqDataSp {
    
    	// 更多详情查看API接口地址说明
    	private String appid = ""; // 微信分配的公众账号ID(企业号corpid即为此appId)
    	private String mch_id = ""; // 微信支付分配的商户号
    
    	private String sub_appid; // 否 String(32) wxd678efh567hg6999
    	// // 微信分配的子商户公众账号ID,如需在支付完成后获取sub_openid则此参数必传。
    
    	private String sub_mch_id;// 是 String(32) 1900000109 微信支付分配的子商户号
    
    	private String device_info = ""; // 设备号(非必填)
    	private String nonce_str = ""; // 随机字符串,不长于32位
    	private String sign = ""; // 签名
    	private String body = ""; // 商品描述
    	private String detail = ""; // 商品详情(非必填)
    	
    	@XStreamCDATA
    	private String attach = ""; // 附加数据(非必填) - 目前存放车牌号或卡号
    	private String out_trade_no = ""; // 商户订单号,调用方产生,32个字符(必填***)
    	private String fee_type = ""; // 货币类型(非必填)
    	private int total_fee = 0; // 总金额(单位:分,必填***)
    	private String spbill_create_ip = ""; // 终端IP
    	private String time_start = ""; // 交易起始时间(格式为yyyyMMddHHmmss)
    	private String time_expire = ""; // 交易结束时间(格式为yyyyMMddHHmmss)
    	private String goods_tag = ""; // 商品标记(非必填)
    
    	// 通知地址,接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。(以Config.java为准)
    	private String notify_url = Config.NOTIFY_URL;
    
    	private String trade_type = "JSAPI"; // 交易类型,默认:JSAPI(JSAPI,NATIVE,APP)
    	private String product_id = ""; // 商品ID(trade_type=NATIVE,此参数必传)
    	private String limit_pay = ""; // 指定支付方式(no_credit--指定不能使用信用卡支付)
    	private String openid = ""; // 用户标识(trade_type=JSAPI,此参数必传)
    	private String sub_openid = ""; // trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
    
    	public ScanPayReqDataSp(String appid, String mch_id, String sub_appid, String sub_mch_id, String key, String body, String detail, String attach,
    			String out_trade_no, int total_fee, String spbill_create_ip, String trade_type, String product_id, String openid, String sub_openid) {
    		this.appid = appid;
    		this.mch_id = mch_id;
    		this.sub_appid = sub_appid;
    		this.sub_mch_id = sub_mch_id;
    		this.body = body;
    		this.detail = detail;
    		this.attach = attach;
    		this.out_trade_no = out_trade_no;
    		this.total_fee = total_fee;
    		this.spbill_create_ip = spbill_create_ip;
    		this.trade_type = trade_type;
    		this.product_id = product_id;
    		this.openid = openid;
    		this.sub_openid = sub_openid;
    
    		// 需要附属值字段,可在此处统一生成
    		this.nonce_str = RandomStringGenerator.getRandomStringByLength(32);
    
    		// 交易时间限制
    		this.time_start = DateUtil.getDateTimeStr(null); // 当前时间
    		long time_expireLong = DateUtil.getTimeStampLong() + Config.ORDER_EXPIRE_TIME;
    		this.time_expire = DateUtil.getDateTimeStr(DateUtil.getTimeStampToDate(time_expireLong)); // 当前时间+600秒
    
    		// sign签名
    		// 根据API给的签名规则进行签名
    		this.sign = Signature.getSign(toMap(), key);
    	}
    
    	public String getAppid() {
    		return appid;
    	}
    
    	public void setAppid(String appid) {
    		this.appid = appid;
    	}
    
    	public String getMch_id() {
    		return mch_id;
    	}
    
    	public void setMch_id(String mch_id) {
    		this.mch_id = mch_id;
    	}
    
    	public String getDevice_info() {
    		return device_info;
    	}
    
    	public void setDevice_info(String device_info) {
    		this.device_info = device_info;
    	}
    
    	public String getNonce_str() {
    		return nonce_str;
    	}
    
    	public void setNonce_str(String nonce_str) {
    		this.nonce_str = nonce_str;
    	}
    
    	public String getSign() {
    		return sign;
    	}
    
    	public void setSign(String sign) {
    		this.sign = sign;
    	}
    
    	public String getBody() {
    		return body;
    	}
    
    	public void setBody(String body) {
    		this.body = body;
    	}
    
    	public String getDetail() {
    		return detail;
    	}
    
    	public void setDetail(String detail) {
    		this.detail = detail;
    	}
    
    	public String getAttach() {
    		return attach;
    	}
    
    	public void setAttach(String attach) {
    		this.attach = attach;
    	}
    
    	public String getOut_trade_no() {
    		return out_trade_no;
    	}
    
    	public void setOut_trade_no(String out_trade_no) {
    		this.out_trade_no = out_trade_no;
    	}
    
    	public String getFee_type() {
    		return fee_type;
    	}
    
    	public void setFee_type(String fee_type) {
    		this.fee_type = fee_type;
    	}
    
    	public int getTotal_fee() {
    		return total_fee;
    	}
    
    	public void setTotal_fee(int total_fee) {
    		this.total_fee = total_fee;
    	}
    
    	public String getSpbill_create_ip() {
    		return spbill_create_ip;
    	}
    
    	public void setSpbill_create_ip(String spbill_create_ip) {
    		this.spbill_create_ip = spbill_create_ip;
    	}
    
    	public String getTime_start() {
    		return time_start;
    	}
    
    	public void setTime_start(String time_start) {
    		this.time_start = time_start;
    	}
    
    	public String getTime_expire() {
    		return time_expire;
    	}
    
    	public void setTime_expire(String time_expire) {
    		this.time_expire = time_expire;
    	}
    
    	public String getGoods_tag() {
    		return goods_tag;
    	}
    
    	public void setGoods_tag(String goods_tag) {
    		this.goods_tag = goods_tag;
    	}
    
    	public String getNotify_url() {
    		return notify_url;
    	}
    
    	public void setNotify_url(String notify_url) {
    		this.notify_url = notify_url;
    	}
    
    	public String getTrade_type() {
    		return trade_type;
    	}
    
    	public void setTrade_type(String trade_type) {
    		this.trade_type = trade_type;
    	}
    
    	public String getProduct_id() {
    		return product_id;
    	}
    
    	public void setProduct_id(String product_id) {
    		this.product_id = product_id;
    	}
    
    	public String getLimit_pay() {
    		return limit_pay;
    	}
    
    	public void setLimit_pay(String limit_pay) {
    		this.limit_pay = limit_pay;
    	}
    
    	public String getOpenid() {
    		return openid;
    	}
    
    	public void setOpenid(String openid) {
    		this.openid = openid;
    	}
    
    	public String getSub_mch_id() {
    		return sub_mch_id;
    	}
    
    	public void setSub_mch_id(String sub_mch_id) {
    		this.sub_mch_id = sub_mch_id;
    	}
    
    	public String getSub_appid() {
    		return sub_appid;
    	}
    
    	public void setSub_appid(String sub_appid) {
    		this.sub_appid = sub_appid;
    	}
    	
    	public String getSub_openid() {
    		return sub_openid;
    	}
    
    	public void setSub_openid(String sub_openid) {
    		this.sub_openid = sub_openid;
    	}
    
    	public Map<String, Object> toMap() {
    		Map<String, Object> map = new HashMap<String, Object>();
    		Field[] fields = this.getClass().getDeclaredFields();
    		for (Field field : fields) {
    			Object obj;
    			try {
    				obj = field.get(this);
    				if (obj != null) {
    					map.put(field.getName(), obj);
    				}
    			} catch (IllegalArgumentException e) {
    			} catch (IllegalAccessException e) {
    			}
    		}
    		return map;
    	}
    
    }
    

    签名工具类

    package com.pay.wechat.util;
    
    import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
    import org.xml.sax.SAXException;
    
    import com.wsimpl.bo.wx.einvoice.HMacShaUtil;
    
    import javax.xml.parsers.ParserConfigurationException;
    
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Map;
    
    /**
     * 签名util 类
     *
     * 
     * @depc 将key修改成传入,不从Configure类获取
     * @author libaibai
     * @version 2.0 2016年2月22日
     */
    public class Signature {
    	private static final Logger LOG = LogManager.getLogger(Signature.class);
    
    	/**
    	 * 签名算法
    	 * 
    	 * @param o 要参与签名的数据对象
    	 * @return 签名
    	 * @throws IllegalAccessException
    	 */
    	public static String getSign(Object o, String key) throws IllegalAccessException {
    		ArrayList<String> list = new ArrayList<String>();
    		Class<?> cls = o.getClass();
    		Field[] fields = cls.getDeclaredFields();
    		for (Field f : fields) {
    			f.setAccessible(true);
    			if (f.get(o) != null && f.get(o) != "") {
    				list.add(f.getName() + "=" + f.get(o) + "&");
    			}
    		}
    		int size = list.size();
    		String[] arrayToSort = list.toArray(new String[size]);
    		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
    		StringBuilder sb = new StringBuilder();
    		for (int i = 0; i < size; i++) {
    			sb.append(arrayToSort[i]);
    		}
    		String result = sb.toString();
    		result += "key=" + key;
    		result = MD5.MD5Encode(result).toUpperCase();
    		return result;
    	}
    
    	/**
    	 * 签名算法
    	 * 
    	 * @param map
    	 * @param key
    	 * @return
    	 */
    	public static String getSign(Map<String, Object> map, String key) {
    		ArrayList<String> list = new ArrayList<String>();
    		for (Map.Entry<String, Object> entry : map.entrySet()) {
    			if (entry.getValue() != "") {
    				list.add(entry.getKey() + "=" + entry.getValue() + "&");
    			}
    		}
    		int size = list.size();
    		String[] arrayToSort = list.toArray(new String[size]);
    		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
    		StringBuilder sb = new StringBuilder();
    		for (int i = 0; i < size; i++) {
    			sb.append(arrayToSort[i]);
    		}
    		String result = sb.toString();
    		result += "key=" + key;
    		result = MD5.MD5Encode(result).toUpperCase();
    		return result;
    	}
    	
    	/**
    	 * 签名算法( HMAC-SHA256)
    	 * 
    	 * @param map
    	 * @param key
    	 * @return
    	 */
    	public static String getSignSha(Map<String, Object> map, String key) {
    		ArrayList<String> list = new ArrayList<String>();
    		for (Map.Entry<String, Object> entry : map.entrySet()) {
    			if (entry.getValue() != "") {
    				list.add(entry.getKey() + "=" + entry.getValue() + "&");
    			}
    		}
    		int size = list.size();
    		String[] arrayToSort = list.toArray(new String[size]);
    		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
    		StringBuilder sb = new StringBuilder();
    		for (int i = 0; i < size; i++) {
    			sb.append(arrayToSort[i]);
    		}
    		String result = sb.toString();
    		result += "key=" + key;
    		result = HMacShaUtil.sha256_HMAC(result, key).toUpperCase();
    		return result;
    	}
    
    	/**
    	 * 从API返回的XML数据里面重新计算一次签名
    	 * 
    	 * @param responseString API返回的XML数据
    	 * @return 新鲜出炉的签名
    	 * @throws ParserConfigurationException
    	 * @throws IOException
    	 * @throws SAXException
    	 */
    	public static String getSignFromResponseString(String responseString, String key)
    			throws IOException, SAXException, ParserConfigurationException {
    		Map<String, Object> map = XMLParser.getMapFromXML(responseString);
    		// 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
    		map.put("sign", "");
    		// 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
    		return Signature.getSign(map, key);
    	}
    
    	/**
    	 * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
    	 * 
    	 * @param responseString API返回的XML数据字符串
    	 * @return API签名是否合法
    	 * @throws ParserConfigurationException
    	 * @throws IOException
    	 * @throws SAXException
    	 */
    	public static boolean checkIsSignValidFromResponseString(String responseString, String key)
    			throws ParserConfigurationException, IOException, SAXException {
    
    		Map<String, Object> map = XMLParser.getMapFromXML(responseString);
    
    		String signFromAPIResponse = map.get("sign").toString();
    		if (signFromAPIResponse == "" || signFromAPIResponse == null) {
    			LOG.error("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
    			return false;
    		}
    		// 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
    		map.put("sign", "");
    		// 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
    		String signForAPIResponse = Signature.getSign(map, key);
    
    		if (!signForAPIResponse.equals(signFromAPIResponse)) {
    			// 签名验不过,表示这个API返回的数据有可能已经被篡改了
    			LOG.error("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
    			return false;
    		}
    		return true;
    	}
    
    }
    

    支付请求类

    ScanPayService .java

    package com.pay.wechat.service;
    
    import org.springframework.stereotype.Component;
    
    import com.pay.wechat.protocol.pay_protocol.ScanPayReqDataSp;
    import com.pay.wechat.util.Config;
    
    /**
     * 支付请求
     *
     * @author libaibai
     * @version 1.0 2015年8月31日
     */
    @Component
    public class ScanPayService extends BaseService {
    
    	/**
    	 * 请求支付服务-- 服务商版
    	 * 
    	 * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
    	 * @return API返回的数据
    	 * @throws Exception
    	 */
    	public String requestSp(ScanPayReqDataSp scanPayReqDataSp) throws Exception {
    
    		super.apiURL = Config.UNIFIEDORDER_API;
    		// --------------------------------------------------------------------
    		// 发送HTTPS的Post请求到API地址
    		// --------------------------------------------------------------------
    		String responseString = sendPost(scanPayReqDataSp);
    
    		return responseString;
    	}
    
    
    
    }
    

    BaseService.java

    package com.pay.wechat.service;
    
    import java.io.IOException;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    
    import javax.annotation.Resource;
    
    import com.dlys.pay.wechat.util.HttpsRequest;
    
    /**
     * 
     * @author libaibai
     *
     */
    public class BaseService {
    
    	// API的地址
    	public String apiURL;
    
    	// 发请求的HTTPS请求器
    
    	@Resource
    	private HttpsRequest httpsRequest;
    
    	protected String sendPost(Object xmlObj) throws UnrecoverableKeyException, IOException,
    			NoSuchAlgorithmException, KeyStoreException, KeyManagementException,
    			ClassNotFoundException, InstantiationException, IllegalAccessException {
    		return httpsRequest.sendPost(apiURL, xmlObj);
    	}
    
    }
    

    HttpsRequest.java

    package com.pay.wechat.util;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    
    import javax.net.ssl.SSLContext;
    
    import org.apache.commons.lang.StringEscapeUtils;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpHeaders;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.stereotype.Component;
    
    import com.pay.wechat.protocol.pay_protocol.ScanPayReqDataSp;
    import com.pay.wechat.util.xmlstream.XStreamFactory;
    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
    
    /**
     * HTTP 请求类
     *
     * @author libaibai
     * @version 1.0 2015年8月31日
     */
    @Component
    public class HttpsRequest {
    	public interface ResultListener {
    		public void onConnectionPoolTimeoutError();
    	}
    
    	private static Logger LOG = LogManager.getLogger(HttpsRequest.class);
    
    	private boolean hasInit = false;
    
    	// 连接超时时间,默认10秒
    	private int socketTimeout = 10000;
    
    	// 传输超时时间,默认30秒
    	private int connectTimeout = 30000;
    
    	// 请求器的配置
    	private RequestConfig requestConfig;
    
    	// HTTP请求器
    	private CloseableHttpClient httpClient;
    
    	/**
    	 * 证书初始化
    	 * 
    	 * @throws UnrecoverableKeyException
    	 * @throws KeyManagementException
    	 * @throws NoSuchAlgorithmException
    	 * @throws KeyStoreException
    	 * @throws IOException
    	 */
    	public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
    		init();
    	}
    
    	private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
    
    		KeyStore keyStore = KeyStore.getInstance("PKCS12");
    		InputStream instream = HttpsRequest.class.getClassLoader().getResourceAsStream(Configure.CERTLOCAL_PATHx);// 加载本地的证书进行https加密传输
    		try {
    			keyStore.load(instream, Configure.CERTPASSWORD.toCharArray());// 设置证书密码
    		} catch (Exception e) {
    			LOG.error("加载证书异常", e);
    		} finally {
    			instream.close();
    		}
    		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, Configure.CERTPASSWORD.toCharArray()).build();
    		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
    				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
    
    		httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    
    		// 根据默认超时限制初始化requestConfig
    		requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
    
    		hasInit = true;
    	}
    
    	/**
    	 * 通过Https往API GET
    	 *
    	 * @param url API地址
    	 * @return API回包的实际数据
    	 * @throws IOException
    	 * @throws KeyStoreException
    	 * @throws UnrecoverableKeyException
    	 * @throws NoSuchAlgorithmException
    	 * @throws KeyManagementException
    	 */
    
    	public String sendGET(String url)
    			throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
    
    		if (!hasInit) {
    			init();
    		}
    
    		String result = null;
    
    		HttpGet httpGet = new HttpGet(url);
    
    		// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
    		httpGet.addHeader("Content-Type", "text/xml");
    
    		// 设置请求器的配置
    		httpGet.setConfig(requestConfig);
    
    		try {
    			HttpResponse response = httpClient.execute(httpGet);
    
    			HttpEntity entity = response.getEntity();
    
    			result = EntityUtils.toString(entity, "UTF-8");
    
    		} catch (Exception e) {
    			LOG.error("HTTP Get请示异常", e);
    		} finally {
    			httpGet.abort();
    		}
    		return result;
    	}
    
    	/**
    	 * 通过Https往API post
    	 *
    	 * @param url API地址
    	 * @param Object 要提交的Object数据对象
    	 * @return API回包的实际数据
    	 * @throws IOException
    	 * @throws KeyStoreException
    	 * @throws UnrecoverableKeyException
    	 * @throws NoSuchAlgorithmException
    	 * @throws KeyManagementException
    	 */
    
    	public String sendPostObject(String url, HttpEntity postEntity)
    			throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
    
    		if (!hasInit) {
    			init();
    		}
    
    		String result = null;
    		HttpPost httpPost = new HttpPost(url);
    		httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.MULTIPART_FORM_DATA.getMimeType());
    		httpPost.setEntity(postEntity);
    
    		// 设置请求器的配置
    		httpPost.setConfig(requestConfig);
    		try {
    			HttpResponse response = httpClient.execute(httpPost);
    			HttpEntity entity = response.getEntity();
    
    			result = EntityUtils.toString(entity, "UTF-8");
    
    		} catch (Exception e) {
    			LOG.error("HTTP POST 请求异常", e);
    		} finally {
    			httpPost.abort();
    		}
    
    		return result;
    	}
    
    	/**
    	 * 通过Https往API post xml数据
    	 *
    	 * @param url API地址
    	 * @param xmlObj 要提交的XML数据对象
    	 * @return API回包的实际数据
    	 * @throws IOException
    	 * @throws KeyStoreException
    	 * @throws UnrecoverableKeyException
    	 * @throws NoSuchAlgorithmException
    	 * @throws KeyManagementException
    	 */
    
    	public String sendPost(String url, Object xmlObj)
    			throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
    
    		if (!hasInit) {
    			init();
    		}
    
    		String result = null;
    		HttpPost httpPost = new HttpPost(url);
    
    		// 解决XStream对出现双下划线的bug
    		// XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8",
    		// new XmlFriendlyNameCoder("-_", "_")));
    
    		XStream xStream = XStreamFactory.getXStream(new XmlFriendlyNameCoder("_-", "_"));
    
    		// 将要提交给API的数据对象转换成XML格式数据Post给API
    		String postDataXML = xStream.toXML(xmlObj);
    		LOG.info("请求微信接口->url=" + url + ",data=" + postDataXML);
    		// LOG.info("data="+StringEscapeUtils.unescapeXml(postDataXML));// 转义字符
    
    		// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
    		StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
    		httpPost.addHeader("Content-Type", "text/xml");
    		httpPost.setEntity(postEntity);
    
    		// 设置请求器的配置
    		httpPost.setConfig(requestConfig);
    
    		try {
    			HttpResponse response = httpClient.execute(httpPost);
    
    			HttpEntity entity = response.getEntity();
    
    			result = EntityUtils.toString(entity, "UTF-8");
    
    		} catch (Exception e) {
    			LOG.error("HTTP POST 请求异常", e);
    
    		} finally {
    			// httpPost.abort();
    			httpPost.releaseConnection();
    		}
    
    		return result;
    	}
    
    	/**
    	 * 设置连接超时时间
    	 *
    	 * @param socketTimeout 连接时长,默认10秒
    	 */
    	public void setSocketTimeout(int socketTimeout) {
    		this.socketTimeout = socketTimeout;
    		resetRequestConfig();
    	}
    
    	/**
    	 * 设置传输超时时间
    	 *
    	 * @param connectTimeout 传输时长,默认30秒
    	 */
    	public void setConnectTimeout(int connectTimeout) {
    		this.connectTimeout = connectTimeout;
    		resetRequestConfig();
    	}
    
    	private void resetRequestConfig() {
    		requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
    	}
    
    	/**
    	 * 允许商户自己做更高级更复杂的请求器配置
    	 *
    	 * @param requestConfig 设置HttpsRequest的请求器配置
    	 */
    	public void setRequestConfig(RequestConfig requestConfig) {
    		this.requestConfig = requestConfig;
    	}
    
    }
    

    UnifiedOrderSp .java

    package com.dlys.pay.wechat;
    
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.stereotype.Component;
    
    import com.dlys.pay.wechat.protocol.pay_protocol.ScanPayReqDataSp;
    import com.dlys.pay.wechat.service.ScanPayService;
    import com.dlys.pay.wechat.util.Util;
    import com.dlys.pay.wechat.util.XMLParser;
    
    /**
     * 微信支付统一下单公用入口--服务商版本
     * 
     * @author libaibai
     * @version 1.0 2017年11月2日
     */
    @Component
    public class UnifiedOrderSp {
    
    	private static final Logger LOG = LogManager.getLogger(UnifiedOrderSp.class);
    
    	@Resource
    	private ScanPayService scanPayService; // wechat sdk
    
    	/**
    	 * 微信支付统一下单(JSAPI)
    	 */
    	public Map<String, Object> unifiedOrderJSAPI(String appid, String mch_id,String sub_appid, String sub_mch_id, String key,
    			String body, String detail, String attach, String out_trade_no, int total_fee, String spbill_create_ip,
    			String openid, String sub_openid) {
    
    		return this.unifiedOrder(appid, mch_id, sub_appid, sub_mch_id, key, body, detail, attach, out_trade_no, total_fee,
    				spbill_create_ip, "JSAPI", Util.getProduct_id(), openid, sub_openid);
    	}
    
    	
    	/**
    	 * 微信支付统一下单(JSAPI/NATIVE/APP方法均可)
    	 * 
    	 * @param appid 公众号的唯一标识
    	 * @param mch_id 微信支付分配的商户号
    	 * @param key 微信应用秘钥
    	 * @param body 商品名称
    	 * @param detail 商品详情(非必填)
    	 * @param attach 附加数据(非必填) - 目前存放车牌号或卡号
    	 * @param out_trade_no 商户订单号
    	 * @param total_fee 支付金额(单位:分)
    	 * @param spbill_create_ip 终端IP
    	 * @param trade_type 交易类型(JSAPI/NATIVE/APP)
    	 * @param product_id 商品ID(trade_type=NATIVE时,必填)
    	 * @param openid 用户标识(trade_type=JSAPI时,必填)
    	 * @return 响应信息
    	 */
    	private Map<String, Object> unifiedOrder(String appid, String mch_id, String sub_appid, String sub_mch_id,
    			String key, String body, String detail, String attach, String out_trade_no, int total_fee,
    			String spbill_create_ip, String trade_type, String product_id, String openid, String sub_openid) {
    
    		ScanPayReqDataSp data = new ScanPayReqDataSp(appid, mch_id, sub_appid, sub_mch_id, key, body, detail, attach,
    				out_trade_no, total_fee, spbill_create_ip, trade_type, product_id, openid, sub_openid);
    		// LOG.info("微信支付统一下单参数:" + JSONObject.fromObject(data).toString());
    		try {
    			String xmlMsg = scanPayService.requestSp(data);
    //			LOG.info("微信支付统一下单返回数据:" + XMLParser.getMapFromXML(xmlMsg));
    			return XMLParser.getMapFromXML(xmlMsg);
    
    		} catch (Exception e) {
    			LOG.error("微信支付统一下单时出错!", e);
    			return null;
    		}
    	}
    }
    

    以上是支付的工具类,基本上只要是微信支付API,都是通用的

     

    以下是业务代码,大家自行修改

    GetPayOrder.java

    package com.pay.wechat.bo;
    
    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.apache.commons.beanutils.BeanUtils;
    import org.apache.commons.lang.StringUtils;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.fastquery.service.FQuery;
    import org.springframework.stereotype.Component;
    
    import com.db.ParkingCarInfoDBService;
    import com.db.PayOrderDBService;
    import com.db.PunitDBService;
    import com.db.PunitParamDBService;
    import com.pay.bo.ParkingPayBo;
    import com.pay.bo.PayOrderBo;
    import com.pay.bo.PayOrderSpBo;
    import com.pay.wechat.UnifiedOrder;
    import com.pay.wechat.UnifiedOrderSp;
    import com.pay.wechat.WxPayBo;
    import com.pay.wechat.protocol.JsapiRequestData;
    import com.wsimpl.bo.operate.InvoiceBusinessBo;
    import com.wsimpl.bo.wx.WxCardBo;
    import com.bean.ParkingCarInfo;
    import com.bean.PayOrder;
    import com.bean.Punit;
    import com.bean.WxCard;
    import com.util.ChargeMoneyUtil;
    import com.util.Config;
    import com.util.Const;
    import com.util.bean.ChargeMoneyBean;
    import com.util.DateUtil;
    import com.util.lang.StringUtil;
    
    /**
     * 生成支付订单,微信统一下单,并返回调取JSAPI所需参数
     * 
     * @author libaibai
     * @version 1.0 2016年3月4日
     */
    @Component
    public class GetPayOrder {
    
    	private static final Logger LOG = LogManager.getLogger(GetPayOrder.class);
    
    	/* db */
    	private PunitDBService punitDBService = FQuery.getRepository(PunitDBService.class); // 物业单位
    	private PunitParamDBService punitParamDBService = FQuery
    			.getRepository(PunitParamDBService.class); // 物业单位
    	private PayOrderDBService payOrderDBService = FQuery.getRepository(PayOrderDBService.class); // 物业单位
    
    	private ParkingCarInfoDBService parkingCarInfoDBService = FQuery
    			.getRepository(ParkingCarInfoDBService.class); // 在场车辆信息
    
    	/* 微信支付相关 */
    	@Resource
    	private PayOrderBo payOrderBo; // 支付总订单
    
    	@Resource
    	private PayOrderSpBo payOrderSpBo; // 支付总订单-- 服务商
    
    	@Resource
    	private WxPayBo weChatBo; // 微信支付共用类
    
    	@Resource
    	private UnifiedOrder unifiedOrder; // 微信支付统一下单
    
    	@Resource
    	private UnifiedOrderSp unifiedOrderSp; // 微信支付统一下单 -- 服务商
    
    	@Resource
    	private ParkingPayBo parkingPayBo;
    
    	@Resource
    	private ChargeMoneyUtil chargeMoneyUtil;
    	
    	@Resource
    	private InvoiceBusinessBo invoiceBusinessBo;
    
    	/**
    	 * 执行方法
    	 * 
    	 * @param code
    	 * @param punitId
    	 * @param iden
    	 * @param chargeMoney
    	 * @return
    	 */
    	public Map<String, Object> get(String code, Long punitId, String iden, Double chargeMoney,
    			Long channelId, Long ruid, Long outTime, String cardId, String encryptCode) {
    		LOG.info("weixin_下单请求,punitId=" + punitId + ",iden=" + iden + ",chargeMoney=" + chargeMoney + 
    				",channelId=" + channelId + ",ruid=" + ruid + ",outTime=" + outTime);
    		
    		Map<String, Object> returnMap = new HashMap<String, Object>(); // 返回Map
    
    		// 参数不完整
    		if (punitId == null || punitId.longValue() <= 0 || code == null || "".equals(code.trim())) {
    			LOG.error("信息不完整,请返回重新进入,punitId=" + punitId + ",code=" + code);
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "信息不完整,请返回重新进入");
    			return returnMap;
    		}
    
    		// 获取停车场微信支付所需参数appid,mch_id,appSecret,key -- begin
    		Punit punit = punitDBService.findById(punitId);
    		if (punit == null) {
    			LOG.error("信息不完整,请返回重新进入,未找到停车场信息,punitId=" + punitId);
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "信息不完整,请返回重新进入");
    			return returnMap;
    		}
    
    		// 停车场对应公众号基本参数(云平台填入),如果是泊链支付,则直接使用德立云停车参数
    		String appid = punit.getAppId();
    		String mch_id = punit.getMchId();
    		String appSecret = punit.getAppSecret();
    		String key = punit.getWx_key();
    		String sub_mchId = punit.getSub_mchId();
    
    		// 微信支付所需参数不完整
    		if (StringUtils.isEmpty(mch_id) && StringUtils.isEmpty(sub_mchId)) {
    			LOG.error("信息不完整,请返回重新进入,必须参数不完整");
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "信息不完整,请返回重新进入");
    			return returnMap;
    		}
    		// 获取停车场微信支付所需参数appid,mch_id,appSecret,key -- end
    
    		// 判断是否启用服务商
    		Map<String, Object> map = punitParamDBService.findParam(punitId);
    		int isSpPay = 0;
    		if (map != null && !map.isEmpty()) {
    			isSpPay = Const.getInteger(map.get("isSpPay"));
    		}
    
    		// 使用德立云停车为服务商
    		String subappid = null;
    		String openid = null;
    		String sub_openid = null;
    		if (isSpPay == 1) {
    			appid = Config.APPID;
    			mch_id = Config.MCHIDSP;
    			appSecret = Config.APPSECRET;
    			key = Config.APIKEY;
    			openid = weChatBo.getOauth2Openid(appid, appSecret, code);
    		} else if (isSpPay == 2) {
    			subappid = Config.APPID;
    			sub_openid = weChatBo.getOauth2Openid(subappid, Config.APPSECRET, code);
    		} else {
    			openid = weChatBo.getOauth2Openid(appid, appSecret, code);
    		}
    		if (StringUtils.isEmpty(openid) && StringUtils.isEmpty(sub_openid)) {
    			LOG.error("信息不完整,请返回重新进入,openId为空, appid=" + appid + ",appSecret=" + appSecret + ",isSpPay=" + isSpPay + ",code=" + code);
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "信息不完整,请返回重新进入");
    			return returnMap;
    		}
    
    		// db查询-用户停车信息
    		ParkingCarInfo pcInfo = null;
    		try {
    			pcInfo = parkingCarInfoDBService.findByIden(iden);
    		} catch (Exception e) {
    			pcInfo = null;
    			LOG.error("根据iden查询停车信息时出错!", e);
    		}
    		// 无停车信息
    		if (pcInfo == null) {
    			LOG.error("信息不完整,请返回重新进入,未找到在场车辆信息,iden=" + iden);
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "信息不完整,请返回重新进入");
    			return returnMap;
    		}
    
    		// 判断是否二次缴费,0元不需要缴费
    		byte isEmptyPay = Const.getByte(map.get("isEmptyPay")); // 支持0元支付
    		if (pcInfo.getPayTime() != null && pcInfo.getPayTime() > 0 || isEmptyPay == 0) {
    			if (chargeMoney == null || chargeMoney.doubleValue() <= 0) {
    				returnMap.put("isPay", "0");
    				returnMap.put("errorMsg", "0元不需缴费");
    				return returnMap;
    			}
    		}
    		
    		// 重新计算缴费金额
    		ChargeMoneyBean chargeMoneyBean = null;
    		long orderDate = 0;
    		// 如果存在出场时间,而且在5分钟之内(考虑到存在时间差)
    		if (outTime != null && outTime > 0 && (Math.abs(DateUtil.getTimeStampLong() - outTime.longValue()) <= 5 * 60)) {
    			chargeMoneyBean = chargeMoneyUtil.getMoney(pcInfo, punit, outTime);
    			orderDate = outTime;
    		} else {
    			chargeMoneyBean = chargeMoneyUtil.getMoney(pcInfo, punit);
    			orderDate = DateUtil.getTimeStampLong();
    		}
    		double chargeMoneydb = StringUtil.getDoubleDecimal(Const.getDouble(chargeMoneyBean.getRealMoney()), 2);
    		if (chargeMoney.doubleValue() != chargeMoneydb) {
    			LOG.warn("weixin_下单失败,punitId=" + punitId + ", plateNum=" + pcInfo.getPlate() + ",页面金额chargeMoney=" + chargeMoney
    					+ ",重新计算金额chargeMoneydb=" + chargeMoneydb);
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "下单失败,请返回重新进入");
    			return returnMap;
    		}
    		double saleMoney = chargeMoneyBean.getSaleMoney();
    		Double shouldPay = chargeMoney;// 实付金额(可能会有优惠卷)
    		LOG.info("GetPayOrder-微信支付开始保存订单,punitId=" +punitId + ",plateNum=" +  pcInfo.getPlate() + ",iden=" + iden );
    		// 保存支付总订单表- (byte) 1
    		PayOrder payOrder = null;
    		if (isSpPay == 0) {
    			byte payway = 0; // 支付途径
    			payOrder = payOrderBo.savePayOrderToParkingPay(payway, (byte) 1, iden, punit.getTenantId(), punitId, ruid, pcInfo.getPlate(),
    					pcInfo.getCardNo(), pcInfo.getEntranceTime(), chargeMoney, appid, mch_id, openid, saleMoney, channelId, 0L, orderDate);
    		} else {
    			payOrder = payOrderSpBo.savePayOrderToParkingPay((byte) 1, iden, punit.getTenantId(), punitId, ruid, pcInfo.getPlate(),
    					pcInfo.getCardNo(), chargeMoney, saleMoney, appid, mch_id, openid, sub_mchId, pcInfo.getEntranceTime(), channelId, 0L, (byte) 0, orderDate);
    		}
    		if (payOrder == null) {
    			LOG.error("weixin_保存订单失败");
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "下单失败,请返回重新进入");
    			return returnMap;
    		}
    		
    		// 0元支付
    		if (chargeMoney.doubleValue() == 0) {
    			LOG.info("weixin-0元支付成功,punitId=" + punitId + ",plateNum=" + pcInfo.getPlate());
    			// 修改订单信息
    			PayOrder temp = FQuery.reset(PayOrder.class);
    			temp.setId(payOrder.getId());
    			temp.setPayState((byte) 1);
    			temp.setPayTime(DateUtil.getTimeStampLong());
    			payOrder = payOrderDBService.update(temp);
    			
    			// 处理在场车辆信息
    			parkingPayBo.handle(payOrder);
    			returnMap.put("isPay", "2");
    			returnMap.put("errorMsg", "支付成功");
    			return returnMap;
    		}
    
    		// 微信统一下单,调用公用入口
    		String body = punit.getUnitName() + "-停车费("
    				+ (pcInfo.getPlate() == null ? "" : pcInfo.getPlate()) + ")";
    		String detail = body; // 商品详情
    		String attach = pcInfo.getPlate(); // 车牌号
    		if (attach == null || "".equals(attach)) {
    			attach = pcInfo.getCardNo();
    		}
    		// 判断是否开通微信无感支付
    		if (Const.getByte(punit.getIsWxFreePay()) == 1) {
    			attach = "#*#{\"pn\":\""+pcInfo.getPlate()+"\",\"aid\":\""+appid+"\", \"vm\":\"true\"}#*#"; 
    			LOG.info("wx-判断是否开通无感支付,attach=" + attach + ",plateNum=" + pcInfo.getPlate());
    		}
    
    		String out_trade_no = payOrder.getPayOrderId();
    		Double payMoney = shouldPay * 100;
    		int total_fee = payMoney.intValue();
    		String spbill_create_ip = "127.0.0.1";
    		
    		//开发票参数
    		String receipt = null;
    		if(isSpPay==0){
    			boolean openWxFaPiaoByAfterPay = invoiceBusinessBo.isOpenWxFaPiaoByAfterPay(punitId, "LTC");
    			if(openWxFaPiaoByAfterPay){
    				receipt = "Y";
    			}
    		}
    
    		Map<String, Object> unifiedOrderMap = null;
    		if (isSpPay == 0) {
    			unifiedOrderMap = unifiedOrder.unifiedOrderJSAPI(appid, mch_id, key, body, detail,
    					attach, out_trade_no, total_fee, spbill_create_ip, openid,receipt);
    		} else {
    			unifiedOrderMap = unifiedOrderSp.unifiedOrderJSAPI(appid, mch_id, subappid, sub_mchId, key, body,
    					detail, attach, out_trade_no, total_fee, spbill_create_ip, openid, sub_openid);
    		}
    		if (unifiedOrderMap == null) {
    			returnMap.put("isPay", "0");
    			returnMap.put("errorMsg", "下单失败,请返回重新进入");
    			return returnMap;
    		}
    
    		// 下单成功,组装JSAPI调用所需参数
    		try {
    			if ("SUCCESS".equals(unifiedOrderMap.get("result_code"))) {
    
    				// 组装JSAPI调用所需参数
    				String timeStamp = DateUtil.getTimeStamp();
    				String nonceStr = Const.getStr(unifiedOrderMap.get("nonce_str"));
    
    				String package1 = "prepay_id=" + Const.getStr(unifiedOrderMap.get("prepay_id"));
    
    				JsapiRequestData jsapiRequestData = new JsapiRequestData(appid, key, timeStamp,
    						nonceStr, package1);
    				String paySign = jsapiRequestData.getPaySign();
    
    				// 组装页面响应Map
    				returnMap.put("isPay", "1");
    				returnMap.put("appid", appid);
    				returnMap.put("timeStamp", timeStamp);
    				returnMap.put("nonceStr", Const.getStr(unifiedOrderMap.get("nonce_str")));
    				returnMap.put("package1", package1);
    				returnMap.put("signType", "MD5");
    				returnMap.put("paySign", paySign);
    				returnMap.put("payOrderId", payOrder.getPayOrderId());
    			}
    		} catch (Exception e) {
    			LOG.error("下单成功,组装JSAPI调用所需参数时出错!", e);
    		}
    
    		return returnMap;
    	}
    
    	/**
    	 * 乘 2位小数 四舍五入
    	 * 
    	 * @param value1
    	 * @param value2
    	 * @return
    	 */
    	private Double mul(Double value1, Double value2) {
    		BigDecimal b1 = new BigDecimal(Double.toString(value1));
    		BigDecimal b2 = new BigDecimal(Double.toString(value2));
    		BigDecimal multiply = b1.multiply(b2);
    		return multiply.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    	}
    
    	/**
    	 * 减 2位小数 四舍五入
    	 * 
    	 * @param value1
    	 * @param value2
    	 * @return
    	 */
    	public Double sub(Double value1, Double value2) {
    		BigDecimal b1 = new BigDecimal(Double.toString(value1));
    		BigDecimal b2 = new BigDecimal(Double.toString(value2));
    		BigDecimal sub = b1.subtract(b2);
    		return sub.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    	}
    }
    

    后台下单成功之后,我们在jsp页面就可以调起微信支付了

    // 微信公众号支付
    function weixinpay (wxCode, punitId, iden, chargeMoney, channelId) {
    	var encryptCode=$("#encryptCode").val();
    	var cardId=$("#cardId").val();
    	var outTime=$("#outTime").val();
    	
    	// 统一下单返回JS调取支付所需参数
    	$.tenetAjax({
    		url: PATH + "/punitWS/getPayOrder",
    		data: {'code':wxCode,'punitId':punitId,'iden':iden,'chargeMoney':chargeMoney,'channelId':channelId, 'outTime':outTime, 'cardId':cardId,'encryptCode':encryptCode},//卡券传值
    		async: false,
    		success: function(data){
    			//alert(JSON.stringify(data));
    			if(data.payOrderMap==null){
    				$("#iformbtndID").html('<a class="btna bg1">支付失败,请返回重新进入</a>');
    				return;
    			}
    			
    			var isPay = data.payOrderMap.isPay;
    			var errorMsg = data.payOrderMap.errorMsg;
    			if(isPay==null || isPay==0){
    				alert(errorMsg);
    				$("#iformbtndID").html('<a class="btna bg1">'+errorMsg+'</a>');
    				return;
    			} else if (isPay==2) {
    				$("#iformbtndID").html('<p>支付成功</p>');
    				return;
    			}
    			
    			// JS调取微信支付
    			var appid = data.payOrderMap.appid;
    			var timeStamp = data.payOrderMap.timeStamp;
    			var nonceStr = data.payOrderMap.nonceStr;
    			var package1 = data.payOrderMap.package1;
    			var signType = data.payOrderMap.signType;
    			var paySign = data.payOrderMap.paySign;
    			var payOrderId = data.payOrderMap.payOrderId;
    			if (typeof window.WeixinJSBridge == "undefined"){
    				$(document).on('WeixinJSBridgeReady',function(){ 
    					onBridgeReady(appid, timeStamp, nonceStr, package1, signType, paySign, payOrderId);
    				})
    			} else {
    				onBridgeReady(appid, timeStamp, nonceStr, package1, signType, paySign, payOrderId);
    			}
    		}
    	});
    }
    
    
    // JS调取微信支付
    function onBridgeReady(appId, timeStamp, nonceStr, package1, signType,
    		paySign, payOrderId) {
    	WeixinJSBridge.invoke('getBrandWCPayRequest', {
    		"appId" : appId, //公众号名称,由商户传入
    		"timeStamp" : timeStamp, //时间戳,自1970年以来的秒数
    		"nonceStr" : nonceStr, //随机串
    		"package" : package1, //订单详情扩展字符串
    		"signType" : signType, //微信签名方式MD5
    		"paySign" : paySign
    	//微信签名
    	}, function(res) {
    		// 			alert(res.err_msg);
    		if (res.err_msg == null) {
    			$("#iformbtndID").html('<a class="btna bg1">支付失败,请返回重新进入</a>');
    			return;
    		}
    
    		// 支付成功
    		if (res.err_msg == "get_brand_wcpay_request:ok") {
    			var punitId = $("#punitId").val();
    			var stayTime = $("#outDelayID").text();
    			var unitName= $("#unitNameID").text();
    			var chargeMoney = $("#chargeMoney").val();
    			window.location.href="paysuc?punitId="+punitId+"&payOrderId="+payOrderId+"&stayTime="+stayTime+"&unitName="+unitName+"&payMoney="+chargeMoney;
    			return;
    		} else {
    			$("#iformbtndID").html('<a class="btna bg1">支付失败,请返回重新进入</a>');
    			return;
    		}
    	});
    }
    

     

    ok,微信支付就到此结束了

    展开全文
  • 微信支付服务商模式

    千次阅读 2019-03-03 21:24:00
    今天使用微信支付服务商模式开发的时候,遇到了一些。特记录下 https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_1 官方的文档,写的真的很难懂。demo也是普通商户的。 在支付的时候。几个参数...

    今天使用微信支付服务商模式开发的时候,遇到了一些。特记录下

    https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=9_1

    官方的文档,写的真的很难懂。demo 也是普通商户的。

    在支付的时候。几个参数需要注意下

    appid. 这个填服务商公众号的那个appid

    mch_id 填服务商的商户号

    sub_appid 这个填子商户公众号的appid

    sub_mch_id 填服务商下的子商户的mc_id

    sub_openid 填子商户公众号获取的openid

    举个例子:

    A有申请了公众号,然后有一个appid 为 "Wxaaaaaa",然后需要将B公众号的 "Wxbbbb"关联下。

    这个时候,需要用A的公众号去申请服务商模式。得到一个服务商的mc_id = M_00001.然后创建了一个子商户为 M_son_001并关联了B公众号的Wxbbbb

    然后b的项目 需要获取openid=Ox1111。 然后用A的服务商账号进行支付。

    在上面的例子中 

    appid=wxaaaa

    sub_appid=Wxbbbb

    mch_id = M_0001.

    sub_mch_id=M_son_001

    sub_openid=Ox1111

    请求的时候openid参数不用传递。只用传递sub_openid和sub_appid即可

    转载于:https://www.cnblogs.com/tl542475736/p/10467729.html

    展开全文
  • 一些学员看过子恒老师《微信支付服务商申请》的视频, 说在申请过程中, 需要提交一份‘服务商开发能力说明文档’。 用自己写的, 提交上去后, 没有通过。 学员就问子恒老师, 能不能提供一份微信服务商开发能力...
  • 最近客户有个需求:客户使用微信完成付款后会... 所以就有了以下解决方案; 一、在原有的公众号下申请服务商(如图)按照流程完成申请: ... ...三、使用你收到的微信支付服务商账号登录https://pay.weixin.qq.com/进...
  • springboot集成微信支付服务商版之小程序支付 一、说明: 通过引入依赖实现微信支付,是非常方便的; 但是官方的SDK没有服务商版,以下是在原SDK的基础上封装了服务商版,共勉; 二、准备参数 1.特约商户创建的小...
  • springboot集成微信支付服务商版之付款码支付 一、说明: 通过引入依赖实现微信支付,是非常方便的; 但是官方的SDK没有服务商版,以下是在原SDK的基础上封装了服务商版,共勉; 二、开发步骤 1.在pom.xml中引入...
  • 随着智能手机的普及, 越来越多的人使用手机上网和购物, ...网络公司需要成为微信支付服务商, 接着可以开发出一个业务平台, 让传统企业在平台上销售产品, 网上支付可以通过网络公司在微信支付中的账号,
  • 微信支付服务商加密字段解析 $decrypted = '解析出来的内容'; $key = '商户私钥'; openssl_private_decrypt(base64_decode('加密内容'),$decrypted='',$key,OPENSSL_PKCS1_OAEP_PADDING)
  • springboot集成微信支付服务商版之付款码支付 一、说明: 通过引入依赖实现微信支付,是非常方便的; 但是官方的SDK没有服务商版,以下是在原SDK的基础上封装了服务商版,共勉; 二、开发步骤 1.在pom.xml中引入...
  • 微信支付服务商验收流程文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=23_1 1、服务商配置 服务商平台配置子商户,获取子商户的支付授权 公众号支付,在子商户开发配置中设置JSAPI...
  • 微信支付服务商以及特约商户相关总结服务商特约商户与普通商户的区别服务商特约商户申请流程 服务商特约商户与普通商户的区别 服务商不能给自己申请特约商户,自己没有支付能力; 服务商只能新申请子商户(特约...
  • 由于微信支付服务商对技术要求很高, 而且又可以帮助传统企业开发业务平台, 所以想要使用服务商的强大功能, 必须要先通过微信的认证。 如果你是一直跟随着子恒老师的课程走过来的, 已经知道了很多微信...
  • 2、服务商收益:服务商提供点金计划相关技术服务,由微信支付服务商支付返佣奖励; 3、服务商管理工具:可在服务商平台对特约商户开通/关闭点金计划,以及为特约商户配置同业过滤标签,过滤所选行业的广告。同时...
  • 修改了普通商户的微信支付demo,使服务商模式的微信支付在填写参数正确的情况下直接可以使用,demo中一些修改的地方也打上了注释来区分服务商和子商户的参数,也可以配合下文参考: ...
  • 整合了微信最新的支付文档,该demo中有支付和打款给个人银行卡和微信零钱,自己公司开发的,已经线上运行,没有任何问题
  • 背景:已完成微信支付商户模式的开发,微信支付需要转换为服务商形式 微信服务商的子商户是特约商户,这个特约商户需要由服务商账号在微信服务商平台进行重新申请,不能将旧的商户直接绑定到服务商下面。后续服务...
  • 微信支付服务商模式
  • 微信支付服务商平台于2018年7月份悄然在【账户中心】的【API安全】中增加了一个“API 证书(权威CA颁发)”版块,由于和原来的“API证书”版块命名相似,着实让很多服务商懵了一下,不知道这是干啥用的,然道是比...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,708
精华内容 8,283
关键字:

微信支付服务商