支付宝配置:
package com.integralpay.config; public class AlipayConfig { //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号 public static String app_id = "2018000000000"; // 商户私钥,您的PKCS8格式RSA2私钥 public static String merchant_private_key = "xxxxxxxxxxxxxxxxxxxxxx"; // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。 public static String alipay_public_key = "xxxxxxxxxxxxxxxxxxxxxx"; // 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 // 支付宝与服务器交互的页面,用户看不到 public static String notify_url = "http://xxxxx/notify_url"; // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 // 付款成功之后返回给用户查看的界面 public static String return_url = "http://xxxxx/return_url"; // 签名方式 public static String sign_type = "RSA2"; // 字符编码格式 public static String charset = "utf-8"; // 支付宝网关 现在是沙箱地址 public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ }
微信配置(微信使用的是第二种方式 统一支付):
package com.integralpay.config; public class WechatConfig { public static String appid = "wx12345678910"; // appid public static String appsecret = ""; // appsecret public static String mch_id = "150000000000"; // 商业号 public static String key = "6acd9791afa5adz9das8a5d04e1388a"; // API_KEY public static String spbill_create_ip = "0.0.0.0"; // 获取发起电脑 ip public static String notify_url = "http://xxxx/weixin_notify"; // 回调接口 }
下面是具体实现
支付宝
package com.integralpay.controller; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.request.AlipayTradePagePayRequest; import com.talent.cloud.integralpay.config.AlipayConfig; import com.talent.cloud.integralpay.entity.T_integralRecharge; import com.talent.cloud.integralpay.service.IntegralrechargeService; @Controller public class AliPayController { @Autowired private IntegralrechargeService integralrechargeService; /** * 获取订单数据接口 * @param request * @param response * @throws AlipayApiException * @throws IOException */ @RequestMapping("/AliPay") public void AliPay(T_integralRecharge integralRecharge,HttpServletRequest req, Model mod, HttpServletResponse rep) throws AlipayApiException, IOException{ //系统下单 int hashCodeV = UUID.randomUUID().toString().hashCode(); if(hashCodeV < 0) { //有可能是负数 hashCodeV = - hashCodeV; } integralRecharge.setOrder_id(integralRecharge.getEnterprise_id()+String.format("%015d", hashCodeV)); integralRecharge.setState(0); integralrechargeService.insertOrder(integralRecharge); //获得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type); //设置请求参数 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(AlipayConfig.return_url); alipayRequest.setNotifyUrl(AlipayConfig.notify_url); //商户订单号,商户网站订单系统中唯一订单号,必填 String out_trade_no = integralRecharge.getOrder_id(); //付款金额,必填 String total_amount = integralRecharge.getAmount().toString(); //订单名称,必填 String subject = "积分充值"; //商品描述,可空 String body = "人才云积分充值"; alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," + "\"total_amount\":\""+ total_amount +"\"," + "\"subject\":\""+ subject +"\"," + "\"body\":\""+ body +"\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); //请求 String result = alipayClient.pageExecute(alipayRequest).getBody(); rep.setContentType("text/html;charset=" + AlipayConfig.charset); rep.getWriter().write(result);//直接将完整的表单html输出到页面 rep.getWriter().flush(); rep.getWriter().close(); } /** * 回调路径return_url * @param request * @param response * @throws AlipayApiException * @throws IOException */ @RequestMapping(value = "/return_url", method = RequestMethod.GET) public void returnUrl(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, IOException{ String msg = new String(); //获取支付宝GET过来反馈信息 Map<String,String> params = new HashMap<String,String>(); Map requestParams = request.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } //乱码解决,这段代码在出现乱码时使用。 //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset,AlipayConfig.sign_type); if(signVerified) { //商户订单号 String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8"); //支付宝交易号 String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8"); //付款金额 String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8"); //系统处理根据支付宝回调更改订单状态或者其他关联表的数据 T_integralRecharge order = integralrechargeService.findOneByTradeCode(out_trade_no); if(order == null) { msg = "订单号不存在"; }else { /* if(!order.getAmount().toString().equals(total_amount)){ msg = "付款金额错误"; }*/ if(order.getState() == 1){ //判断当前订单是否已处理 msg = "系统订单:"+ out_trade_no + "成功支付。"; } } }else{ msg = "验签失败"; } response.setContentType("text/html;charset=utf-8"); PrintWriter out=response.getWriter(); out.println("<html><script>window.onload=()=>{alert('"+msg+"');window.location.href='http://localhost:8081/#/enterprisePurse/';}</script></html>"); } @RequestMapping(value = "/notify_url", method = RequestMethod.POST) public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, IOException{ //获取支付宝POST过来反馈信息 response.setContentType("text/html;charset=" + AlipayConfig.charset); Map<String,String> params = new HashMap<String,String>(); Map requestParams = request.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } //乱码解决,这段代码在出现乱码时使用。 //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset,AlipayConfig.sign_type); if(signVerified) { //商户订单号 String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8"); //支付宝交易号 String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8"); //交易状态 String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8"); //系统处理根据支付宝回调更改订单状态或者其他关联表的数据 T_integralRecharge order = integralrechargeService.findOneByTradeCode(out_trade_no); if(trade_status.equals("TRADE_FINISHED")){ //已经付款过 if(order.getState() == 0) { integralrechargeService.handleOrder(out_trade_no,order.getEnterprise_id(),order.getAmount()); } }else if (trade_status.equals("TRADE_SUCCESS")){ //付款成功 if(order.getState() == 0) { integralrechargeService.handleOrder(out_trade_no,order.getEnterprise_id(),order.getAmount()); } } response.getWriter().write("success"); }else {//验证失败 response.getWriter().write("fail"); } response.getWriter().flush(); response.getWriter().close(); } }
微信
package com.integralpay.controller; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.talent.cloud.integralpay.config.WechatConfig; import com.talent.cloud.integralpay.entity.T_integralRecharge; import com.talent.cloud.integralpay.service.IntegralrechargeService; import com.talent.cloud.integralpay.util.HttpUtil; import com.talent.cloud.integralpay.util.PayCommonUtil; import com.talent.cloud.integralpay.util.XMLUtil; import net.sf.json.JSONObject; @Controller public class WechatController { @Autowired private IntegralrechargeService integralrechargeService; @RequestMapping("/WechatPay") @ResponseBody public String weixin_pay(T_integralRecharge integralRecharge) throws Exception { JSONObject object = new JSONObject(); // 账号信息 String appid = WechatConfig.appid; // appid //String appsecret = PayConfigUtil.APP_SECRET; // appsecret String mch_id = WechatConfig.mch_id; // 商业号 String key = WechatConfig.key; // key String currTime = PayCommonUtil.getCurrTime(); String strTime = currTime.substring(8, currTime.length()); String strRandom = PayCommonUtil.buildRandom(4) + ""; String nonce_str = strTime + strRandom; //integralRecharge.setAmount(integralRecharge.getAmount() * 100); String order_price = integralRecharge.getAmount().toString(); // 价格 注意:价格的单位是分 String body = "人才云积分充值"; // 商品名称 int hashCodeV = UUID.randomUUID().toString().hashCode(); if(hashCodeV < 0) { //有可能是负数 hashCodeV = - hashCodeV; } String out_trade_no = integralRecharge.getEnterprise_id()+String.format("%015d", hashCodeV); // 订单号 object.put("out_trade_no", out_trade_no); //生成订单 integralRecharge.setOrder_id(out_trade_no); integralRecharge.setState(0); integralrechargeService.insertOrder(integralRecharge); // 获取发起电脑 ip String spbill_create_ip = WechatConfig.spbill_create_ip; // 回调接口 String notify_url = WechatConfig.notify_url; String trade_type = "NATIVE"; SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>(); packageParams.put("appid", appid); 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", order_price); packageParams.put("spbill_create_ip", spbill_create_ip); packageParams.put("notify_url", notify_url); packageParams.put("trade_type", trade_type); String sign = PayCommonUtil.createSign("UTF-8", packageParams,key); packageParams.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(packageParams); String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML); Map map = XMLUtil.doXMLParse(resXml); //String return_code = (String) map.get("return_code"); //String prepay_id = (String) map.get("prepay_id"); String urlCode = (String) map.get("code_url"); object.put("urlCode", urlCode); return object.toString(); } @RequestMapping("/weixin_notify") public void weixin_notify(HttpServletRequest request,HttpServletResponse response) throws Exception{ String msg = new String(); //读取参数 InputStream inputStream ; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s ; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.readLine()) != null){ sb.append(s); } in.close(); inputStream.close(); //解析xml成map Map<String, String> m = new HashMap<String, String>(); m = XMLUtil.doXMLParse(sb.toString()); //过滤空 设置 TreeMap SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>(); Iterator it = m.keySet().iterator(); while (it.hasNext()) { String parameter = (String) it.next(); String parameterValue = m.get(parameter); String v = ""; if(null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } // 账号信息 String key = "xxxxxxxxxxxxxxxxxxx"; // api-key //判断签名是否正确 if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) { //------------------------------ //处理业务开始 //------------------------------ String resXml = ""; if("SUCCESS".equals((String)packageParams.get("result_code"))){ // 这里是支付成功 //////////执行自己的业务逻辑//////////////// String mch_id = (String)packageParams.get("mch_id"); String openid = (String)packageParams.get("openid"); String is_subscribe = (String)packageParams.get("is_subscribe"); String out_trade_no = (String)packageParams.get("out_trade_no"); String total_fee = (String)packageParams.get("total_fee"); T_integralRecharge order = integralrechargeService.findOneByTradeCode(out_trade_no); if(order.getState() == 0) { integralrechargeService.handleOrder(out_trade_no,order.getEnterprise_id(),order.getAmount()); } //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { /*logger.info("支付失败,错误信息:" + packageParams.get("err_code"));*/ resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } //------------------------------ //处理业务完毕 //------------------------------ BufferedOutputStream out = new BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } else{ /*logger.info("通知签名验证失败");*/ } } }
微信还需要几个工具类
package com.integralpay.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; 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){ return postData(urlStr, data, null); } public static String postData(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) { } finally { try { if (reader != null) reader.close(); } catch (IOException e) { } } return null; } }
package com.integralpay.util; import java.security.MessageDigest; 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" }; }
package com.integralpay.util; 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排序,遇到空值的参数不参加签名。 * @return boolean */ 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(); //System.out.println(tenpaySign + " " + mysign); return tenpaySign.equals(mysign); } /** * @author * @date 2016-4-22 * @Description:sign签名 * @param characterEncoding * 编码格式 * @param parameters * 请求参数 * @return */ 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; } /** * @author * @date 2016-4-22 * @Description:将请求参数转换为xml格式的string * @param parameters * 请求参数 * @return */ 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(); } /** * 取出一个指定长度大小的随机正整数. * * @param length * int 设定所取出随机数的长度。length小于11 * @return int 返回生成的随机数。 */ 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; } }
package com.talent.cloud.integralpay.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; public class XMLUtil { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ 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 */ 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(); } }