微信:微信扫码支付、调用统一下单接口、网站支付 + springmvc

7 篇文章 0 订阅
4 篇文章 0 订阅

一、场景:公司需要在网站上进行微信支付。

二、API:使用微信开放平台的接入微信支付


-扫码支付。 微信支付开发者平台链接

三、分析:

  1. 接入扫码支付(包含PC网站支付)包含三个阶段,问这里只讲使用,也就是第2阶段的《启动设计和开发》。
  2. 点击查看开发者文档(扫码支付)后,这里感觉微信的文档没有支付宝好理解(稍微吐槽下~~~),不过我们忽略一切,直接进入模式二:模式二最简单直接,不需要在商户后台进行配置,推荐大家使用,微信也说流程更为简单,我这里也讲的是模式二,模式一大家有兴趣可以自行研究下。
  3. 如上图,总流程有14步,主要流程是生成订单、调统一下单API、将返回的支付交易链接生成二维码展示;我这边主要就是将这三步结合springmvc后,成功生儿二维码之后,用户就可以扫码支付了。后面的回调跟跟我的另一篇博文基本类似,大家借鉴下就行了:支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc

四、实现:

  1. 准备:根据统一下单接口API我先定义了三个对象:UnifiedOrderRequest(统一下单请求参数(必填))、UnifiedOrderRequestExt(统一下单请求参数(非必填))、UnifiedOrderRespose(统一下单返回参数);具体如下代码,get、set方法可自行生产,太占篇幅。

    UnifiedOrderRequest.class
    /**
     * 统一下单请求参数(必填)
     * @author Y
     *
     */
    public class UnifiedOrderRequest {
    	private String appid;				//公众账号ID
    	private String mch_id;				//商户号
    	private String nonce_str;			//随机字符串
    	private String sign;				//签名
    	private String body;				//商品描述
    	private String out_trade_no;		<span style="white-space:pre">	</span>//商户订单号
    	private String total_fee;			//总金额
    	private String spbill_create_ip;	<span style="white-space:pre">	</span>//终端IP
    	private String notify_url;			//通知地址
    	private String trade_type;			//交易类型
    }
    UnifiedOrderRequestExt.class
    /**
     * 统一下单请求参数(非必填)
     * @author Y
     *
     */
    public class UnifiedOrderRequestExt extends UnifiedOrderRequest{
    	
    	private String device_info;			//设备号
    	private String detail;				//商品详情
    	private String attach;				//附加数据
    	private String fee_type;			//货币类型
    	private String time_start;			//交易起始时间
    	private String time_expire;			//交易结束时间
    	private String goods_tag;			//商品标记
    	private String product_id;			//商品ID
    	private String limit_pay;			//指定支付方式
    	private String openid;				//用户标识
    }
    UnifiedOrderRespose.class
    /**
     * 统一下单返回参数
     * @author Y
     *
     */
    public class UnifiedOrderRespose {
    	private String return_code;				//返回状态码
    	private String return_msg;				//返回信息
    	private String appid;					//公众账号ID
    	private String mch_id;					//商户号
    	private String device_info;				//设备号
    	private String nonce_str;				//随机字符串
    	private String sign;					//签名
    	private String result_code;				//业务结果
    	private String err_code;				//错误代码
    	private String err_code_des;			<span style="white-space:pre">	</span>//错误代码描述
    	private String trade_type;				//交易类型
    	private String prepay_id;				//预支付交易会话标识
    	private String code_url;				//二维码链接
    }
  2. Controller主入口:
    	/**
    	 * 创建二维码
    	 */
    	@RequestMapping("createQRCode")
    	public void createQRCode(String orderId, HttpServletResponse response) {
    		
    		//生成订单
    		String orderInfo = createOrderInfo(orderId);
    		//调统一下单API
    		String code_url = httpOrder(orderInfo);
    		//将返回预支付交易链接(code_url)生成二维码图片
    		//这里使用的是zxing   <span style="color:#ff0000;"><strong>说明1(见文末)</strong></span>
    		try {
    			int width = 200;
    			int height = 200;
    			String format = "png";
    			Hashtable hints = new Hashtable();
    			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
    			BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);
    			OutputStream out = null;
    			out = response.getOutputStream();
    			MatrixToImageWriter.writeToStream(bitMatrix, format, out);
    			out.flush();
    			out.close();
    		} catch (Exception e) {
    		}
    
    	}

  3. 生成订单:分两部分:一部分是业务需求的订单信息,就是发起支付前的订单信息,业务系统自行创建存储;另一部分是满足统一下单API要求的订单信息(也是我们这里要讲的)。“xxxxxx”:是你需要自己填写的对应信息:
    	/**
    	 * 生成订单
    	 * @param orderId
    	 * @return
    	 */
    	private String createOrderInfo(String orderId) {
    		//生成订单对象
    		UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
    		unifiedOrderRequest.setAppid("xxxxxxxxxxxxx");//公众账号ID
    		unifiedOrderRequest.setMch_id("xxxxxxxxx");//商户号
    		unifiedOrderRequest.setNonce_str(StringUtil.makeUUID());//随机字符串       <span style="color:#ff0000;"><strong>说明2(见文末)</strong></span>
    		unifiedOrderRequest.setBody("xxxxxx");//商品描述
    		unifiedOrderRequest.setOut_trade_no(orderId);//商户订单号
    		unifiedOrderRequest.setTotal_fee("x");	//金额需要扩大100倍:1代表支付时是0.01
    		unifiedOrderRequest.setSpbill_create_ip("xxxxxxxxxxxxx");//终端IP
    		unifiedOrderRequest.setNotify_url("xxxxxxxxxxxxxx");//通知地址
    		unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
    		unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//签名<span style="color:#ff0000;"><strong>说明5(见文末,签名方法一并给出)</strong></span>
    		//将订单对象转为xml格式
    		XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); //<span style="color:#ff0000;"><strong>说明3(见文末)</strong></span>
    		xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
    		return xStream.toXML(unifiedOrderRequest);
    	}

  4. 调统一下单API:根据要求将生成订单中返回的xml向微信给定的统一下单URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder,发送请求,成功并获得二维码。
    	/**
    	 * 调统一下单API
    	 * @param orderInfo
    	 * @return
    	 */
    	private String httpOrder(String orderInfo) {
    		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    		try {
    			HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
    			//加入数据  
                conn.setRequestMethod("POST");  
                conn.setDoOutput(true);  
                  
                BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());  
                buffOutStr.write(orderInfo.getBytes());
                buffOutStr.flush();  
                buffOutStr.close();  
                  
                //获取输入流  
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));  
                  
                String line = null;  
                StringBuffer sb = new StringBuffer();  
                while((line = reader.readLine())!= null){  
                    sb.append(line);  
                }  
                
                XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//说明3(见文末)
                //将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
                xStream.alias("xml", UnifiedOrderRespose.class);
                UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
                
                //根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
                //<span style="color:#ff0000;"><strong>说明4(见文末)</strong></span>
                if(null!=unifiedOrderRespose 
                		&& "SUCCESS".equals(unifiedOrderRespose.getReturn_code()) 
                		&& "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
                	return unifiedOrderRespose.getCode_url();
                }else{
                	return null;
                }
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}

  5. 将返回的支付交易链接生成二维码展示:没有异常的情况下,在页面中使用<img>标签接收就行。实际使用时,结合前端和业务的需求放置二维码。可以在扫码支付/案例及规范中找到部分素材和界面规范来设计微信风格的支付页面。
    <img src="${ctx}/wxPay/createQRCode?orderId=1111" width="174px">

  6. 用户可以通过维系客户端进行扫码支付。支付完成后回调我们notify_url设置的url,通过成功的回调来更改业务系统中的订单状态或者一些业务需求。这里回调没有写出可以参考支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc中的回调。

