** 支付解决方案_微信扫码支付*

版权声明:文章为作者自己原创文章,转载请注明出处。 https://blog.csdn.net/qq_37128049/article/details/85028599

课程目标

1.  掌握二维码生成插件qrious的使用
2.  能够说出微信支付开发的整体思路
3.  能够调用微信支付接口(统一下单)生成支付二维码
4.  能够调用微信支付接口(查询订单)查询支付状态
5.  实现支付日志的生成与订单状态的修改

二维码

  1. 什么是二维码

    1. 二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。

    2. 二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。

    3. 图示:

  2. 二维码的优势:

    1. 信息容量大, 可以容纳多达1850个大写字母或2710个数字或500多个汉字
    2. 应用范围广, 支持文字,声音,图片,指纹等等…
    3. 容错能力强, 即使图片出现部分破损也能使用
    4. 成本低, 容易制作
  3. 二维码的容错级别:
    L级(低) 7%的码字可以被恢复。
    M级(中) 的码字的15%可以被恢复。
    Q级(四分)的码字的25%可以被恢复。
    H级(高) 的码字的30%可以被恢复。

二维码生成插件qrious:

  1. qrious是一款基于HTML5 Canvas的纯JS二维码生成插件。通过qrious.js可以快速生成各种二维码,你可以控制二维码的尺寸颜色,还可以将生成的二维码进行Base64编码。

  2. qrious.js二维码插件的可用配置参数如下:

  3. 释义:

    • 方块确定方位,黑色代表1,白色代表0

微信扫码支付

1. 介绍:
	* 微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于 PC 网站支付、实体店单品或订单支付、媒体广告支付等场景。
2. 申请步骤:(了解)
	1. 第一步:注册公众号(类型须为:服务号)
		请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型。

	2. 第二步:认证公众号
		公众号认证后才可申请微信支付,认证费:300 元/次。

	3. 第三步:提交资料申请微信支付
		登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为 1-5个工作日内。

	4. 第四步:开户成功,登录商户平台进行验证
		资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。

	5. 第五步:在线签署协议
		本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。

微信支付SDK

1. 微信支付接口调用的整体思路:
	* 按 API 要求组装参数,以 XML 方式发送(POST)给微信支付接口(URL),微信支付接口也是以 XML 方式给予响应。程序根据返回的结果(其中包括支付 URL)生成二维码或判断订单状态
	* 简单来讲:通过URL将一些参数告诉给微信,然后接受返回值生成二维码

2. 释义:
	1. appid:微信公众账号或开放平台 APP 的唯一标识
	2. mch_id:商户号 (配置文件中的 partner)
	3. partnerkey:商户密钥
	4. sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性【每次都不同】

3. 微信支付SDK
	* 微信支付提供了 SDK, 下载后打开源码,install 到本地仓库;
	* 导入依赖:
		<dependency>
		<groupId>com.github.wxpay</groupId>
		<artifactId>wxpay-sdk</artifactId>
		<version>0.0.3</version>
		</dependency>

4. 我们主要会用到微信支付 SDK 的以下功能:
	1. 获取随机字符串
		WXPayUtil.generateNonceStr()

	2. MAP 转换为 XML 字符串(自动添加签名)
		WXPayUtil.generateSignedXml(param, partnerkey)

	3. XML 字符串转换为 MAP
		WXPayUtil.xmlToMap(result)

5. HttpClient工具类
	1. 介绍:
		1. HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目Cactus 和 HTMLUnit 都使用了 HttpClient。HttpClient 
		2. 通俗的讲就是模拟了浏览器的行为,如果我们需要在后端向某一地址提交数据获取结果,就可以使用 HttpClient.
		3. 关于 HttpClient(原生)具体的使用不属于我们本章的学习内容,我们这里这里为了简化 HttpClient 的使用,提供了工具类 HttpClient(对原生 HttpClient 进行了封装)

	2. HttpClient工具类使用的步骤:
		
			HttpClient client=new HttpClient(请求的 url 地址);
			client.setHttps(true);//是否是 https 协议
			client.setXmlParam(xmlParam);//发送的 xml 数据
			client.post();//执行 post 请求
			String result = client.getContent(); //获取结果

查询状态

思路:
	* 前端循环调用后端
	* 后端循环调用微信支付查询结果,前端调用后端


2. 交易状态类型:
	* SUCCESS: 支付成功
	* REFUND : 转入退款
	* NOTPAY:	未支付
	* CLOSED:  已关闭
	* REVOKED: 已撤销
	* USERPAYING: 用户支付中
	* PAYERROR: 支付失败(其他原因,银行返回失败)
	* 支付状态机等可以查看相关文档

支付日志需求

* 思路:
	* 在用户下订单时,判断如果为微信支付,就向支付日志表添加一条记录,信息包括支付总金额,订单id(多个),用户id,下单时间等信息,支付状态为0(未支付);

	* 生成的支付日志对象放入reids中,以用户id作为key,这样在生成支付二维码时就可以从redis中提取支付日志对象中的金额和订单号;

	* 当用户支付成功后,修改支付日志的支付状态为1(已支付),并记录微信传递给我们的交易流水号。根据订单id(多个)修改订单的状态为2(已付款).

微信支付准备:

1. 业务流程:
	1. 选择商品以及相应的规格和数量后点击"加入购物车"。
	2. 当加入购物车后跳转到购物车列表页面,对收货地址,商品添加或者删除等操作后点击"结算"
	3. 当带着参数进入结算页的时候,首先对使用微信支付和货到付款等方式进行判断,然后跳转到相应的页面
	4. 【今日】页面通过与微信官方交互然后自动生成二维码,用户扫码之后显示"付款成功"或者"付款失败"等.


2. 技术分析[准备阶段]:
	1. 微信支付功能必须为服务号才能申请微信付款功能,这个由公司完成并提供给我们相关的账户和密码;
	2. 查看微信支付SDK文档,获取大概的流程;
	3. 首先应该在本地仓库中配好微信支付SDK的jar包,并引入微信支付SDK的依赖
	4. 使用HttpClient工具类,方便向微信官方发送请求和接收请求;
	5. 搭建工程,分为消费方和服务方,消费方应该直接放入用户加入购物车的消费项目里,服务方加入服务方,服务方分成interface和service解耦合;
	6. 应该引入HttpClient.java工具类和添加依赖,添加properties配置文件[这里的配置文件应该为商户的信息,如appid,partner,partnerkey...等]

