微信app支付详细教程
微信支付作为三大支付之一,越来越多的客户要求产品中添加微信支付 但是网上能找到可用的demo很少
所以写一篇自己写微信支付的过程,希望能给有需要的开发者一点帮助。
下面让我们来进入正题
1准备工作
首先得去微信开放平台申请app支付权限 当申请成功后会收到一封邮件 这里面有个商店号 MCH_ID 和PARTNER_ID 注意这俩 其实是一样的,都是商店号,但是
通过上图我们可以看到 不同接口 对应的字段并不一样 (有意思吗 就不能统一一下)但其实都是一个商店号
然后我们还需要拿到一些key值 下面代码有介绍 就不一一说来源了
拿到这些值之后我们就可以进行下一步了
2写支付逻辑
我写的代码如下 关键点都加上了注解
@Api(tags = {"支付接口"})
@RestController
@RequestMapping(value = "weixinMobile")
public class WeixinMobilePayController {
private static final Logger logger = LoggerFactory.getLogger(WeixinMobilePayController.class);
@RequestMapping(value="dop",method=RequestMethod.POST)
public JsonBack dopay(HttpServletRequest request, JsonBack jsonBack,HttpServletResponse response,String membertoken,int num,String id) throws Exception {
Member mem= MemberServiceImp.loginMemberMap.get("token");
if(mem.getMemberToken().equals(membertoken)){
MemberLevel level = memberLevelService.getMemberLevelById(id);
int x = Integer.parseInt(level.getLevelMoney());
int cc=x * num*100;//微信以分为单位,如果数据库里面的价格没扩大100的话这里要乘以100
String total_fee =cc+"";
String body=ConstantUtil.BODY;
String mch_id=ConstantUtil.MCH_ID;
String currTime = PayCommonUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayCommonUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
String notify_url=ConstantUtil.NOTIFY_URL;//回调地址 必须能直接访问 不是二级域名也可以
String out_trade_no=String.valueOf(UUID.next()); // 订单号
String timestamp=WXUtil.getTimeStamp();
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
packageParams.put("appid",ConstantUtil.APP_ID);
packageParams.put("mch_id",mch_id);
packageParams.put("nonce_str",nonce_str);
packageParams.put("body",body);// 商品描述
packageParams.put("out_trade_no", out_trade_no);// 商户订单号
packageParams.put("total_fee", total_fee);// 总金额
String addr = AddressUtils.getIpAddr(request);
packageParams.put("spbill_create_ip", addr);// 发起人IP地址
packageParams.put("notify_url", notify_url);// 回调地址
packageParams.put("trade_type", "APP");// 交易类型
packageParams.put("time_start",timestamp);
String sign = PayCommonUtil.createSign("UTF-8", packageParams,ConstantUtil.APP_KEY);
packageParams.put("sign", sign);// 签名
String requestXML = PayCommonUtil.getRequestXml(packageParams);
String resXml = HttpUtil.postData(ConstantUtil.NOTIFY_URL, requestXML);
Map map = XMLUtil.doXMLParse(resXml);
String returnCode = (String) map.get("return_code");
String returnMsg = (String) map.get("return_msg");
logger.info("result:"+returnMsg);
if("SUCCESS".equals(returnCode)){
String resultCode = (String) map.get("result_code");
String prepay_id = (String) map.get("prepay_id");
String noncestr=(String) map.get("nonce_str");
if("SUCCESS".equals(resultCode)){
System.out.println("获取prepay_id成功"+prepay_id);//必须获取到这个prepay_id才算微信认可了你的第一次签名
//这里写预下单业务逻辑
SortedMap<Object, Object> packageParam = new TreeMap<Object, Object>();
// ConfigUtil.commonParams(packageParams);
packageParam.put("appid",ConstantUtil.APP_ID);
packageParam.put("partnerid",mch_id);
packageParam.put("noncestr",noncestr);
packageParam.put("prepayid",prepay_id);// 商品描述
packageParam.put("package", "Sign=WXPay");// 商户订单号
packageParam.put("timestamp",timestamp);
String sign1 = PayCommonUtil.createSign("UTF-8", packageParam,ConstantUtil.APP_KEY);//这里是二次签名 前台要拿到去调起微信支付,如果这个错了的话会在前台报签名错误
map.put("partnerid", mch_id);
map.put("timestamp", timestamp);
map.put("package","Sign=WXPay");
map.put("retcode", "0");
map.put("sign", sign1);
jsonBack = new JsonBack(true, "success", map);
}}
}else{
jsonBack = new JsonBack(false, "token不一致", null);
}
return jsonBack;
}
3 写回调逻辑
微信会根据你的回调地址去请求回调的action 并且地址必须是网络地址 能直接访问 而且不能携带参数
代码如下
@RequestMapping(value="WXP",method=RequestMethod.POST)
public void WXPayBack(HttpServletRequest request, HttpServletResponse response){
String resXml = "";
Member mem= MemberServiceImp.loginMemberMap.get("token");
try {
//解析XML
Map<String, String> map = MobileUtil.parseXml(request);
String return_code = map.get("return_code");//状态
String out_trade_no = map.get("out_trade_no");//订单号
if (return_code.equals("SUCCESS")) {
if (out_trade_no != null) {
//处理订单逻辑
这里面可以根据订单号来查询到付款买的什么
然后在预订单里加一个是否付款的状态来限制只能执行一次业务逻辑
否则就需要返回给微信一个success
resXml = "<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>";
} catch (Exception e1) {
// TODO Auto-generated catch block
logger.warn("新增服务失败");
}
}
else{
logger.warn("该用户已经买过金卡");
}
}else{
logger.info("已经购买会员完成");
}
}else{
//logger.warn("[payPage]根据id查询等级没有查询到记录,levelId="+levelId);
}
}else{
logger.info("callback fail:{}",out_trade_no);
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
} catch (Exception e) {
logger.error("callback fail",e);
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
}
4 工具类
上面用到的工具类如下
package com.zhjt.health.testpay; public class ConstantUtil {
/**
* 微信开发平台应用ID 下面参数都不完整 需要写入自己的参数
*/
public static final String APP_ID="wx60e8c9b5b7";
/**
* 应用对应的凭证
*/
public static final String APP_SECRET="85cae8f9";
/**
* 应用对应的密钥
*/ public static final String APP_KEY="wffgg";
/**
* 微信支付商户号 1500906271
*/
public static final String MCH_ID="271";
/**
* 商品描述
*/
public static final String BODY="yunyi";
/**
* 商户号对应的密钥
*/
public static final String PARTNER_key="2121."; /**
* 商户id
*/
public static final String PARTNER_ID="1";
/**
* 常量固定值
*/
public static final String GRANT_TYPE="client_credential";
/**
* 获取预支付id的接口url
*/
public static String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* 微信服务器回调通知url
*/
public static String NOTIFY_URL="http://106.14.15.78:8090/weck"; public static String NOTIFY_URL2="http://106.14.15.78:8090/wec";
public static String NOTIFY_URL3="http://106.14.15.78:8090/wei;
}
ConstantUtil
package com.zhjt.health.util.pay; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
/**
* http请求(这里用户获取订单url生成二维码)
* 创建者 科帮网
* 创建时间 2017年7月31日
*
*/
public class HttpUtil {
private final static int CONNECT_TIMEOUT = 5000; // in milliseconds
private final static String DEFAULT_ENCODING = "UTF-8"; public static String postData(String urlStr, String data) {
String postData = postData2(urlStr, data, null);
System.out.println(postData+"测试postDate");
return postData;
} public static String postData(String urlStr, String data, String contentType) { BufferedReader reader = null;
System.out.println("跳进来了");
try {
URL url = new URL(urlStr);
System.out.println(url+"测试URL");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(CONNECT_TIMEOUT);
if (contentType != null)
conn.setRequestProperty("content-type", contentType);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
if (data == null)
data = "";
writer.write(data);
writer.flush();
writer.close(); reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return null;
} public static String postData2(String urlStr, String data, String contentType) {
BufferedReader reader = null;
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
conn.setReadTimeout(CONNECT_TIMEOUT);
if(contentType != null)
conn.setRequestProperty("content-type", contentType);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);
if(data == null)
data = "";
writer.write(data);
writer.flush();
writer.close(); reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
sb.append("\r\n");
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
}
}
return null;
}
}
HttpUtil
package com.zhjt.health.util.pay; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap; public class PayCommonUtil {
/**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @Author 科帮网
* @param characterEncoding
* @param packageParams
* @param API_KEY
* @return boolean
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
@SuppressWarnings({ "rawtypes"})
public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
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(!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
//算出摘要
String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();
return tenpaySign.equals(mysign);
}
/**
* @author
* @date 2016-4-22
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param parameters
* 请求参数
* @return
*/
@SuppressWarnings({ "rawtypes"})
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
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 + "&");
}
}
sb.append("key=" + API_KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
} /**
* 将请求参数转换为xml格式的string
* @Author 科帮网
* @param parameters
* @return String
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
@SuppressWarnings({ "rawtypes"})
public static String getRequestXml(SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.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 ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
} /**
* 取出一个指定长度大小的随机正整数.
* @Author 科帮网
* @param length
* @return int
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
public static int buildRandom(int length) {
int num = 1;
double random = Math.random();
if (random < 0.1) {
random = random + 0.1;
}
for (int i = 0; i < length; i++) {
num = num * 10;
}
return (int) ((random * num));
} /**
* 获取当前时间 yyyyMMddHHmmss
*
* @return String
*/
public static String getCurrTime() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String s = outFormat.format(now);
return s;
}
}
PayCommonUtil
package com.zhjt.health.util; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
/**
* XML解析
* 创建者 科帮网
* 创建时间 2017年7月31日
*
*/
public class XMLUtil {
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
*
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Map doXMLParse(String strxml) throws JDOMException, IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if (null == strxml || "".equals(strxml)) {
return null;
} Map m = new HashMap(); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
} m.put(k, v);
} // 关闭流
in.close(); return m;
} /**
* 获取子结点的xml
*
* @param children
* @return String
*/
@SuppressWarnings({ "rawtypes" })
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator it = children.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
} return sb.toString();
} }
XMLUtil
package com.zhjt.health.util.pay; import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.google.gson.Gson;
/**
* 微信H5支付工具类
* 创建者 科帮网
* 创建时间 2017年7月31日
*/
public class MobileUtil {
/**
* 获取用户openID
* @Author 科帮网
* @param code
* @return String
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
public static String getOpenId(String code){
if (code != null) {
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
+ "appid="+ ConfigUtil.APP_ID
+ "&secret="+ ConfigUtil.APP_SECRET + "&code="
+code + "&grant_type=authorization_code";
String returnData = getReturnData(url);
Gson gson = new Gson();
OpenIdClass openIdClass = gson.fromJson(returnData,
OpenIdClass.class);
if (openIdClass.getOpenid() != null) {
return openIdClass.getOpenid();
}
}
return "**************";
}
public static String getReturnData(String urlString) {
String res = "";
try {
URL url = new URL(urlString);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url
.openConnection();
conn.connect();
java.io.BufferedReader in = new java.io.BufferedReader(
new java.io.InputStreamReader(conn.getInputStream(),
"UTF-8"));
String line;
while ((line = in.readLine()) != null) {
res += line;
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
/**
* 回调request 参数解析为map格式
* @Author 科帮网
* @param request
* @return
* @throws Exception Map<String,String>
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(HttpServletRequest request)
throws Exception {
// 解析结果存储在HashMap
Map<String, String> map = new HashMap<String, String>();
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
}
MobileUtil
package com.zhjt.health.entity; import java.util.Map; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; @ApiModel
public class JsonBack { @ApiModelProperty(value = "是否成功", required = true)
private boolean success; @ApiModelProperty(value = "返回消息", required = true)
private String message; @ApiModelProperty(value = "其他", required = false)
private Map<String, Object> map; public JsonBack() {
super();
} public JsonBack(boolean success, String message, Map<String, Object> map) {
super();
this.success = success;
this.message = message;
this.map = map;
} public boolean isSuccess() {
return success;
} public void setSuccess(boolean success) {
this.success = success;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
} public Map<String, Object> getMap() {
return map;
} public void setMap(Map<String, Object> map) {
this.map = map;
} }
JsonBack
package com.zhjt.health.util.pay;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; /**
* 根据IP地址获取详细的地域信息
* 创建者 科帮网
* 创建时间 2017年7月31日
*
*/
public class AddressUtils {
/**
*
* @param content
* 请求的参数 格式为:name=xxx&pwd=xxx
* @param encoding
* 服务器端请求编码。如GBK,UTF-8等
* @return
* @throws UnsupportedEncodingException
*/
public static String getAddresses(String ip) throws UnsupportedEncodingException {
String urlStr ="http://ip.taobao.com/service/getIpInfo.php";
String returnStr = getResult(urlStr, ip);
if (returnStr != null) {
// 处理返回的省市区信息
String[] temp = returnStr.split(",");
if (temp.length < 3) {
return "0";// 无效IP,局域网测试
}
String region = (temp[5].split(":"))[1].replaceAll("\"", "");
region = decodeUnicode(region);// 省份 String country = "";
String area = "";
// String region = "";
String city = "";
String county = "";
String isp = "";
for (int i = 0; i < temp.length; i++) {
switch (i) {
case 1:
country = (temp[i].split(":"))[2].replaceAll("\"", "");
country = decodeUnicode(country);// 国家
break;
case 3:
area = (temp[i].split(":"))[1].replaceAll("\"", "");
area = decodeUnicode(area);// 地区
break;
case 5:
region = (temp[i].split(":"))[1].replaceAll("\"", "");
region = decodeUnicode(region);// 省份
break;
case 7:
city = (temp[i].split(":"))[1].replaceAll("\"", "");
city = decodeUnicode(city);// 市区
break;
case 9:
county = (temp[i].split(":"))[1].replaceAll("\"", "");
county = decodeUnicode(county);// 地区
break;
case 11:
isp = (temp[i].split(":"))[1].replaceAll("\"", "");
isp = decodeUnicode(isp); // ISP公司
break;
}
}
String address = region+city;
if(StringUtils.isBlank(address)){
address = "地球村";
}
return address;
}
return null;
} /**
* @param urlStr
* 请求的地址
* @param content
* 请求的参数 格式为:name=xxx&pwd=xxx
* @param encoding
* 服务器端请求编码。如GBK,UTF-8等
* @return
*/
private static String getResult(String urlStr, String ip) {
URL url = null;
HttpURLConnection connection = null;
try {
url = new URL(urlStr);
connection = (HttpURLConnection) url.openConnection();// 新建连接实例
/**
* 超时错误 由 2s改为5s
*/
connection.setConnectTimeout(5000);// 设置连接超时时间,单位毫秒
connection.setReadTimeout(5000);// 设置读取数据超时时间,单位毫秒
connection.setDoOutput(true);// 是否打开输出流 true|false
connection.setDoInput(true);// 是否打开输入流true|false
connection.setRequestMethod("POST");// 提交方法POST|GET
connection.setUseCaches(false);// 是否缓存true|false
connection.connect();// 打开连接端口
DataOutputStream out = new DataOutputStream(connection.getOutputStream());// 打开输出流往对端服务器写数据
out.writeBytes("ip="+ip);// 写数据,也就是提交你的表单 name=xxx&pwd=xxx
out.flush();// 刷新
out.close();// 关闭输出流
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));// 往对端写完数据对端服务器返回数据
// ,以BufferedReader流来读取
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
return buffer.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();// 关闭连接
}
}
return null;
} /**
* unicode 转换成 中文
* @param theString
* @return
*/
public static String decodeUnicode(String theString) {
char aChar;
int len = theString.length();
StringBuffer outBuffer = new StringBuffer(len);
for (int x = 0; x < len;) {
aChar = theString.charAt(x++);
if (aChar == '\\') {
aChar = theString.charAt(x++);
if (aChar == 'u') {
int value = 0;
for (int i = 0; i < 4; i++) {
aChar = theString.charAt(x++);
switch (aChar) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value = (value << 4) + aChar - '0';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
value = (value << 4) + 10 + aChar - 'a';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
value = (value << 4) + 10 + aChar - 'A';
break;
default:
throw new IllegalArgumentException("Malformed encoding.");
}
}
outBuffer.append((char) value);
} else {
if (aChar == 't') {
aChar = '\t';
} else if (aChar == 'r') {
aChar = '\r';
} else if (aChar == 'n') {
aChar = '\n';
} else if (aChar == 'f') {
aChar = '\f';
}
outBuffer.append(aChar);
}
} else {
outBuffer.append(aChar);
}
}
return outBuffer.toString();
}
/**
* 获取IP地址
* @Author 科帮网
* @param request
* @return String
* @Date 2017年7月31日
* 更新日志
* 2017年7月31日 科帮网 首次创建
*
*/
public static String getIpAddr(HttpServletRequest request)
{
String ip = request.getHeader("X-Real-IP");
if(!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip))
return ip;
ip = request.getHeader("X-Forwarded-For");
if(!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip))
{
int index = ip.indexOf(',');
if(index != -1)
return ip.substring(0, index);
else
return ip;
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("Proxy-Client-IP");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("WL-Proxy-Client-IP");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("HTTP_CLIENT_IP");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip = request.getRemoteAddr();
if(ip==null||ip!=null&&ip.indexOf("0:0:0:0:0:0:0")!=-1){
return "127.0.0.1";
}
return ip;
}
}
AddressUtils
微信app支付详细教程的更多相关文章
- 微信app支付android客户端以及.net服务端实现
由于公司运营需要,需要在客户端(android/ios)增加微信以及支付宝支付,在调用微信app支付时遇到一些问题,也算是一些踩过的坑,记录下来 ,希望能对.net开发者服务端网站更快的集成微信app ...
- 微信app支付 ci框架做的
/** * 组合微信app支付 获得prepayid * @param int $order_num */ private function _wxpay_reques ...
- .net 微信APP支付接口的开发流程以及坑
流程 申请APP的微信支付 申请成功之后得到APPID 商户号 以及自己设置商户号的支付密码 这时就可以开发接口了 微信APP支付API:https://pay.weixin.qq.com/wiki/ ...
- php开发微信APP支付接口
之前在开发APP中用到了微信支付,因为是第一次用,所以中途也遇到了好多问题,通过查看文档和搜集资料,终于完成了该功能的实现.在这里简单分享一下后台php接口的开发实例. 原文地址:代码汇个人博客 ht ...
- H5使用codovar插件实现微信支付(微信APP支付模式,前端)
H5打包的app实现微信支付及支付宝支付,本章主要详解微信支付,支付宝支付请查看另一篇“H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)” ps:本文只试用H5开发的,微信 AP ...
- nodejs+koa2微信app支付,小程序支付
企业付款到零钱文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 1,搞微信支付,先看流程图 https: ...
- asp.net core 微信APP支付(扫码支付,H5支付,公众号支付,app支付)之4
微信app支付需要以下参数,类封装如下 public class WxPayModel { /// <summary> /// 应用ID /// </summary> publ ...
- 微信支付-微信公众号支付,微信H5支付,微信APP支付,微信扫码支付
在支付前,如果使用第三方MVC框架,则使用重写模式,服务器也需要配置该项 if (!-e $request_filename){ rewrite ^/(.*)$ /index.php/$ last; ...
- Android版-微信APP支付
首发地址: Android版-微信APP支付 欢迎留言.转发 微信极速开发系列文章(微信支付.授权获取用户信息等):点击这里 目录 1.注册账号.开发者认证 2.添加应用 3.申请微信支付 4.技术开 ...
随机推荐
- struts2的配置文件
struts2的配置文件 1.配置Action的struts.xml 2.配置Struts2有关属性的struts.properties
- Django学习-21-表关系参数
一对多关系 ForeignKey(ForeignObject) # ForeignObject(RelatedField) to, # 要进行关联的表名 to_field=None, # 要关联的表中 ...
- Linux中挂载Windows共享出来的目录
Windows中1.新建文件夹,创建共享目录 右键文件夹,共享 2.设置访问方式 Everyone,添加确认 Linux-ubuntu中1.安装cifs#sudo apt-get install ci ...
- 事件驱动的Java框架
事件驱动的三个要素: 事件源:能够接收外部事件的源体. 侦听器:能够接收事件源通知的对象. 事件处理程序:用于处理事件的对象.
- .Net Core使用Redis的一个入门简单Demo
本例子讲述一个在.Net core环境中对Redis数据库进行增删改查操作. 首先,要安装好Redis数据库,至于怎么安装,本文不再赘述,可以自行百度,有很详细的教程. 安装好之后,在CMD中输入 r ...
- 异常-----Java compiler level does not match解决方法
1, 先设置好jdk,需要确定 项目,eclipse/myeclipse,系统 用的是同一个版本的JDK,我系统中安装的JDK是1.7,所以我把eclipse的jdk成1.7 2, 进入 window ...
- How I explained OOD to my wife(转)
How I explained OOD to my wife Learning Object Oriented Design principles through interesting conver ...
- Spring 之BeanFactory(转)
BeanFactory是Spring的“心脏”.它就是Spring IoC容器的真面目. Spring使用BeanFactory来实例化.配置和管理Bean.但是,在大多数情况我们并不直接使用Bean ...
- 【USACO4.2】草地排水Drainage Ditches(最大流)
题目背景 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没 ...
- 清橙A1212:剪枝
题面 清橙 Sol 一种新的树上\(DP\)姿势 从左往右按链\(DP\) 做法: 维护两个栈\(S1\),\(S2\) \(S1\)存当前的链 \(S2\)存分叉点以下要改的链 \(Dfs\),弄一 ...