五、说明:

  1. 二维码可以查看zxing实现二维码生成和解析;微信这边也提供了二维码的学习,大家有兴趣可以看看:http://www.thonky.com/qr-code-tutorial/ 和http://coolshell.cn/articles/10590.html

  2. 随机字符串:微信对随机字符串的要求是不超过32位。我这边是这样生成的,用时间戳。
    	/**
    	 * 创建UUID
    	 * @return
    	 */
    	public static synchronized String makeUUID() {
    		Date date = new Date();
    		StringBuffer s = new StringBuffer(DateUtil.formatYmdhmsm(date));
    		return s.append((new Random().nextInt(900) + 100)).toString();
    	}



  3. 使用Xstream时,由于微信定义的变量名大部分使用了“_”,但是在Xstream中它是关键字,所以会自动变为“__”,引起报错。详情请看:XStream异常:对象转为XML时,会把"_"转成"__";报错:(Lcom/thoughtworks/xstream/io/naming/NameCoder;)V

  4. 获取二维码链接时,只有在return_code 和result_code都为SUCCESS的时候有返回;这里我就简单的满足时返回,不满足返回null,您写的时候需要结合业务考虑下,是否需要增加判断,从而满足不同的业务场景。统一下单API

  5. 签名在上面一直没有详细说明,首先查看微信的安全规范中签名算法。key值,需要自己填写
    	/**
    	 * 生成签名
    	 * 
    	 * @param appid_value
    	 * @param mch_id_value
    	 * @param productId
    	 * @param nonce_str_value
    	 * @param trade_type 
    	 * @param notify_url 
    	 * @param spbill_create_ip 
    	 * @param total_fee 
    	 * @param out_trade_no 
    	 * @return
    	 */
    	private String createSign(UnifiedOrderRequest unifiedOrderRequest) {
    		//根据规则创建可排序的map集合
    		SortedMap<String, String> packageParams = new TreeMap<String, String>();
    		packageParams.put("appid", unifiedOrderRequest.getAppid());
    		packageParams.put("body", unifiedOrderRequest.getBody());
    		packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
    		packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
    		packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());
    		packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
    		packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());
    		packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());
    		packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());
    
    		StringBuffer sb = new StringBuffer();
    		Set es = packageParams.entrySet();//字典序
    		Iterator it = es.iterator();
    		while (it.hasNext()) {
    			Map.Entry entry = (Map.Entry) it.next();
    			String k = (String) entry.getKey();
    			String v = (String) entry.getValue();
    			//为空不参与签名、参数名区分大小写
    			if (null != v && !"".equals(v) && !"sign".equals(k)
    					&& !"key".equals(k)) {
    				sb.append(k + "=" + v + "&");
    			}
    		}
    		//第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    		sb.append("key=" +"xxxxxxxxxxxxxxxxx");
    		String sign = MD5Util.MD5Encode(sb.toString(), "utf-8")
    				.toUpperCase();//MD5加密
    		return sign;
    	}