支付流程图

1. 首先生成微信二维码:

		1. 准备:
			1. 通过HttpClient工具类实现对远程支付接口的调用
			2. 接口连接:https://api.mch.weixin.qq.com/pay/unifiedorder
			1. 参考文档:统一下单API
		2. 开始:
			1. interface:接口服务层应该建立一个生成微信二维码的接口
			2. serviceimpl:注入properties中的配置文件,创建一个生成二维码的方法createNative
				* 创建一个map集合,将需要发送给微信的数据存入map集合内
				* 通过WXPayUtil工具类将集合内的数据转为XML格式数据
				* 通过HttpClient发送给微信
				* 获取XML结果后调用WXPayUtil工具类将它转为Map格式的数据
				* 创建一个新的Map集合,将获取的结果存入新建的map集合内		【这里的数据是要展现给前端的,所以只存一些需要展示的,不必所有都存入,否则安全性有影响】
				* 将集合返回

			3. Controller:
				1. 通过@Reference注解注入Service的类:WeixinPayService
				2. 建立一个生成微信二维码的方法,调用雪花算法将订单号和支付类型作为方法参数调用Serivec的createNative,将得到的map集合返回上去;

			4. payService.js:
				1. 建立一个本地支付的方法,指向pay/createNative.do [Controller.java类的生成二维码方法]
			5. payController.js:
				1. 建立一个本地生成二维码的方法,前端页面调用此方法进行查询后端,获取结果后得到订单编号和金额大小,同时在这里生成二维码,将订单编号和金额大小都返回到前端页面;

			6. pay.html:
				1. 首先引入js相关文件,qrious.min.js创建二维码的js文件,以及绑定ng-app,ng-controller,初始调用ng-init生成二维码功能
				2. 将放置二维码图片的地方<img id="qrious">
				3. 显示订单:订单号:{{out_trade_no}}      显示金额:<em class="orange money">¥{{money}}</em>元

2. 然后,检测支付状态:

		1. 准备:
			1. 需求:
				* 当用户支付成功的时候我们应该跳转到成功页面,提示:恭喜您,付款成功啦!,支付方式:微信支付  支付金额:xxxx元
				* 当用户支付失败的时候我们应该跳转到失败页面,提示:支付失败,请稍后再试!  失败原因:...   提供一个重新支付按钮以及跳转到品优购首页的功能

			2. 实现思路:
				1. 我们可以通过HttpClient工具类实现对远程支付接口的调用
				2. 微信接口链接:
						https://api.mch.weixin.qq.com/pay/orderquery
				3. 参考文档: 查询订单API
				4. 思路:
					1. 我们可以在后端建立查询状态方法,方法内通过循环查询,如果获取到结果则进行判断:
						* 如果结果为Null,则返回空map集合,
						* 如果有值,则返回给controller,再返回给前端
					2. 前端进行循环调用查询状态方法。前端controller.js对返回的结果进行判断:
						1. 如果map==null,则提示支付出错,跳出循环判断,
						2. 如果map.get("trade_state").equals("SUCCESS"),那么则返回支付成功,
						3. 同时程序可以使用Thread进行睡眠,Thread.sleep(3000),此方法可以使循环查询每三秒执行一次

					
		2. 开始:
			1. interface:
				* 创建查询状态方法,接收参数订单编号
			2. serviceImpl:
				* 实现查询状态方法,新建一个HashMap,然后存入公众号id,商户号id,订单号,随机字符串,以及查询订单状态的url地址;【URL地址是微信提供的,其他通过配置文件注入和参数接收】
				* 通过WXPayUtil将Map集合转为XML格式的字符串,然后通过HttpClient传入url地址发送获取状态;
				* 接收状态并将其转为Map集合,然后返回结果,如果获取失败则打印异常;

			3. controller:
				* 创建queryPayStatus
					1. 先定义一个实体类Result resutl=null;
					2. 循环调用Service层的查询订单状态方法并获取返回值;
					3. 对返回值进行判断,如果==null,则result:false,出错
					4. 如果map.get("trade_state").equals("SUCCESS"),则result:true,"支付成功"
					5. 线程等待每3秒执行一次

			4. payService.js:
				* 创建查询状态方法并指向查询状态的地址和方法,传给它订单编号;

			5. payController.js:
				* controller.js中创建查询状态方法,方法中对返回结果进行判断,
					1. 如果返回结果为true,则跳转到支付成功页面
					2. 如果返回结果为false,则跳转到失败页面

				* 将该方法在createNative生成二维码的时候进行调用,这样在二维码生成的时候就完成了查询订单状态的功能;因为二维码是初始化init就进行调用,所以生成二维码开始起就可以对二维码状态进行查询;

再然后,我们需要加一个查询时间限制

		1. 准备:
			1. 需求:
				* 如果用户到了二维码页面一直未支付,或是关掉了支付页面,我们的代码会一直循环调用微信接口,这样会对程序造成很大的压力。所以我们要加一个时间限制或是循环次数限制,当超过时间或次数时,跳出循环。
			2. 实现思路:
				1. 可以在Contrller.java中的查询状态方法内定义一个计时器,int x=0; 然后再while(true){}循环查询状态的时候每次x++;如果x>=100时[可以自定义时间],然后result=new Result(false,"二维码超时");

				2. 在 前端中payController.js中再添加一个判断,如果成功则跳转,如果失败则进行判断,如果返回的结果是二维码超时,则重新生成二维码,否则就跳转到失败页面;

	、

再然后,支付成功页面我们应该显示金额

		1. 准备:
			1. 需求:现在我们支付成功页面显示的是固定的值,怎么显示真正的支付金额呢?我们这里可以使用 angularJS 的页面传参来解决
			2. 实现思路:
				* payController.js中的查询支付状态方法内,如果返回的result是true,支付成功,那么我们在跳转到支付成功页面的时候应该传入参数:$scope.money  [付款金额]
		2. 开始:
			1. payController.js: 
				1. 跳转页面传参,当支付成功后跳转到成功页面的时候传入付款金额
					* if(response.success){
							location.href="paysuccess.html#?money="+$scope.money;}
				2. 引入$location服务,新增获取金额的方法;
					return $location.search()['money'];
			2. paysuccess.html:
				1. 引入相关的js,并在body添加指令:ng-app,ng-controller
				2. 用表达式显示金额:			<p>支付金额:¥{{getMoney()}}元</p>

