这是我的第一篇博客,突然就想写一篇,写的不好要见凉呀!
这篇主要是介绍一下“公众号微信支付”也就是JSAPI支付,用最基础的方式来实现。
里面有的内容也是当初在一些大神博客里面借鉴的一些代码!
其实实现不难,主要是deBug,我猜有人会不知道怎么操作,这里强烈建议Sunny-Ngrok。
有免费的域名,不过速度不快,也可以10元买一个,这个就快了。
下面的代码直接复制,在本地调试一下就可以实现支付,不过不建议!
下面开始直接进入正题。
- 首先是基础配置:
要写这个功能你肯定有个微信公众号的后台的登录账号,在公众号设置里面如图:
这里还有一个要注意的地方,基本配置里的IP白名单一定不要忘了(可以设置几个)!
紧接就是“微信商户平台”里面配置一下如图:
这里如果域名没有设置正确,你页面里的支付控件可能只是“闪”一下就没了。
然后开始介绍业务流程:附图一张官方流程
这里我口水话简述一下:
1.授权页面获取code
2.用code获取用户的openId
3.处理好预支付所需要的相关参数,请求接口获取预支付id(prepay_id) --第一次签名
4.再把获取的预支付id,跟所需要的参数封装起来,异步返回到前端,调起支付控件 --第二次签名
5.前端获取到支付成功的消息后,执行自己的业务逻辑
下面开始贴代码跟详细表述一下:
微信相关参数类:
public class WxPayConfig {
//=======【基本信息设置】=====================================
//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
public static final String APPID = "..";//
//商户id
public static final String MCHID = "..";//
//商户支付密钥Key。审核通过后,在微信发送的邮件中查看,在申请支付开发的时候自己设置的
public static final String KEY = "..";//
//应用密匙JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
public static final String APPSECRET = "..";//需改
//=======【异步通知url设置】===================================
//异步通知url,回调的地址,一定是外网地址
private static String SERVER_URL = "http://www.xxx.cn";//需改
public static final String NOTIFY_URL = SERVER_URL + "/notifyUrl";
//编码方式
public static final String ENCODE = "UTF-8";
//微信uri-根据code获取openid的请求地址
public static String GET_OPENID = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
//微信uri-请求预支付接口
public static String UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
}
一 获取code(这里一般就是你公众号里面的自定义菜单中的地址,授权后再重定向到你的页面)
@WebServlet("/userWeixin")
public class UserWeixin extends HttpServlet {
/**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = -74398932371435346L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//回调地址
String backUrl="http://www.xxxx.cn/jsp/zb/up_register.jsp";
//3个参数,response_type:固定为token 。client_id=appid 。 redirect_uri:成功后回调后地址
//授权地址
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+WxPayConfig.APPID
+ "&redirect_uri="+URLEncoder.encode(backUrl,"UTF-8")
+ "&response_type=token"
+ "&scope=snsapi_userinfo"
+ "&state=STATE#wechat_redirect";
//重定向到授权页面
response.sendRedirect(url);
}
}
这个时候重定向时到你指定的地址时,链接里面或附带参数code。就像这样:delUser?code=xxx";
你有很多种方法获取:比如<span id="code" >${param.code}</span>
,然后
再$("#code").text();
二、获取openId (这里就是页面中,点击 支付按钮后的一系列操作)
<script type="text/javascript">
$(function(){
$("#byband").click(function(){
a();
var r=confirm("确认购买?");
if (r==true)
{
doPay();
}
});
});
</script>
function a(){
$.ajax({
type: 'POST',
url: "http://www.xxxx.cn/getOpenId" , /*如有nginx、apache、iis等配置,根据自己的代理服务器配置填写*/
data: "code=" + $("#code").text(),
dataType: "json",
async:false,
success:function(data){
console.log(data);
if(data.status == 1){//openid获取成功
orderId = data.orderId;
}else{//重定向回本页面
var currentUrl = window.location.href;
//去掉code之后的url
var redirectUrl = delQueStr(currentUrl, "code");
//拼接微信授权路径
var uri = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+ data.appId +"&redirect_uri="+ redirectUrl +"&response_type=code&scope=snsapi_base&state=1#wechat_redirect";
location.href = uri;//重定向
}
},
error:function(){
alert("获取openid错误");
}
});
}
@WebServlet("/getOpenId")
public class GetOpenIdServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object openIdObj = request.getSession().getAttribute("openId");
Map<String,Object> map = new HashMap<String,Object>();
map.put("status", 0);//默认失败
map.put("appId", WxPayConfig.APPID);//为了给前端用
if(!StringUtil.isNullOrEmpty(openIdObj)){//已经在session存在 直接返回
map.put("status", 1);//成功
map.put("openId", openIdObj.toString());
}else{//根据code获取openid
String code = request.getParameter("code");
if(!StringUtil.isNullOrEmpty(code)){//有code
//请求api获取openid
String str = HttpInvoker.sendGetRequest(StringUtil.format(WxPayConfig.GET_OPENID, new Object[]{WxPayConfig.APPID,WxPayConfig.APPSECRET,code}));
//将json转map
Map<String, Object> toMap = WeixinUtil.jsonStrToMap(str);
if(!StringUtil.isNullOrEmpty(toMap.get("openid"))){//获取openid成功
map.put("status", 1);//成功
map.put("openId", toMap.get("openid").toString());
//放入session
request.getSession().setAttribute("openId", toMap.get("openid").toString());
//设定session只存在30秒,防止冲突
request.getSession().setMaxInactiveInterval(30);
}
}
}
//返回结果
response.getWriter().print(JSONObject.fromObject(map).toString());
}
}
这里把openId存入session中,如果你一个域名下有多个公众号支付,一定要注意设置session的存活时间。
三、生成自己的订单号和,获取预支付id,调起支付控件,支付成功跳转
//去支付
function doPay(){
//先要获取orderId
$.ajax({
type: 'POST',
url: "http://www.xxxx.cn/newOrder" ,
data: null,
dataType: "json",
async:false,
success:function(data){
console.log(data);
if(data.status == 1){//openid获取成功
doPrePayId(data.orderId);
}else{//重定向回本页面
alert("获取orderid错误");
}
},
error:function(){
alert("获取openid错误");
}
});
}
function doPrePayId(orderId){
//获取预支付id
$.ajax({
type: 'POST',//body 商品描述。tatalFee 金额(分)
url: "http://www.xxx.cn/BandunifiedOrder" ,
data: "orderId=" + orderId,
dataType: "json",
success:function(res){
if(res.status == 1){//成功
payParam = res.param;//赋值给微信支付参数
onBridgeReady(res.param);//调起控件
}else{
alert(res.msg);
}
},
error:function(){
alert("获取预支付id错误");
}
});
}
//微信提供代码
function onBridgeReady(payParam){
WeixinJSBridge.invoke('getBrandWCPayRequest',payParam,
function(res){
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
alert("支付成功!");
window.location.href="http://www.xxxx.cn/updataUserByBandStatus";
}
}
);
}
@WebServlet("/newOrder")
public class NewOrderServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//这里应该写生成订单和支付相关的数据
//这里我直接写死
Map<String,Object> map = new HashMap<String,Object>();
map.put("status", 1);//成功
map.put("orderId", OrderUtil.gens("SCJYZB"));//生产订单编号
response.getWriter().print(JSONObject.fromObject(map).toString());//返回
}
}
@WebServlet("/unifiedOrder")
public class UnifiedOrderServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String orderId = request.getParameter("orderId");//订单id
Map<String,Object> rsMap = new HashMap<String, Object>();
PrintWriter out = response.getWriter();
try{
rsMap.put("status", 0);//默认出错
//必要参数请自行判断
if(StringUtil.isNullOrEmpty(orderId)){
throw new Exception("订单id为空");
}
String openId = "";
Object openIdObj = request.getSession().getAttribute("openId");
if(!StringUtil.isNullOrEmpty(openIdObj)){//优先拿session
openId = openIdObj.toString();
}else{
String opid = request.getParameter("openId");
if(!StringUtil.isNullOrEmpty(opid)){
openId = opid;
}else{
throw new Exception("openid为空");
}
}
//---------获取调用预支付相关参数
Map<String,String> paramMap = new HashMap<String, String>();
paramMap.put("appid", WxPayConfig.APPID);//appid
paramMap.put("mch_id", WxPayConfig.MCHID);//商户号
paramMap.put("nonce_str", WeixinUtil.createNoncestr(32));//随机字符串
paramMap.put("body","Zbfile");//商品描述
//商户订单号:需唯一 (一定要注意,看自己设计,支付id和订单id关联)
//注:我们这里用orderId,按道理是需要支付id,
//也就是每次按支付都要生成不一样的id,防止支付错误
paramMap.put("out_trade_no", orderId);
paramMap.put("total_fee", "20000");//金额 -- 实际金额需除以 100
paramMap.put("spbill_create_ip", WeixinUtil.getRemoteHost(request));//客户ip地址
paramMap.put("notify_url", WxPayConfig.NOTIFY_URL);//回调地址
paramMap.put("trade_type", "JSAPI");//交易类型
paramMap.put("openid", openId);//用户openid
paramMap.put("sign", WeixinUtil.getSign(paramMap));//签名 ,默认sign_type是MD5
//---------------
String unifiedStr = HttpInvoker.sendPostRequest(WxPayConfig.UNIFIED_ORDER, WeixinUtil.arrayToXml(paramMap));
Map<String, String> preMap = WeixinUtil.xmltoMap(unifiedStr);
String prepayId = preMap.get("prepay_id");
if(StringUtil.isNullOrEmpty(prepayId)){
throw new Exception("获取prepay_id错误:" + preMap.get("return_msg"));
}
//返回参数
Map<String,String> jsApiMap = new HashMap<String,String>();
jsApiMap.put("appId", WxPayConfig.APPID);
jsApiMap.put("timeStamp", WeixinUtil.getTimestamp(new Date()) + "");
jsApiMap.put("nonceStr", WeixinUtil.createNoncestr(32));
jsApiMap.put("package", "prepay_id=" + prepayId);
jsApiMap.put("signType", "MD5");
jsApiMap.put("paySign", WeixinUtil.getSign(jsApiMap));
rsMap.put("status", 1);//成功
rsMap.put("param", JSONObject.fromObject(jsApiMap));
String json = JSONObject.fromObject(rsMap).toString();
out.print(json);//发送给前端
request.getSession().removeAttribute("openId");//刷新openid,防止。公众号,与openid冲突
}catch(Exception e){
e.getStackTrace();
rsMap.put("msg", e);
out.print(rsMap);
}finally{
out.close();
out = null;
}
}
}
所用工具类:
/**
* http请求类
* ClassName: HttpInvoker
* date: 2017年10月24日 下午2:17:06
*
*/
public class HttpInvoker {
/**
* 该url里面已经携带了请求参数
*
* @param url
* @throws IOException
* @Description:
*/
public static String sendGetRequest(String url) {
String lines = "";
try {
// 拼凑get请求的URL字串,使用URLEncoder.encode对特殊和不可见字符进行编码
/*String getURL = url + "?username="
+ URLEncoder.encode("fata", "utf-8");*/
URL getUrl = new URL(url);
// 根据拼凑的URL,打开连接,URL.openConnection()函数会根据
// URL的类型,返回不同的URLConnection子类的对象,在这里我们的URL是一个http,因此它实际上返回的是HttpURLConnection
HttpURLConnection connection = (HttpURLConnection) getUrl
.openConnection();
// 建立与服务器的连接,并未发送数据
connection.connect();
// 发送数据到服务器并使用Reader读取返回的数据
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream(),"UTF-8"));
String temp = "";
while ((temp = reader.readLine()) != null) {
lines = lines + temp;
}
reader.close();
// 断开连接
connection.disconnect();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lines;
}
/**
* post提交
* @param url
* @param content
* @return
*/
public static String sendPostRequest(String url, String content) {
String line = "";
try {
// content =URLEncoder.encode(content, "utf-8");
// Post请求的url,与get不同的是不需要带参数
URL postUrl = new URL(url);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) postUrl
.openConnection();
// 打开读写属性,默认均为false
connection.setDoOutput(true);
connection.setDoInput(true);
// 设置请求方式,默认为GET
connection.setRequestMethod("POST");
// Post 请求不能使用缓存
connection.setUseCaches(false);
//
// connection.setRequestProperty("Content-type","application/x-www-form-urlencoded");
connection.setRequestProperty("Content-type","text/html");
connection.setInstanceFollowRedirects(true);
// connection.setRequestProperty(" Content-Type ",
// " application/x-www-form-urlencoded ");
DataOutputStream out = new DataOutputStream(
connection.getOutputStream());
out.write(content.toString().getBytes("utf-8"));
// out.writeBytes(content);
out.flush();
out.close(); // flush and close
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
System.out.println("read from server....");
String tmp = "";
while ((tmp = reader.readLine()) != null) {
line = line + tmp;
}
reader.close();
connection.disconnect();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return line;
}
/**
* post提交
* @param url
* @param content
* @return
*/
public static String sendPostRequestUrlencoded(String url, String content) {
String line = "";
try {
// content =URLEncoder.encode(content, "utf-8");
// Post请求的url,与get不同的是不需要带参数
URL postUrl = new URL(url);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) postUrl
.openConnection();
// 打开读写属性,默认均为false
connection.setDoOutput(true);
connection.setDoInput(true);
// 设置请求方式,默认为GET
connection.setRequestMethod("POST");
// Post 请求不能使用缓存
connection.setUseCaches(false);
//
connection.setRequestProperty("Content-type","application/x-www-form-urlencoded");
// connection.setRequestProperty("Content-type","text/html");
connection.setInstanceFollowRedirects(true);
// connection.setRequestProperty(" Content-Type ",
// " application/x-www-form-urlencoded ");
DataOutputStream out = new DataOutputStream(
connection.getOutputStream());
out.write(content.toString().getBytes("utf-8"));
// out.writeBytes(content);
out.flush();
out.close(); // flush and close
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
System.out.println("read from server....");
String tmp = "";
while ((tmp = reader.readLine()) != null) {
line = line + tmp;
}
reader.close();
connection.disconnect();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return line;
}
/**
* 作用:使用证书,以post方式提交xml到对应的接口url
* second 超时时间
*/
public String postXmlSSLCurl(String url, String content,int second){
String line = "";
try {
// content =URLEncoder.encode(content, "utf-8");
// Post请求的url,与get不同的是不需要带参数
URL postUrl = new URL(url);
// 打开连接
HttpURLConnection connection = (HttpURLConnection) postUrl
.openConnection();
// 打开读写属性,默认均为false
connection.setDoOutput(true);
connection.setDoInput(true);
// 设置请求方式,默认为GET
connection.setRequestMethod("POST");
// Post 请求不能使用缓存
connection.setUseCaches(false);
//
connection.setRequestProperty("Content-type","text/html");
connection.setInstanceFollowRedirects(true);
// connection.setRequestProperty(" Content-Type ",
// " application/x-www-form-urlencoded ");
DataOutputStream out = new DataOutputStream(
connection.getOutputStream());
out.write(content.toString().getBytes("utf-8"));
// out.writeBytes(content);
out.flush();
out.close(); // flush and close
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
System.out.println("read from server....");
String tmp = "";
while ((tmp = reader.readLine()) != null) {
line = line + tmp;
}
reader.close();
connection.disconnect();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return line;
}
}
字符处理等工具类
/**
*
* @Title: 转型、判空、格式化操作
* @Description:
* @Author:fengjianshe
* @Since:2013年8月26日
* @Version:1.1.0
*/
public class StringUtil {
private static Map<String, Object> dataMap = new HashMap<String, Object>();
public static void initMap(Map<String, Object> paramMap) {
dataMap = paramMap;
}
/**
* 判断是否为空
*
* @param str
* @return
*/
public static boolean isNullOrEmpty(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return true;
}
return false;
}
public static String getPercent(double d) {
return getDouble1(d * 100) + "%";
}
public static byte getByte(Object obj) {
int i = getInt(obj);
if (-128 < i && i < 127) {
return (byte) i;
}
return (byte) 0;
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static float getFloat(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
}
try {
return ((int) (Float.valueOf(obj.toString()) * 100)) / (float) 100;
} catch (Exception e) {
return 0;
}
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static float getFloatM(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
}
try {
if (dataMap == null) {
throw new NullPointerException("dataMap is null");
}
return getFloat(dataMap.get(obj));
} catch (Exception e) {
return 0;
}
}
/**
* 获取浮点数: 例子: 104 / 0.7 普通计算结果为:72.7995898 ,而通过本方法处理后会得出精确的值:72.8
*
* @param f
* @return
*/
public static float getFloat2(float f) {
return new Float(new DecimalFormat("#.##").format(f)).floatValue();
}
/**
* 获取浮点数: 例子: 104 / 0.7 普通计算结果为:72.7495898 ,而通过本方法处理后会得出精确的值:72.8
*
* @param f
* @return
*/
public static float getFloat1(float f) {
return new Float(new DecimalFormat("#.#").format(f)).floatValue();
}
public static double getDouble1(Object obj) {
if (obj != null && obj.toString().trim() != ""
&& obj.toString().trim().toUpperCase() != "NULL") {
return getDouble(Double.valueOf(obj.toString()));
} else {
return 0.0;
}
}
/**
* 获取Double
*
* @param obj
* @return
*/
public static double getDoubleM(Object obj) {
if (obj != null && obj.toString().trim() != ""
&& obj.toString().trim().toUpperCase() != "NULL") {
try {
if (dataMap == null) {
throw new NullPointerException("dataMap is null");
}
return getDouble1(dataMap.get(obj));
} catch (Exception e) {
return 0;
}
} else {
return 0.0;
}
}
/**
* 获取浮点数: 例子: 104 / 0.7 普通计算结果为:72.7495898 ,而通过本方法处理后会得出精确的值:72.8
*
* @param f
* @return
*/
public static double getDouble(double f) {
return (new Double(new DecimalFormat("#.##").format(f))).doubleValue();
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static int getInt(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
}
try {
Double d = new Double(obj.toString());
return d.intValue();
} catch (Exception e) {
return 0;
}
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static int getIntM(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
}
try {
if (dataMap == null) {
throw new NullPointerException("dataMap is null");
}
return getInt(dataMap.get(obj));
} catch (Exception e) {
return 0;
}
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static boolean getBoolean(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return false;
}
try {
if (getInt(obj) == 1 || obj.toString().equalsIgnoreCase("true")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
/**
* 获取整数
*
* @param obj
* @return
*/
public static boolean getBooleanM(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return false;
}
try {
if (dataMap == null) {
throw new NullPointerException("dataMap is null");
}
return getBoolean(dataMap.get(obj));
} catch (Exception e) {
return false;
}
}
/**
* 获取字符串
*
* @param obj
* @return
*/
public static String getString(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return "";
}
try {
return obj.toString().trim();
} catch (Exception e) {
return "";
}
}
/**
* 获取长整数
*
* @param obj
* @return
*/
public static long getLong(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
}
try {
return Long.valueOf(obj.toString());
} catch (Exception e) {
return 0;
}
}
/**
* 获取字符串
*
* @param obj
* @return
*/
public static String getStringM(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return "";
}
try {
if (dataMap == null) {
throw new NullPointerException("dataMap is null");
}
return getString(dataMap.get(obj));
} catch (Exception e) {
return "";
}
}
/**
* 获取utf8编码字符串
*
* @param s
* @return
*/
public static String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
byte[] b;
try {
b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0)
k += 256;
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
/**
* Utf8URL解码
*
* @param text
* @return
*/
public static String Utf8URLdecode(String text) {
String result = "";
int p = 0;
if (text != null && text.length() > 0) {
text = text.toLowerCase();
p = text.indexOf("%e");
if (p == -1)
return text;
while (p != -1) {
result += text.substring(0, p);
text = text.substring(p, text.length());
if (text == "" || text.length() < 9)
return result;
result += CodeToWord(text.substring(0, 9));
text = text.substring(9, text.length());
p = text.indexOf("%e");
}
}
return result + text;
}
/**
* 编码是否有效
*
* @param text
* @return
*/
private static boolean Utf8codeCheck(String text) {
String sign = "";
if (text.startsWith("%e"))
for (int i = 0, p = 0; p != -1; i++) {
p = text.indexOf("%", p);
if (p != -1)
p++;
sign += p;
}
return sign.equals("147-1");
}
/**
* 是否Utf8Url编码
*
* @param text
* @return
*/
public boolean isUtf8Url(String text) {
text = text.toLowerCase();
int p = text.indexOf("%");
if (p != -1 && text.length() - p > 9) {
text = text.substring(p, p + 9);
}
return Utf8codeCheck(text);
}
/**
* utf8URL编码转字符
*
* @param text
* @return
*/
private static String CodeToWord(String text) {
String result;
if (Utf8codeCheck(text)) {
byte[] code = new byte[3];
code[0] = (byte) (Integer.parseInt(text.substring(1, 3), 16) - 256);
code[1] = (byte) (Integer.parseInt(text.substring(4, 6), 16) - 256);
code[2] = (byte) (Integer.parseInt(text.substring(7, 9), 16) - 256);
try {
result = new String(code, "UTF-8");
} catch (UnsupportedEncodingException ex) {
result = null;
}
} else {
result = text;
}
return result;
}
public static String format(String message, Object[] words) {
if (words != null && words.length > 0 && message instanceof String) {
message = MessageFormat.format((String) message, words);
}
return message;
}
/**
* servlet
*
* @param str
* @return
* @throws UnsupportedEncodingException
*/
public static String toStringUTF8(String str)
throws UnsupportedEncodingException {
return new String(str.getBytes("ISO-8859-1"), "UTF-8");
}
/**
* 时间格式转换 <> 取得当前系统时间
*
* @param date
* @return
*/
public static String dateToString(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(date);
return str;
}
/**
* 判断是否是手机号码
*
* @param mobile
* @return
* @Description:
*/
public static boolean isMobileNo(String mobile) {
boolean isTrue = false;
Pattern p = Pattern
.compile("^((13[0-9])|(15[^4,\\D])|(17[6-8])|(18[0-9]))\\d{8}$");
Matcher m = p.matcher(mobile);
isTrue = m.matches();
return isTrue;
}
/**
* 截取后几位的字符串
*
* @param str
* @param lenth
* @return
* @Description:
*/
public static String cutBehindStr(String str, int lenth) {
return str.substring(str.length() - lenth);
}
/**
* 生成指定位数数字随机数
*
* @return
* @Description:
*/
public static String getRandomDigitStr(int count) {
Random rd = new Random();
String n = "";
int getNum;
do {
getNum = Math.abs(rd.nextInt()) % 10 + 48;// 产生数字0-9的随机数
// getNum = Math.abs(rd.nextInt())%26 + 97;//产生字母a-z的随机数
char num1 = (char) getNum;
String dn = Character.toString(num1);
n += dn;
} while (n.length() < count);
return n;
}
/**
* (单位:米)转算成经纬度 纬度1度 = 大约111km 纬度1分 = 大约1.85km 纬度1秒 = 大约30.9m 经度xpoint =
* 116.34(单位:°) 纬度ypoint = 24.52(单位:°)
*
* @return
* @Description:
*/
public static double ConvertXYpoint(Object obj) {
if (null == obj || "".equals(obj.toString().trim())
|| obj.toString().toUpperCase().equals("NULL")) {
return 0;
} else {
Double d = new Double(obj.toString());
return d / 111 / 1000;
}
}
/**
* 判断文件是否为图片<br>
* <br>
* @param pInput 文件名<br>
* @param pImgeFlag 判断具体文件类型<br>
* @return 检查后的结果<br>
* @throws Exception
*/
public static boolean isPicture(String pInput) throws Exception{
// 文件名称为空的场合
if(isNullOrEmpty(pInput)){
// 返回不和合法
return false;
}
// 获得文件后缀名
String tmpName = pInput.substring(pInput.lastIndexOf(".") + 1,
pInput.length());
// 声明图片后缀名数组
String imgeArray [] = {"bmp","gif","jpe","jpg","jpeg","png"};
for (int i = 0; i < imgeArray.length; i++) {
if(tmpName.equals(imgeArray[i])){
return true;
}
}
return false;
}
public static String removeBlankAndEnter(String content) {
String dest = "";
if (content != null) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(content);
dest = m.replaceAll("");
}
return dest;
}
public static String sub(String str,int bi,int ei) {
return str.substring(bi, ei);
}
/**
* 验证邮箱
* @param email
* @return
*/
public static boolean checkEmail(String email){
boolean flag = false;
try{
String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
Pattern regex = Pattern.compile(check);
Matcher matcher = regex.matcher(email);
flag = matcher.matches();
}catch(Exception e){
flag = false;
}
return flag;
}
/**
* 验证邮箱
* @param email
* @return
*/
public static boolean checkAccount(String account){
boolean flag = false;
try{
String check = "^[A-Za-z0-9]{6,20}$";
Pattern regex = Pattern.compile(check);
Matcher matcher = regex.matcher(account);
flag = matcher.matches();
}catch(Exception e){
flag = false;
}
return flag;
}
}
MD5 工具类 (这里我修改了一下,为了支持body中文,MD5做了编码)
public class MD5Util {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
订单生成
public class OrderUtil {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
/**
* 生成订单号
*
* @param pre 订单号前缀
* @return
*/
public static String gens(String pre) {
//生成
String orderNo = pre + sdf.format(new Date()) + (1 + (int) (Math.random() * 10000));
return orderNo;
}
}
Token获取
public class Token {
/**
* 获取Token
* @param appid
* @param secret
* @return
*/
public static Map getAccessTokenMap(String appid,String secret){
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret;
String x = "";
try {
x = HttpInvoker.sendGetRequest(url);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, Object> toMap = WeixinUtil.jsonStrToMap(x);
return toMap;
/*Map map = JSON.parseObject(x, HashMap.class);
return map;*/
}
/**
* 刷新Token
*/
public void updataAccessToken() {
String appid= "";
String secret="";
Map tokenMap = Token.getAccessTokenMap(appid, secret);
String accessToken = tokenMap.get("access_token").toString();
int ex_time = 7200;
}
}
openId获取
/**
* 获取微信openId
* @param code 微信登录授权code
* @return
*/
public static String getOpenId(String code){
String openId="";
//请求api获取openid
String str = HttpInvoker.sendGetRequest(StringUtil.format(WxPayConfig.GET_OPENID, new Object[]{WxPayConfig.APPID,WxPayConfig.APPSECRET,code}));
//将json转map
Map<String, Object> toMap = WeixinUtil.jsonStrToMap(str);
if(!StringUtil.isNullOrEmpty(toMap.get("openid"))){//获取openid成功
openId=(String) toMap.get("openid");
}
return openId;
}
微信相关工具类
/**
* 微信相关工具类
* ClassName:WeixinUtil
* Date: 2017年10月24日 下午2:05:05
* @author sqq
* @since JDK 1.8
*/
public class WeixinUtil {
/** = */
public static final String QSTRING_EQUAL = "=";
/** & */
public static final String QSTRING_SPLIT = "&";
/**
* 作用:产生随机字符串,不长于32位
*/
public static String createNoncestr(int length){
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
String str ="";
Random rand = new Random();
for (int i = 0; i < length; i++) {
int index = rand.nextInt(chars.length());
str += chars.substring(index, index + 1);
}
return str;
}
/**
* 把请求要素按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param para 请求要素
* @param sort 是否需要根据key值作升序排列
* @param encode 是否需要URL编码
* @return 拼接成的字符串
*/
public static String formatBizQueryParaMap(Map<String,String> para,boolean sort, boolean encode)
{
List<String> keys = new ArrayList<String>(para.keySet());
if (sort)
Collections.sort(keys);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = para.get(key);
if (encode) {
try {
value = URLEncoder.encode(value, WxPayConfig.ENCODE);
} catch (UnsupportedEncodingException e) {
}
}
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
sb.append(key).append(QSTRING_EQUAL).append(value);
} else {
sb.append(key).append(QSTRING_EQUAL).append(value).append(QSTRING_SPLIT);
}
}
return sb.toString();
}
/**
* 作用:生成签名
*/
public static String getSign(Map<String,String> paramMap)
{
// System.out.println("------------------bef-----------");
for (String key : paramMap.keySet()) {//
// System.out.println("-------------------------:" + key);
//值为空不参加签名
if(StringUtil.isNullOrEmpty(paramMap.get(key))){
// System.out.println("-------------------------1:" + key);
paramMap.remove(key);
}
}
String params = formatBizQueryParaMap(paramMap, true, false);
//echo '【string1】'.$String.'</br>';
//签名步骤二:在string后加入KEY
params = params + "&key=" + WxPayConfig.KEY;//
//echo "【string2】".$String."</br>";
//签名步骤三:MD5加密并转大写
params = MD5Util.MD5Encode(params,"utf-8");
//echo "【string3】 ".$String."</br>";
//签名步骤四:所有字符转为大写
//echo "【result】 ".$result_."</br>";
return params;
}
/**
* 作用:map转xml
*/
public static String arrayToXml(Map<String,String> paramMap){
String xml = "<xml>";
for (String key : paramMap.keySet()) {//
//值是否只有字母和数字
if(paramMap.get(key).matches("^[\\da-zA-Z]*$")){
xml += "<" + key + ">" + paramMap.get(key) + "</" + key + ">";
}else{
xml += "<" + key + "><![CDATA[" + paramMap.get(key) + "]]></" + key + ">";
}
}
xml += "</xml>";
return xml;
}
/**
* xml 转 map
* @param xml
* @return
*/
public static Map<String,String> xmltoMap(String xml) {
try {
Map<String,String> map = new HashMap<String,String>();
Document document = DocumentHelper.parseText(xml);
Element nodeElement = document.getRootElement();
List node = nodeElement.elements();
for (Iterator it = node.iterator(); it.hasNext();) {
Element elm = (Element) it.next();
String val = elm.getText();
val = val.replace("<![CDATA[", "");
val = val.replace("]]>", "");
map.put(elm.getName(), val);
elm = null;
}
node = null;
nodeElement = null;
document = null;
return map;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* jsonStrToMap:(json转map).
* @author sqq
* @param jsonStr
* @return
* @since JDK 1.8
*/
public static Map<String, Object> jsonStrToMap(String jsonStr){
Map<String, Object> map = new HashMap<String, Object>();
//最外层解析
JSONObject json = JSONObject.fromObject(jsonStr);
for(Object k : json.keySet()){
Object v = json.get(k);
//如果内层还是数组的话,继续解析
if(v instanceof JSONArray){
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
Iterator<JSONObject> it = ((JSONArray)v).iterator();
while(it.hasNext()){
JSONObject json2 = it.next();
list.add(jsonStrToMap(json2.toString()));
}
map.put(k.toString(), list);
} else {
map.put(k.toString(), v);
}
}
return map;
}
/**
* 获取ip地址
* getRemoteHost
* @author sqq
* @param request
* @return
* @since JDK 1.8
*/
public static String getRemoteHost(javax.servlet.http.HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
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.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
}
/**
* 获取精确到秒的时间戳
* @param date
* @return
*/
public static int getTimestamp(Date date){
if (null == date) {
return 0;
}
String timestamp = String.valueOf(date.getTime()/1000);
return Integer.valueOf(timestamp);
}
/**
* 授权统一路径拼凑
* @param dqurl 当前访问的路径
* @param str 路径返回的参数
* @return
* @throws Exception
*/
public String doWeixinRedirectUrl(HttpServletRequest request) throws Exception{
//特别注意:params分享会出现code过期参数 应去掉后作为回调地址
// String server_url_name = PropertiesUtil.getValue("SERVER_URL_NAME");//服务器地址
String returl = request.getScheme()+"://"+ request.getServerName() + request.getRequestURI();
Map<String,String[]> paramMap = request.getParameterMap();
String params = "";
int next = 0;
//过滤code、state
for (String key : paramMap.keySet()) {
String[] strs = paramMap.get(key);
if(!key.equals("code") && !key.equals("state")){
if(next == 0){
params += "?";
}else{
params += "&";
}
params += key + "=" + strs[0];
next ++;
}
}
System.out.println("params:" + params);
String dqurl = returl + params;
dqurl = URLEncoder.encode(dqurl, "utf-8");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+ WxPayConfig.APPID +"&redirect_uri="+ dqurl +"&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";
return url;
}