相关文章:支付宝:web页面扫码支付、网站支付、支付宝即时到账 + springmvc













  • 8
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 32
    评论
### 回答1: 好的,下面是一个基于Spring MVC框架的小程序支付接口的示例代码: 1. 配置文件: 在Spring的配置文件中,需要配置微信支付相关的参数,包括商户号、AppID、商户密钥等信息。可以将这些参数放在properties文件中,通过Spring的属性注入来获取。 ``` <!-- 微信支付配置 --> <util:properties id="wxpayConfig" location="classpath:wxpay.properties"/> <!-- 微信支付服务 --> <bean id="wxpayService" class="com.example.wxpay.WxPayService"> <property name="mchId" value="${wxpayConfig.mchId}"/> <property name="appId" value="${wxpayConfig.appId}"/> <property name="mchKey" value="${wxpayConfig.mchKey}"/> </bean> <!-- Spring MVC 配置 --> <mvc:annotation-driven/> <context:component-scan base-package="com.example.controller"/> ``` 2. Controller: 在Controller中,需要编写处理支付请求的方法。该方法接收支付订单信息,调用微信支付API生成预支付订单,并将生成的预支付订单信息返回给前端。在用户确认支付后,再调用微信支付API完成支付。 ``` @Controller @RequestMapping("/wxpay") public class WxPayController { @Autowired private WxPayService wxpayService; @RequestMapping("/createOrder") @ResponseBody public Map<String, String> createOrder(@RequestBody Map<String, Object> order) throws Exception { String body = (String) order.get("body"); String outTradeNo = (String) order.get("out_trade_no"); int totalFee = (int) order.get("total_fee"); Map<String, String> params = new HashMap<>(); params.put("body", body); params.put("out_trade_no", outTradeNo); params.put("total_fee", String.valueOf(totalFee)); params.put("trade_type", "JSAPI"); params.put("openid", "用户的openid"); Map<String, String> result = wxpayService.createOrder(params); Map<String, String> response = new HashMap<>(); response.put("appId", wxpayService.getAppId()); response.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); response.put("nonceStr", result.get("nonce_str")); response.put("package", "prepay_id=" + result.get("prepay_id")); response.put("signType", "MD5"); response.put("paySign", wxpayService.generatePaySign(response)); return response; } @RequestMapping("/notify") @ResponseBody public String notify(@RequestBody String xmlData) throws Exception { Map<String, String> result = wxpayService.parsePayResult(xmlData); // 处理支付结果 return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"; } } ``` 3. WxPayService: WxPayService是一个封装了微信支付API的服务类,用于生成预支付订单、处理支付结果等操作。 ``` @Service public class WxPayService { private String mchId; private String appId; private String mchKey; // 省略构造函数和Getter/Setter方法 public Map<String, String> createOrder(Map<String, String> params) throws Exception { SortedMap<String ### 回答2: 要编写一个基于Spring MVC架构的小程序支付接口,我们可以按照以下步骤进行: 1. 首先,我们需要搭建一个Spring MVC项目。在pom.xml文件中添加相关的依赖,如Spring MVC、Spring Boot、MyBatis等。 2. 接下来,我们需要配置Spring MVC。创建一个配置类,使用@EnableWebMvc注解开启Spring MVC功能,并配置视图解析器、静态资源访问、拦截器等。 3. 编写一个支付Controller,用于接收小程序请求并处理支付逻辑。我们可以使用@RequestMapping注解来定义支付接口的URL地址和请求方式。例如,可以定义一个支付接口为/pay,请求方式为POST。 4. 在Controller中,我们可以通过@RequestParam注解来获取小程序发来的参数,例如订单号、商品描述、金额等。 5. 在支付接口中,我们可以使用第三方支付平台的SDK来发起支付请求。例如,可以使用支付宝SDK或微信支付SDK。根据所选支付平台的具体文档,我们可以编写相应的代码,调用支付API,将支付参数传递给支付平台,并获取支付结果。 6. 处理支付结果。根据支付平台的返回结果,我们可以判断支付是否成功,并进行相应的处理。例如,可以更新订单状态、发送支付成功通知等。 7. 最后,我们可以编写一个简单的测试页面,用于模拟小程序发送支付请求。在页面中,我们可以填写订单号、商品描述、金额等,并通过Ajax方式调用支付接口。 这样,一个基于Spring MVC架构的小程序支付接口就完成了。我们可以通过扫描小程序的支付码或调用小程序的支付API,实现支付功能。同时,通过合理的异常处理和日志记录,我们可以提高支付接口的可靠性和可维护性。 ### 回答3: 在基于Spring MVC架构的小程序支付接口中,我们可以使用以下步骤来实现: 1. 首先,我们需要在Spring MVC配置文件中配置相关的bean,包括必要的依赖关系和初始化参数。 2. 接下来,我们需要编写一个控制器类,用于处理来自小程序的支付请求。可以使用@RequestMapping注解来映射URL路径和请求方法。 3. 在控制器类中,我们可以编写一个处理支付请求的方法。在该方法中,我们可以使用微信支付的API来生成预支付订单,包括商品信息、订单号、金额等。 4. 接着,我们可以将预支付订单信息返回给小程序端,小程序可以根据返回数据调起微信支付的界面。在支付界面中,用户需要输入支付密码或选择其他支付方式进行支付。 5. 支付完成后,微信支付会回调设置的回调URL,我们可以编写一个处理回调的方法来接收微信支付的通知。在该方法中,我们可以对支付结果进行验证,包括订单号、金额、支付状态等。 6. 验证通过后,我们可以更新订单状态为已支付,并进行相关业务处理,比如发货、生成发票等。 7. 最后,我们可以返回支付结果给小程序端,用于展示支付成功或失败的界面。 在以上过程中,我们可以使用Spring MVC提供的注解、组件和工具来简化开发。同时,需要注意支付接口的安全性,比如对支付订单的合法性进行验证,使用HTTPS进行通信等。此外,还需要了解微信支付的相关文档和规范,根据实际需求来定制开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值