最后,我们应该添加一个支付日志的功能

		1. 准备:
			1. 需求:
				1. 系统中无法查询到支付记录
				2. 支付后订单状态没有改变

			2. 实现思路:
				1. 在用户下订单时,判断如果为微信支付,就想支付日志表添加一条记录,信息包括支付总金额、订单 ID(多个)、用户 ID 、下单时间等信息,支付状态为 0(未支付)
				2. 生成的支付日志对象放入 redis 中,以用户 ID 作为 key,这样在生成支付二维码时就可以从 redis 中提取支付日志对象中的金额和订单号。
			3. 当用户支付成功后,修改支付日志的支付状态为 1(已支付),并记录微信传递给我们的交易流水号。根据订单 ID(多个)修改订单的状态为 2(已付款)。
			4. 分析表结构:根据需求我们应该独立建立一个订单支付日志表,它应该包含:支付订单号,创建事件,支付完成时间,支付金额,交易流水,交易状态,支付类型,订单表id串
			

		2. 具体思路[解决系统中无法查询到支付记录]:
			1. interface: 
				* 首先我们在接口中创建一个通过用户id查询redis中订单的办法。
			2. service:
				1. 然后在实现类中的生成二维码方法[createNative]中先获取当前用户,
				2. 通过当前用户userid查询redis返回一个payLog日志对象,
				3. 然后对其进行判断如果该日志不存在则返回一个new HashMap();			【即这个值为null】
				4. 如果该日志存在,则将日志中的订单编号和商品金额作为参数调用weixinPayService.createNative(..)返回;
			
		3. 具体思路[解决支付后订单状态没有改变]
			1. interface:	
				* 创建一个修改订单状态的方法,并传入订单编号,和交易号的的方法;

			2. serviceimpl:
				1. 首先要明确做的三件事情:
					1. 修改支付日志状态
					2. 修改关联的订单的状态
					3. 清除缓存中的支付日志对象

				2. 实现接口新建的修改订单状态方法updateOrderStatus(String out_trade_no,String transaction_id):
					1. 通过日志操作类通过订单编号查询到payLog对象,然后修改payLog对象内的属性,如交易状态,交易号等
					2. 通过日志类payLog.getOrderList()获取订单号列表然后查询到orderList值,
					3. orderList的值为"xxx,xxx,xxx",我们可以通过spilt(",")方法获取到订单号数组。
					4. 遍历订单编号,通过订单操作类orderMapper.selectByPrimaryKey方法查询id值获得订单,如果订单存在则修改状态,并orderMapper.updateByPrimaryKey(order)覆盖订单;
					5. 通过redisTemplate查找"payLog".delete删除日志id;

			3. PayController.java:
				1. 在微信支付接口有成功返回状态时,调用修改状态的方法
						if(map.get("trade_state").equals("SUCCESS")){//如果成功
						result=new Result(true, "支付成功");
						//修改订单状态
						orderService.updateOrderStatus(out_trade_no,
						map.get("transaction_id"));
						break;
						}

interface:

1. pom.xml:


			<?xml version="1.0" encoding="UTF-8"?>
			<project xmlns="http://maven.apache.org/POM/4.0.0"
			         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
			    <parent>
			        <artifactId>pinyougou-parent</artifactId>
			        <groupId>com.pinyougou</groupId>
			        <version>1.0-SNAPSHOT</version>
			    </parent>
			    <modelVersion>4.0.0</modelVersion>
			    <packaging>jar</packaging>
			
			    <artifactId>pinyougou-pay-interface</artifactId>
			
			
			</project>

2. WeixinPayService.java [接口]
						package com.pinyougou.pay.service;
				
				import java.util.Map;
				
				public interface WeixinPayService {
				
				    /*
				    *
				    * 生成二维码
				    * */
				    public Map createNative(String out_trade_no ,String total_fee);
				
				
				    /*
				    *
				    * 查询支付订单状态
				    * */
				    public  Map queryPayStatus(String out_trade_no);
				}

serviceImpl

  1. pom.xml

     	<?xml version="1.0" encoding="UTF-8"?>
     	<project xmlns="http://maven.apache.org/POM/4.0.0"
     	         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     	         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     	    <parent>
     	        <artifactId>pinyougou-parent</artifactId>
     	        <groupId>com.pinyougou</groupId>
     	        <version>1.0-SNAPSHOT</version>
     	    </parent>
     	    <modelVersion>4.0.0</modelVersion>
     	    <packaging>war</packaging>
     	    <artifactId>pinyougou-pay-service</artifactId>
     	
     	    <properties>
     	        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     	        <maven.compiler.source>1.7</maven.compiler.source>
     	        <maven.compiler.target>1.7</maven.compiler.target>
     	    </properties>
     	
     	    <dependencies>
     	
     	        <!-- Spring -->
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-context</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-beans</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-webmvc</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-jdbc</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-aspects</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-jms</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-context-support</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.springframework</groupId>
     	            <artifactId>spring-test</artifactId>
     	        </dependency>
     	        <!-- dubbo相关 -->
     	        <dependency>
     	            <groupId>com.alibaba</groupId>
     	            <artifactId>dubbo</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>org.apache.zookeeper</groupId>
     	            <artifactId>zookeeper</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>com.github.sgroschupf</groupId>
     	            <artifactId>zkclient</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>junit</groupId>
     	            <artifactId>junit</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>com.alibaba</groupId>
     	            <artifactId>fastjson</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>javassist</groupId>
     	            <artifactId>javassist</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>commons-codec</groupId>
     	            <artifactId>commons-codec</artifactId>
     	        </dependency>
     	        <dependency>
     	            <groupId>javax.servlet</groupId>
     	            <artifactId>servlet-api</artifactId>
     	            <scope>provided</scope>
     	        </dependency>
     	
     	        <dependency>
     	            <groupId>com.pinyougou</groupId>
     	            <artifactId>pinyougou-pay-interface</artifactId>
     	            <version>1.0-SNAPSHOT</version>
     	        </dependency>
     	        <dependency>
     	            <groupId>com.pinyougou</groupId>
     	            <artifactId>pinyougou-common</artifactId>
     	            <version>1.0-SNAPSHOT</version>
     	        </dependency>
     	        <dependency>
     	            <groupId>com.github.wxpay</groupId>
     	            <artifactId>wxpay-sdk</artifactId>
     	            <version>0.0.3</version>
     	        </dependency>
     	
     	    </dependencies>
     	
     	    <build>
     	        <plugins>
     	            <plugin>
     	                <groupId>org.apache.tomcat.maven</groupId>
     	                <artifactId>tomcat7-maven-plugin</artifactId>
     	                <version>2.2</version>
     	                <configuration>
     	                    <!-- 指定端口 -->
     	                    <port>9000</port>
     	                    <!-- 请求路径 -->
     	                    <path>/</path>
     	                </configuration>
     	            </plugin>
     	        </plugins>
     	    </build>
     	
     	</project>
    
  2. WeinxinPayServiceImpl.java:

     				package com.pinyougou.pay.service.impl;
     				
     				import com.alibaba.dubbo.config.annotation.Service;
     				import com.github.wxpay.sdk.WXPayUtil;
     				import com.pinyougou.pay.service.WeixinPayService;
     				import org.springframework.beans.factory.annotation.Value;
     				import util.HttpClient;
     				
     				import java.util.HashMap;
     				import java.util.Map;
     				
     				/**
     				 * WeixinPayServiceImpl
     				 * hasee
     				 * 2018/12/14
     				 * 15:13
     				 *
     				 * @Version 1.0
     				 **/
     				
     				@Service
     				public class WeixinPayServiceImpl implements WeixinPayService {
     				
     				    @Value("${appid}")
     				    private String appid;
     				
     				    @Value("${partner}")
     				    private String partner;
     				
     				    @Value("${partnerkey}")
     				    private String partnerkey;
     				
     				    @Override
     				    public Map createNative(String out_trade_no, String total_fee) {
     				        //1. 参数封装
     				        Map param=new HashMap();
     				        param.put("appid",appid);       //公众号id
     				        param.put("mch_id",partner);    //商户key值
     				        param.put("nonce_str", WXPayUtil.generateNonceStr());       //商户密码,随机字符串
     				        param.put("body","品优购");    //主体
     				        param.put("out_trade_no",out_trade_no);     //交易订单
     				        param.put("total_fee",total_fee);       //金额(分)
     				        param.put("spbill_create_ip","127.0.0.1");      //终端ip
     				        param.put("notify_url","http://www.itcast.cn");     //回调地址
     				        param.put("trade_type","NATIVE");           //交易类型
     				
     				        try {
     				            String xmlParam=WXPayUtil.generateSignedXml(param,partnerkey);
     				            System.out.println("请求的参数:"+xmlParam);
     				
     				            //2. 发送请求
     				            HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
     				            httpClient.setHttps(true);
     				            httpClient.setXmlParam(xmlParam);
     				            httpClient.post();
     				
     				
     				            //获取结果
     				            String xmlResult=httpClient.getContent();
     				            Map<String, String> mapResult=WXPayUtil.xmlToMap(xmlResult);
     				            System.out.println("接收到的结果"+mapResult);
     				            Map map=new HashMap();
     				            map.put("code_url",mapResult.get("code_url"));          //生成支付二维码连接
     				            map.put("out_trade_no",mapResult.get("out_trade_no"));
     				            map.put("total_fee",mapResult.get("total_fee"));
     				            return  map;
     				        } catch (Exception e) {
     				            e.printStackTrace();
     				            return new HashMap();
     				        }
     				    }
     				
     				    @Override
     				    public Map queryPayStatus(String out_trade_no) {
     				        //1. 封装参数
     				        Map param=new HashMap();
     				        param.put("appid",appid);
     				        param.put("mch_id",partner);
     				        param.put("out_trade_no",out_trade_no);
     				        param.put("nonce_str",WXPayUtil.generateNonceStr());
     				        try {
     				            String xmlParam=WXPayUtil.generateSignedXml(param,partnerkey);
     				            //2. 发送请求
     				           HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
     				           httpClient.setHttps(true);
     				           httpClient.setXmlParam(xmlParam);
     				            httpClient.post();
     				
     				            //3. 获取结果
     				            String xmlResult=httpClient.getContent();
     				            Map<String, String> map=WXPayUtil.xmlToMap(xmlResult);
     				            return map;
     				
     				        } catch (Exception e) {
     				            e.printStackTrace();
     				            return new HashMap();
     				        }
     				
     				    }
     				}
    
  3. resources/sping/applicationContext-service.xml

     	<?xml version="1.0" encoding="UTF-8"?>
     	<beans xmlns="http://www.springframework.org/schema/beans"
     		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
     		xmlns:context="http://www.springframework.org/schema/context"
     		xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
     		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     	        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
     	        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
     	        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
     	
     	    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
     		<dubbo:application name="pinyougou-pay-service"/>
     	    <dubbo:registry address="zookeeper://192.168.25.128:2181"/>
     	    <dubbo:annotation package="com.pinyougou.pay.service.impl" />		 
     	</beans>
    
  4. webapp/WEB-INF/web.xml:

     		<?xml version="1.0" encoding="UTF-8"?>
     		<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     		         xmlns="http://java.sun.com/xml/ns/javaee"
     		         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
     		         version="2.5">
     		
     		  <!-- 加载spring容器 -->
     		  <context-param>
     		    <param-name>contextConfigLocation</param-name>
     		    <param-value>classpath*:spring/applicationContext*.xml</param-value>
     		  </context-param>
     		  <listener>
     		    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     		  </listener>
     		
     		
     		</web-app>
    

Controller:

  1. controller:

     package com.pinyougou.cart.controller;
     	import com.alibaba.dubbo.config.annotation.Reference;
     	import com.pinyougou.order.service.OrderService;
     	import com.pinyougou.pay.service.WeixinPayService;
     	import com.pinyougou.pojo.TbPayLog;
     	import entity.Result;
     	import org.springframework.security.core.context.SecurityContextHolder;
     	import org.springframework.web.bind.annotation.RequestMapping;
     	import org.springframework.web.bind.annotation.RestController;
     	
     	import java.util.HashMap;
     	import java.util.Map;
     	
     	/**
     	 * PayController
     	 * hasee
     	 * 2018/12/14
     	 * 15:55
     	 *
     	 * @Version 1.0
     	 **/
     	@RestController
     	@RequestMapping("/pay")
     	public class PayController {
     	
     	    @Reference
     	    private WeixinPayService weixinPayService;
     	
     	    @Reference
     	    private OrderService orderService;
     	
     	    @RequestMapping("/createNative")
     	    public Map createNative(){
     	       //获取当前登录用户
     	        String username=SecurityContextHolder.getContext().getAuthentication().getName();
     	        //从日志中提取缓存
     	        TbPayLog payLog=orderService.searchPayLogFromRedis(username);
     	        //调用微信支付接口
     	        if (payLog!=null){
     	            return weixinPayService.createNative(payLog.getOutTradeNo(),payLog.getTotalFee()+"");
     	        }else{
     	            return new HashMap();
     	        }
     	
     	    }
     	
     	
     	    @RequestMapping("/queryPayStatus")
     	    public Result queryPayStatus(String out_trade_no){
     	        Result result=null;
     	        int x=0;
     	        while (true){
     	            Map<String,String> map=weixinPayService.queryPayStatus(out_trade_no);       //调用查询
     	            if (map==null){
     	                result=new Result(false,"支付发生错误!");
     	                break;
     	            }
     	            if (map.get("trade_state").equals("SUCCESS")){
     	                result=new Result(true,"支付成功");
     	                orderService.updateOrderStatus(out_trade_no,map.get("transaction_id"));         //修改订单状态
     	                break;
     	            }
     	            try {
     	                Thread.sleep(3000);
     	            } catch (InterruptedException e) {
     	                e.printStackTrace();
     	            }
     	            x++;
     	            //平时x>100[三秒执行一次,每分钟执行20次,五分钟执行100次,大概5分钟左右二维码超时],这里方便测试我们可以直接大于4
     	            if (x>=4){
     	                result=new Result(false,"二维码超时");
     	                break;
     	            }
     	
     	        }
     	        return result;
     	    }
     	}
    
  2. pom.xml:

     			<?xml version="1.0" encoding="UTF-8"?>
     			<project xmlns="http://maven.apache.org/POM/4.0.0"
     			         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     			         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     			    <parent>
     			        <artifactId>pinyougou-parent</artifactId>
     			        <groupId>com.pinyougou</groupId>
     			        <version>1.0-SNAPSHOT</version>
     			    </parent>
     			    <modelVersion>4.0.0</modelVersion>
     			    <packaging>war</packaging>
     			    <artifactId>pinyougou-cart-web</artifactId>
     			
     			    <dependencies>
     			        <!-- Spring -->
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-context</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-beans</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-webmvc</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-jdbc</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-aspects</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-jms</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-context-support</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.springframework</groupId>
     			            <artifactId>spring-test</artifactId>
     			        </dependency>
     			        <!-- dubbo相关 -->
     			        <dependency>
     			            <groupId>com.alibaba</groupId>
     			            <artifactId>dubbo</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.apache.zookeeper</groupId>
     			            <artifactId>zookeeper</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.github.sgroschupf</groupId>
     			            <artifactId>zkclient</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>junit</groupId>
     			            <artifactId>junit</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.alibaba</groupId>
     			            <artifactId>fastjson</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>javassist</groupId>
     			            <artifactId>javassist</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>commons-codec</groupId>
     			            <artifactId>commons-codec</artifactId>
     			        </dependency>
     			        <dependency>
     			            <groupId>javax.servlet</groupId>
     			            <artifactId>servlet-api</artifactId>
     			            <scope>provided</scope>
     			        </dependency>
     			
     			
     			        <dependency>
     			            <groupId>org.springframework.security</groupId>
     			            <artifactId>spring-security-web</artifactId>
     			            <version>4.1.0.RELEASE</version>
     			        </dependency>
     			
     			        <dependency>
     			            <groupId>org.springframework.security</groupId>
     			            <artifactId>spring-security-config</artifactId>
     			            <version>4.1.0.RELEASE</version>
     			        </dependency>
     			
     			
     			
     			        <dependency>
     			            <groupId>org.springframework.security</groupId>
     			            <artifactId>spring-security-cas</artifactId>
     			            <version>4.1.0.RELEASE</version>
     			        </dependency>
     			        <dependency>
     			            <groupId>org.jasig.cas.client</groupId>
     			            <artifactId>cas-client-core</artifactId>
     			            <version>3.3.3</version>
     			            <exclusions>
     			                <exclusion>
     			                    <groupId>org.slf4j</groupId>
     			                    <artifactId>log4j-over-slf4j</artifactId>
     			                </exclusion>
     			            </exclusions>
     			        </dependency>
     			
     			        <dependency>
     			            <groupId>com.pinyougou</groupId>
     			            <artifactId>pinyougou-common</artifactId>
     			            <version>1.0-SNAPSHOT</version>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.pinyougou</groupId>
     			            <artifactId>pinyougou-cart-interface</artifactId>
     			            <version>1.0-SNAPSHOT</version>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.pinyougou</groupId>
     			            <artifactId>pinyougou-user-interface</artifactId>
     			            <version>1.0-SNAPSHOT</version>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.pinyougou</groupId>
     			            <artifactId>pinyougou-order-interface</artifactId>
     			            <version>1.0-SNAPSHOT</version>
     			        </dependency>
     			        <dependency>
     			            <groupId>com.pinyougou</groupId>
     			            <artifactId>pinyougou-pay-interface</artifactId>
     			            <version>1.0-SNAPSHOT</version>
     			        </dependency>
     			    </dependencies>
     			
     			
     			    <build>
     			        <plugins>
     			            <plugin>
     			                <groupId>org.apache.tomcat.maven</groupId>
     			                <artifactId>tomcat7-maven-plugin</artifactId>
     			                <version>2.2</version>
     			                <configuration>
     			                    <!-- 指定端口 -->
     			                    <port>9107</port>
     			                    <!-- 请求路径 -->
     			                    <path>/</path>
     			                </configuration>
     			            </plugin>
     			        </plugins>
     			    </build>
     			
     			</project>
    
  3. resources/sping/spring-security.xml

     		<?xml version="1.0" encoding="UTF-8"?>
     		<beans:beans xmlns="http://www.springframework.org/schema/security"
     			xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     			xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     								http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
     		
     		    <http pattern="/css/**" security="none"></http>
     		    <http pattern="/img/**" security="none"></http>
     		    <http pattern="/js/**" security="none"></http>
     		    <http pattern="/plugins/**" security="none"></http>
     		
     		    <http pattern="/cart.html" security="none"></http>
     		
     		
     		
     			<!--   entry-point-ref  入口点引用 -->
     		    <!--登录不在自己本身的系统中进行登录,所以需要设置入口点-->
     			<http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
     		        <!--匿名角色IS_AUTHENTICATED_ANONYMOUSLY-->
     		        <!--如果用户登录了,则显示登录名,如果未登录则登录名:anonymousUser,必须要放在ROLE_USER前面-->
     		        <intercept-url pattern="/cart/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"></intercept-url>
     		        <intercept-url pattern="/**" access="ROLE_USER"/>   
     		        <csrf disabled="true"/>  
     		        <!-- custom-filter为过滤器, position 表示将过滤器放在指定的位置上,before表示放在指定位置之前  ,after表示放在指定的位置之后  -->           
     		        <custom-filter ref="casAuthenticationFilter"  position="CAS_FILTER" />      
     		        <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>  
     		        <custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>  
     		    </http>
     		
     		
     		    <!--CAS只是单点登录的一种解决方案,所以这里不一定一定要接入CAS,也可以接入其他的;-->
     		  	<!-- CAS入口点 开始 -->
     		    <beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">  
     		        <!-- 单点登录服务器登录URL -->  
     		        <beans:property name="loginUrl" value="http://localhost:9100/cas/login"/>  
     		        <beans:property name="serviceProperties" ref="serviceProperties"/>  
     		    </beans:bean>      
     		    <beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">  
     		        <!--service 配置自身工程的根地址+/login/cas   -->  
     		        <beans:property name="service" value="http://localhost:9107/login/cas"/>
     		    </beans:bean>  
     		    <!-- CAS入口点 结束 -->
     		
     		    
     		    <!-- 认证过滤器 开始 -->
     		    <beans:bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">  
     		        <beans:property name="authenticationManager" ref="authenticationManager"/>  
     		    </beans:bean>  
     				<!-- 认证管理器 -->
     			<authentication-manager alias="authenticationManager">
     				<authentication-provider  ref="casAuthenticationProvider">
     				</authentication-provider>
     			</authentication-manager>
     				<!-- 认证提供者 -->
     			<beans:bean id="casAuthenticationProvider"     class="org.springframework.security.cas.authentication.CasAuthenticationProvider">  
     		        <beans:property name="authenticationUserDetailsService">  
     		            <beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">  
     		                <beans:constructor-arg ref="userDetailsService" />  
     		            </beans:bean>  
     		        </beans:property>  
     		        <beans:property name="serviceProperties" ref="serviceProperties"/>  
     		        <!-- ticketValidator 为票据验证器 -->
     		        <beans:property name="ticketValidator">  
     		            <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">  
     		                <beans:constructor-arg index="0" value="http://localhost:9100/cas"/>  
     		            </beans:bean>  
     		        </beans:property>  
     		        <beans:property name="key" value="an_id_for_this_auth_provider_only"/> 
     		    </beans:bean>        
     		   		 <!-- 认证类 -->
     			<beans:bean id="userDetailsService" class="com.pinyougou.user.service.UserDetailServiceImpl"/>
     			
     			<!-- 认证过滤器 结束 -->
     			
     			
     			<!-- 单点登出  开始  -->     
     		    <beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>    
     		    <!-- 经过此配置,当用户在地址栏输入本地工程 /logout/cas  -->      
     		    <beans:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">  
     		        <beans:constructor-arg value="http://localhost:9100/cas/logout?service=http://localhost:9103"/>
     		        <beans:constructor-arg>  
     		            <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>  
     		        </beans:constructor-arg>  
     		        <beans:property name="filterProcessesUrl" value="/logout/cas"/>  
     		    </beans:bean>  
     		    <!-- 单点登出  结束 -->  
     			
     		</beans:beans>
    
  4. resources/springmvc.xml

     		<?xml version="1.0" encoding="UTF-8"?>
     		<beans xmlns="http://www.springframework.org/schema/beans"
     			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
     			xmlns:context="http://www.springframework.org/schema/context"
     			xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
     			xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     		        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
     		        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
     		        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
     		    <context:property-placeholder location="classpath:config/application.properties" />
     			
     			<mvc:annotation-driven>
     			  <mvc:message-converters register-defaults="true">
     			    <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">  
     			      <property name="supportedMediaTypes" value="application/json"/>
     			      <property name="features">
     			        <array>
     			          <value>WriteMapNullValue</value>
     			          <value>WriteDateUseDateFormat</value>
     			        </array>
     			      </property>
     			    </bean>
     			  </mvc:message-converters>  
     			</mvc:annotation-driven>
     		
     			<!-- 引用dubbo 服务 -->
     			<dubbo:application name="pinyougou-cart-web" />
     			<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
     			<dubbo:annotation package="com.pinyougou.cart.controller" />
     		
     		</beans>
    
  5. js/controller.js

     		app.controller('payController',function ($scope,$location,payService) {
     		
     		
     		   $scope.createNative=function () {
     		       payService.createNative().success(
     		           function (response) {
     		                //显示订单号和金额
     		               //toFixed是保留两位小数,total_fee单位是分除以100变为元
     		               $scope.money=(response.total_fee/100).toFixed(2);
     		               $scope.out_trade_no=response.out_trade_no;
     		
     		               //生成二维码
     		               var qr=new QRious({
     		                   element:document.getElementById('qrious'),
     		                   size:250,
     		                   value:response.code_url,
     		                   level:'H'
     		               });
     		                queryPayStatus();       //调用查询
     		
     		
     		
     		       })
     		   };
     		
     		
     		   //调用查询
     		    queryPayStatus=function () {
     		        payService.queryPayStatus($scope.out_trade_no).success(
     		            function (response) {
     		                if (response.success){
     		                    location.href="paysuccess.html#?money="+$scope.money;
     		                }else{
     		                    if (response.message=='二维码超时'){
     		                        //这里调用重新生成二维码功能,当关闭浏览器,后端循环遍历查询订单状态即停止,如果不关闭浏览器和本支付页面的话,就可以实现每隔几秒重新生成一次二维码功能;
     		                        $scope.createNative();      //重新生成二维码
     		                    }else{
     		                        location.href="payfail.html";
     		                    }
     		                    }})}
     		    // 获取金额
     		    $scope.getMoney=function () {
     		        return $location.search()['money'];
     		    }
     		
     		});
    
  6. js/base.js:

     	var app=angular.module('pinyougou',[]);
    
  7. js/service.js:

     	app.controller('payController',function ($scope,$location,payService) {
     
     
        $scope.createNative=function () {
            payService.createNative().success(
                function (response) {
                     //显示订单号和金额
                    //toFixed是保留两位小数,total_fee单位是分除以100变为元
                    $scope.money=(response.total_fee/100).toFixed(2);
                    $scope.out_trade_no=response.out_trade_no;
     
                    //生成二维码
                    var qr=new QRious({
                        element:document.getElementById('qrious'),
                        size:250,
                        value:response.code_url,
                        level:'H'
                    });
                     queryPayStatus();       //调用查询
     
     
     
            })
        };
     
     
        //调用查询
         queryPayStatus=function () {
             payService.queryPayStatus($scope.out_trade_no).success(
                 function (response) {
                     if (response.success){
                         location.href="paysuccess.html#?money="+$scope.money;
                     }else{
                         if (response.message=='二维码超时'){
                             //这里调用重新生成二维码功能,当关闭浏览器,后端循环遍历查询订单状态即停止,如果不关闭浏览器和本支付页面的话,就可以实现每隔几秒重新生成一次二维码功能;
                             $scope.createNative();      //重新生成二维码
                         }else{
                             location.href="payfail.html";
                         }
                         }})}
         // 获取金额
         $scope.getMoney=function () {
             return $location.search()['money'];
         }
     
     });
    
  8. webapp/WEB-INF/web.xml

     		<?xml version="1.0" encoding="UTF-8"?>
     		<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     		         xmlns="http://java.sun.com/xml/ns/javaee"
     		         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
     		         version="2.5">
     		    <!-- 解决post乱码 -->
     		    <filter>
     		        <filter-name>CharacterEncodingFilter</filter-name>
     		        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
     		        <init-param>
     		            <param-name>encoding</param-name>
     		            <param-value>utf-8</param-value>
     		        </init-param>
     		        <init-param>
     		            <param-name>forceEncoding</param-name>
     		            <param-value>true</param-value>
     		        </init-param>
     		    </filter>
     		    <filter-mapping>
     		        <filter-name>CharacterEncodingFilter</filter-name>
     		        <url-pattern>/*</url-pattern>
     		    </filter-mapping>
     		
     		    <context-param>
     		        <param-name>contextConfigLocation</param-name>
     		        <param-value>classpath:spring/spring-security.xml</param-value>
     		    </context-param>
     		    <listener>
     		        <listener-class>
     		            org.springframework.web.context.ContextLoaderListener
     		        </listener-class>
     		    </listener>
     		
     		    <filter>
     		        <filter-name>springSecurityFilterChain</filter-name>
     		        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     		    </filter>
     		    <filter-mapping>
     		        <filter-name>springSecurityFilterChain</filter-name>
     		        <url-pattern>/*</url-pattern>
     		    </filter-mapping>
     		    <servlet>
     		        <servlet-name>springmvc</servlet-name>
     		        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     		        <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
     		        <init-param>
     		            <param-name>contextConfigLocation</param-name>
     		            <param-value>classpath:spring/springmvc.xml</param-value>
     		        </init-param>
     		    </servlet>
     		
     		    <servlet-mapping>
     		        <servlet-name>springmvc</servlet-name>
     		        <url-pattern>*.do</url-pattern>
     		    </servlet-mapping>
     		    <welcome-file-list>
     		        <welcome-file>cart.html</welcome-file>
     		    </welcome-file-list>
     		
     		
     		</web-app>
    

HttpClient工具类:

		package util;
		
		import java.io.IOException;
		import java.security.GeneralSecurityException;
		import java.security.cert.CertificateException;
		import java.security.cert.X509Certificate;
		import java.text.ParseException;
		import java.util.HashMap;
		import java.util.LinkedList;
		import java.util.List;
		import java.util.Map;
		
		import javax.net.ssl.SSLContext;
		import javax.net.ssl.SSLException;
		import javax.net.ssl.SSLSession;
		import javax.net.ssl.SSLSocket;
		import javax.net.ssl.TrustManager;
		import javax.net.ssl.X509TrustManager;
		
		import org.apache.http.Consts;
		import org.apache.http.HttpEntity;
		import org.apache.http.NameValuePair;
		import org.apache.http.client.ClientProtocolException;
		import org.apache.http.client.config.RequestConfig;
		import org.apache.http.client.entity.UrlEncodedFormEntity;
		import org.apache.http.client.methods.CloseableHttpResponse;
		import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
		import org.apache.http.client.methods.HttpGet;
		import org.apache.http.client.methods.HttpPost;
		import org.apache.http.client.methods.HttpPut;
		import org.apache.http.client.methods.HttpUriRequest;
		import org.apache.http.conn.scheme.Scheme;
		import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
		import org.apache.http.conn.ssl.SSLContextBuilder;
		import org.apache.http.conn.ssl.SSLSocketFactory;
		import org.apache.http.conn.ssl.TrustStrategy;
		import org.apache.http.conn.ssl.X509HostnameVerifier;
		import org.apache.http.entity.StringEntity;
		import org.apache.http.impl.client.CloseableHttpClient;
		import org.apache.http.impl.client.DefaultHttpClient;
		import org.apache.http.impl.client.HttpClients;
		import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
		import org.apache.http.message.BasicNameValuePair;
		import org.apache.http.util.EntityUtils;
		
		/**
		 * http请求客户端
		 * 
		 * @author Administrator
		 * 
		 */
		public class HttpClient {
			private String url;
			private Map<String, String> param;
			private int statusCode;
			private String content;
			private String xmlParam;
			private boolean isHttps;
		
			public boolean isHttps() {
				return isHttps;
			}
		
			public void setHttps(boolean isHttps) {
				this.isHttps = isHttps;
			}
		
			public String getXmlParam() {
				return xmlParam;
			}
		
			public void setXmlParam(String xmlParam) {
				this.xmlParam = xmlParam;
			}
		
			public HttpClient(String url, Map<String, String> param) {
				this.url = url;
				this.param = param;
			}
		
			public HttpClient(String url) {
				this.url = url;
			}
		
			public void setParameter(Map<String, String> map) {
				param = map;
			}
		
			public void addParameter(String key, String value) {
				if (param == null)
					param = new HashMap<String, String>();
				param.put(key, value);
			}
		
			public void post() throws ClientProtocolException, IOException {
				HttpPost http = new HttpPost(url);
				setEntity(http);
				execute(http);
			}
		
			public void put() throws ClientProtocolException, IOException {
				HttpPut http = new HttpPut(url);
				setEntity(http);
				execute(http);
			}
		
			public void get() throws ClientProtocolException, IOException {
				if (param != null) {
					StringBuilder url = new StringBuilder(this.url);
					boolean isFirst = true;
					for (String key : param.keySet()) {
						if (isFirst)
							url.append("?");
						else
							url.append("&");
						url.append(key).append("=").append(param.get(key));
					}
					this.url = url.toString();
				}
				HttpGet http = new HttpGet(url);
				execute(http);
			}
		
			/**
			 * set http post,put param
			 */
			private void setEntity(HttpEntityEnclosingRequestBase http) {
				if (param != null) {
					List<NameValuePair> nvps = new LinkedList<NameValuePair>();
					for (String key : param.keySet())
						nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
					http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
				}
				if (xmlParam != null) {
					http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
				}
			}
		
			private void execute(HttpUriRequest http) throws ClientProtocolException,
					IOException {
				CloseableHttpClient httpClient = null;
				try {
					if (isHttps) {
						SSLContext sslContext = new SSLContextBuilder()
								.loadTrustMaterial(null, new TrustStrategy() {
									// 信任所有
									public boolean isTrusted(X509Certificate[] chain,
											String authType)
											throws CertificateException {
										return true;
									}
								}).build();
						SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
								sslContext);
						httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
								.build();
					} else {
						httpClient = HttpClients.createDefault();
					}
					CloseableHttpResponse response = httpClient.execute(http);
					try {
						if (response != null) {
							if (response.getStatusLine() != null)
								statusCode = response.getStatusLine().getStatusCode();
							HttpEntity entity = response.getEntity();
							// 响应内容
							content = EntityUtils.toString(entity, Consts.UTF_8);
						}
					} finally {
						response.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					httpClient.close();
				}
			}
		
			public int getStatusCode() {
				return statusCode;
			}
		
			public String getContent() throws ParseException, IOException {
				return content;
			}
		
		}

雪花算法工具类

			package util;
			
			import java.lang.management.ManagementFactory;
			import java.net.InetAddress;
			import java.net.NetworkInterface;
			
			/**
			 * <p>名称:IdWorker.java</p>
			 * <p>描述:分布式自增长ID</p>
			 * <pre>
			 *     Twitter的 Snowflake JAVA实现方案
			 * </pre>
			 * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
			 * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
			 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
			 * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
			 * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
			 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
			 * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
			 * <p>
			 * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
			 *
			 * @author Polim
			 */
			public class IdWorker {
			    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
			    private final static long twepoch = 1288834974657L;
			    // 机器标识位数
			    private final static long workerIdBits = 5L;
			    // 数据中心标识位数
			    private final static long datacenterIdBits = 5L;
			    // 机器ID最大值
			    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
			    // 数据中心ID最大值
			    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
			    // 毫秒内自增位
			    private final static long sequenceBits = 12L;
			    // 机器ID偏左移12位
			    private final static long workerIdShift = sequenceBits;
			    // 数据中心ID左移17位
			    private final static long datacenterIdShift = sequenceBits + workerIdBits;
			    // 时间毫秒左移22位
			    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
			
			    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
			    /* 上次生产id时间戳 */
			    private static long lastTimestamp = -1L;
			    // 0,并发控制
			    private long sequence = 0L;
			
			    private final long workerId;
			    // 数据标识id部分
			    private final long datacenterId;
			
			    public IdWorker(){
			        this.datacenterId = getDatacenterId(maxDatacenterId);
			        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
			    }
			    /**
			     * @param workerId
			     *            工作机器ID
			     * @param datacenterId
			     *            序列号
			     */
			    public IdWorker(long workerId, long datacenterId) {
			        if (workerId > maxWorkerId || workerId < 0) {
			            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
			        }
			        if (datacenterId > maxDatacenterId || datacenterId < 0) {
			            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
			        }
			        this.workerId = workerId;
			        this.datacenterId = datacenterId;
			    }
			    /**
			     * 获取下一个ID
			     *
			     * @return
			     */
			    public synchronized long nextId() {
			        long timestamp = timeGen();
			        if (timestamp < lastTimestamp) {
			            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
			        }
			
			        if (lastTimestamp == timestamp) {
			            // 当前毫秒内,则+1
			            sequence = (sequence + 1) & sequenceMask;
			            if (sequence == 0) {
			                // 当前毫秒内计数满了,则等待下一秒
			                timestamp = tilNextMillis(lastTimestamp);
			            }
			        } else {
			            sequence = 0L;
			        }
			        lastTimestamp = timestamp;
			        // ID偏移组合生成最终的ID,并返回ID
			        long nextId = ((timestamp - twepoch) << timestampLeftShift)
			                | (datacenterId << datacenterIdShift)
			                | (workerId << workerIdShift) | sequence;
			
			        return nextId;
			    }
			
			    private long tilNextMillis(final long lastTimestamp) {
			        long timestamp = this.timeGen();
			        while (timestamp <= lastTimestamp) {
			            timestamp = this.timeGen();
			        }
			        return timestamp;
			    }
			
			    private long timeGen() {
			        return System.currentTimeMillis();
			    }
			
			    /**
			     * <p>
			     * 获取 maxWorkerId
			     * </p>
			     */
			    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
			        StringBuffer mpid = new StringBuffer();
			        mpid.append(datacenterId);
			        String name = ManagementFactory.getRuntimeMXBean().getName();
			        if (!name.isEmpty()) {
			         /*
			          * GET jvmPid
			          */
			            mpid.append(name.split("@")[0]);
			        }
			      /*
			       * MAC + PID 的 hashcode 获取16个低位
			       */
			        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
			    }
			
			    /**
			     * <p>
			     * 数据标识id部分
			     * </p>
			     */
			    protected static long getDatacenterId(long maxDatacenterId) {
			        long id = 0L;
			        try {
			            InetAddress ip = InetAddress.getLocalHost();
			            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
			            if (network == null) {
			                id = 1L;
			            } else {
			                byte[] mac = network.getHardwareAddress();
			                id = ((0x000000FF & (long) mac[mac.length - 1])
			                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
			                id = id % (maxDatacenterId + 1);
			            }
			        } catch (Exception e) {
			            System.out.println(" getDatacenterId: " + e.getMessage());
			        }
			        return id;
			    }
			
			 /*
			    //测试
			    public static void main(String[] args) {
			        IdWorker idWorker=new IdWorker(0,0);
			        for (int i=0; i < 100; i++) {
			            long nextId=idWorker.nextId();
			            System.out.println(nextId);
			        }
			    }
			*/
			}

猜你喜欢

转载自blog.csdn.net/qq_37128049/article/details/85028599