前些日子做的微信扫码支付,现在都有点忘了怎么做的了,赶紧记录一下。。
首先先看比较好的案例,帮了我好多好多,太感谢无私奉献的人们了,我选择的模式二开发
一、场景:公司需要在网站上进行微信支付。
二、API:使用微信开放平台的接入微信支付
-扫码支付。
三、实现:
一是:按照微信扫码支付规则生成二维码信息.
二是:微信没有提供生成二维码图片的接口。需要我们自己把二维码信息生成到二维码图片中。
1、首先我们要获取微信后台的必要的信息。
public class Configure {
// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证 // 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改 public static String key = ""; //微信分配的公众号ID(开通公众号之后可以获取到) public static String appID = ""; public static String appsecret = ""; //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) public static String mchID = ""; //HTTPS证书的本地路径 public static String certLocalPath = "D:/wx/apiclient_cert.p12"; //HTTPS证书密码,默认密码等于商户号MCHID public static String certPassword = ""; /** * 功能描述: 获取客户端IP * * @author yanzy 2016-1-18 下午08:19:45 * * @param request * @return */ public static String getClientIp(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; } //随机字符串 public static String getNonceStr() { String currTime = PayCommonUtil.getCurrTime(); String strTime = currTime.substring(8, currTime.length()); String strRandom = PayCommonUtil.buildRandom(4) + ""; String nonce_st = strTime + strRandom; return nonce_st; } //1)扫码支付API public static String PAY_API = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //2)退款API public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //3)退款查询API public static String REFUND_QUERY_API = "https://api.mch.weixin.qq.com/pay/refundquery"; //4)查询订单状态 public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery"; public static String notify_url = BlockAttribute.host+"/payment/weixin/weixin_notify.jsp"; public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest"; }还有各种工具类:HttpUtilpublic 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) { LogUtil.writeLog("Error connecting to " + urlStr + ": " + e.getMessage()); } finally { try { if (reader != null) reader.close(); } catch (IOException e) { } } return null; } /** * 自定义SSL双向证书验证 * * @param url * @param mchId * @param arrayToXml * @return * @throws Exception */ public static String clientCustomSSLCall(String url,String mchId, String arrayToXml) throws Exception { String jsonStr = null; KeyStore keyStore = KeyStore.getInstance("PKCS12"); // System.out.println("capath:=" + cAPath); FileInputStream instream = new FileInputStream(new File(Configure.certLocalPath)); try { keyStore.load(instream, mchId.toCharArray()); } finally { instream.close(); } // Trust own CA and all self-signed certs SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { HttpPost httpPost = new HttpPost(url); httpPost.setEntity(new StringEntity(arrayToXml, "UTF-8")); CloseableHttpResponse response = httpclient.execute(httpPost); jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); response.close(); } finally { httpclient.close(); } return jsonStr; } }MD5工具类
public class MD5 {
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; /** * 转换字节数组为16进制字串 * @param b 字节数组 * @return 16进制字串 */ public static String byteArrayToHexString(byte[] b) { StringBuilder resultSb = new StringBuilder(); for (byte aB : b) { resultSb.append(byteToHexString(aB)); } return resultSb.toString(); } /** * 转换byte到16进制 * @param b 要转换的byte * @return 16进制格式 */ private static String byteToHexString(byte b) { int n = b; if (n < 0) { n = 256 + n; } int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } /** * MD5编码 * @param origin 原始字符串 * @return 经过MD5加密之后的结果 */ 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; } }PayCommonUtil 工具类
@SuppressWarnings({"rawtypes"})
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 = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); String tenpaySign = ((String)packageParams.get("sign")).toLowerCase(); return tenpaySign.equals(mysign); } /** * @Description:sign签名 * @param characterEncoding * @param parameters * @return */ public static String createSign(String characterEncoding, SortedMap<String, String> parameters, String API_KEY) { StringBuffer sb = new StringBuffer(); 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 (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + API_KEY); String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; } /** * @author * @date 2016-4-22 * @Description:将请求参数转换为xml格式的string * @param parameters * 请求参数 * @return */ public static String getRequestXml(SortedMap<String, String> 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; } public static String getCurrTimeS() { Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyy"+"年"+"MM"+"月"+"dd"+"日 "+"HH"+"时"+"mm"+"分"+"ss"+"秒"); String s = outFormat.format(now); return s; }}XMLUtil 工具类
@SuppressWarnings({"unchecked"})
public class XMLUtil { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map<String, Object> doXMLParse(String strxml) throws JDOMException, IOException { strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if(null == strxml || "".equals(strxml)) { return null; } Map<String, Object> m = new HashMap<String, Object>(); InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8")); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List<Element> list = root.getChildren(); Iterator<Element> it = list.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List<Element> 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<Element> children) { StringBuffer sb = new StringBuffer(); if(!children.isEmpty()) { Iterator<Element> it = children.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String name = e.getName(); String value = e.getTextNormalize(); List<Element> list = e.getChildren(); sb.append("<" + name + ">"); if(!list.isEmpty()) { sb.append(XMLUtil.getChildrenText(list)); } sb.append(value); sb.append("</" + name + ">"); } } return sb.toString(); } }以上是需要用到的工具类,下面我们就要开始调用了
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.cn.service.face.payment.weixinpay.*"%> <%@ page import="java.util.*"%><%@ page import="java.lang.*"%><%@ page import="com.cn.service.environment.*" %><%@ page import="com.cn.dto.entity.ordermanage.*"%><%@ page import="com.cn.service.face.order.commodity.*"%><%@ page import="com.cn.service.face.payment.weixinpay.*"%><%@ page import="com.cn.service.system.tools.*"%><% ///微信扫码支付接口 请求参数/ String orderno = request.getParameter("orderno"); OrderManyPayFace orderManyPayFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderManyPayFace.class); UserOrder uo = orderManyPayFace.getUserOrder(orderno); double money=orderManyPayFace.getPayMoney(orderno); int transport=uo.getTransportCosts()!=null?uo.getTransportCosts().intValue():0; orderno=orderManyPayFace.getPayOrderno(orderno); money=money+transport; String txnAmt =Double.valueOf(money*100).intValue()+""; String body=uo.getOrderName(); SortedMap<String,String> parameters = new TreeMap<String,String>(); parameters.put("body", body); //商品描述 parameters.put("out_trade_no", orderno); //商户订单号 parameters.put("total_fee", txnAmt); //交易金额,单位分,不要带小数点 parameters.put("trade_type", "NATIVE"); //交易类型 , parameters.put("product_id", orderno); //商品ID WinxinpayServiceFace winxinpay=EnvironmentBean.getInstance().getBeanByBeanClass(WinxinpayServiceFace.class); String sHtmlText = winxinpay.trade_create_by_weixinpay(parameters,request); String qrcode=ZxingEncode.createQRCode(200, 200, request, sHtmlText);%><script type="text/javascript" src="js/jquery-1.7.1.min.js"></script><script type="text/javascript" src="js/qrcode.js"></script><style>*{ margin:0px; padding:0px;}.wrapper{width:1000px; margin:20px auto;border:1px solid #ccc;}.orderdetail{ background:#f2f2f2; height:60px; line-height:60px; color:#333333; padding-left:20px; padding-right:20px;}.orderdetail span{ display:block;}.ordernum{ float:left;}.ordermoney{ float:right;}.logo{ padding:20px;}.pay_method{margin:20px; position:relative; height:400px;}.pay_method ul{ position:absolute;left:0px;top:0px;background:#fff; z-index:1;}.pay_method ul li{ float:left; list-style:none; border:1px solid #ccc;border-bottom:none; height:30px; line-height:30px; padding-left:20px; padding-right:20px;}.num_pay{border:1px solid #ccc;position:absolute;left:0px;top:29px; width:960px; height:360px;}.logowx{margin-top:20px;margin-left:20px;}.erweima{ margin:0px auto; text-align:center;}.erweima span{ display:block; margin-bottom:10px;}</style><body><div class="wrapper"> <div class="logo"><img src="images/pay/logo.png" width="61" height="26" /></div> <div class="orderdetail"> <span class="ordernum">订单编号: <%=orderno%></span> <span class="ordermoney">应付金额:¥<%=money%></span> </div> <div class="pay_method"> <ul> <li>微信支付</li> </ul> <div style="clear:both;"></div> <div class="num_pay"> <img src="images/pay/WePayLogo.png" width="120" height="32" class="logowx" /> <div class="erweima"> <!-- <span id="qrcode"></span> --> <img src="<%=qrcode%>"/> <span><img src="images/pay/des.png" width="180" height="60"/></span> </div> </div> </div></div></body><script type="text/javascript"> //这是查询订单 var t1; var sum=0; var out_trade_no="<%=orderno%>"; var paymentId="<%=uo.getPaymentId()%>"; t1=setInterval("ajaxstatus()", 5000); function ajaxstatus() { sum++; if(sum>600){ window.clearInterval(t1);return false;} if(sum>180){ m=sum % 10; if(m!=0){return false;} } if (out_trade_no != null) { $.ajax({ type:"post", url:"/PaymentFgAction!weixinQuery.action", dataType:"json", data: {"orderno":out_trade_no,"paymentId":paymentId}, success: function (data) { if (data== "1") { window.location.href = "http://www.hiersun-ido.com/account/listUserOrder.html"; //<a href="http://www.hiersun-ido.com/account/listUserOrder.html">返回个人中心</a> } }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("请求订单状态出错"); } }); } }</script>
/**
* 构造微信扫码支付跳转接口 * @param sParaTemp 请求参数集合 * @return 表单提交HTML信息 * @throws IOException * @throws JDOMException */ public static String trade_create_by_weixinpay(SortedMap<String, String> parameters,HttpServletRequest request) throws JDOMException, IOException { //增加基本配置 parameters.put("appid", Configure.appID); parameters.put("mch_id", Configure.mchID); parameters.put("nonce_str",Configure.getNonceStr()); parameters.put("spbill_create_ip", Configure.getClientIp(request)); parameters.put("notify_url", Configure.notify_url); String sign = PayCommonUtil.createSign("UTF-8", parameters,Configure.key); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String resXml = HttpUtil.postData(Configure.PAY_API, requestXML); Map map = XMLUtil.doXMLParse(resXml); String urlCode = (String) map.get("code_url"); return urlCode; }/**
* 微信扫码支付交易状态查询 * @throws IOException * @throws JDOMException */ public String weixinQuery(String orderno) throws JDOMException, IOException { SortedMap<String,String> parameters = new TreeMap<String,String>(); //查询交易需要的参数 parameters.put("appid", Configure.appID); parameters.put("mch_id", Configure.mchID); parameters.put("out_trade_no", orderno); //商户订单号 parameters.put("nonce_str",Configure.getNonceStr()); String sign = PayCommonUtil.createSign("UTF-8", parameters,Configure.key); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String resXml = HttpUtil.postData(Configure.PAY_QUERY_API, requestXML); Map map = XMLUtil.doXMLParse(resXml); String trade_state = (String) map.get("trade_state"); return trade_state ; } /** * 构造微信扫码申请退款接口 * @param sParaTemp 请求参数集合 * @return 表单提交HTML信息 * @throws Exception */ public static String trade_create_by_weixinrefund(SortedMap<String, String> parameters) { String result_code=null; //增加基本配置 try { parameters.put("appid", Configure.appID); parameters.put("mch_id", Configure.mchID); parameters.put("nonce_str",Configure.getNonceStr()); String sign = PayCommonUtil.createSign("UTF-8", parameters,Configure.key); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String resXml; resXml = HttpUtil.clientCustomSSLCall(Configure.REFUND_API, Configure.mchID,requestXML); //String resXml = HttpUtil.postData(Configure.REFUND_API, requestXML); Map map = XMLUtil.doXMLParse(resXml); result_code = (String) map.get("result_code"); String err_code_des=(String)map.get("err_code_des"); String refund_id=(String)map.get("refund_id"); if("SUCCESS".equals(result_code)){ return refund_id; }else{ return err_code_des; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "申请退款失败"; } }生成二维码的工具类
import java.io.*;
import java.util.*;import java.awt.*;import java.awt.image.*;import javax.imageio.*;import javax.servlet.http.*;import com.google.zxing.*;import com.google.zxing.common.*;import com.cn.service.system.common.*;import com.google.zxing.qrcode.decoder.*;@SuppressWarnings({ "rawtypes","unchecked","unused"})public class ZxingEncode { public ZxingEncode() { super(); } /** * 生成二维码,并返回二维码图片路径,文件名自动生成 * content:二维码内容 */ public static String createQRCode(int width,int height,HttpServletRequest request,String content) { String attachPath=""; try { attachPath=AttachFile.getImagePath(request,BlockAttribute.twoDimensionCode); /*String projectName=AttachFile.getProjectName(attachPath); String temp_attachPath=attachPath; String mob_attachPath=attachPath; attachPath=attachPath.replaceAll(projectName, "OhdManage.war"); temp_attachPath=temp_attachPath.replaceAll(projectName, "OhdStudio.war"); 同步文件夹:一个文件同时存储在二个项目下 mob_attachPath=mob_attachPath.replaceAll(projectName, "OhdMobile.war"); 同步文件夹:一个文件同时存储在二个项目下 */ attachPath=AttachFile.createAttachDir(attachPath); /*temp_attachPath=AttachFile.createAttachDir(temp_attachPath); mob_attachPath=AttachFile.createAttachDir(mob_attachPath);*/ String fileName=AttachFile.createFileName("png"); attachPath=attachPath+FileTool.getFileSystemSeparator()+fileName; /*temp_attachPath=temp_attachPath+FileTool.getFileSystemSeparator()+fileName; mob_attachPath=mob_attachPath+FileTool.getFileSystemSeparator()+fileName;*/ ZxingEncode qrcodeEncoder=new ZxingEncode(); qrcodeEncoder.encoderQRCode(content, attachPath,width,height); /*qrcodeEncoder.encoderQRCode(content, temp_attachPath,width,height); qrcodeEncoder.encoderQRCode(content, mob_attachPath,width,height); attachPath=attachPath.substring(attachPath.indexOf("userfiles"));*/ } catch(Exception err) { err.printStackTrace(); } return AttachFile.getWebAttachPath(attachPath); } /** * 生成二维码,并返回二维码图片路径,需要传入文件名 * content:二维码内容 */ public static String createQRCode(int width,int height,HttpServletRequest request,String content,String fileName) { String attachPath=""; try { attachPath=AttachFile.getImagePath(request,BlockAttribute.twoDimensionCode); /*String projectName=AttachFile.getProjectName(attachPath); String temp_attachPath=attachPath; String mob_attachPath=attachPath; attachPath=attachPath.replaceAll(projectName, "OhdManage.war"); temp_attachPath=temp_attachPath.replaceAll(projectName, "OhdStudio.war"); 同步文件夹:一个文件同时存储在二个项目下 mob_attachPath=mob_attachPath.replaceAll(projectName, "OhdMobile.war"); 同步文件夹:一个文件同时存储在二个项目下 */ attachPath=AttachFile.createAttachDir(attachPath); /*temp_attachPath=AttachFile.createAttachDir(temp_attachPath); mob_attachPath=AttachFile.createAttachDir(mob_attachPath);*/ fileName=fileName+".png"; attachPath=attachPath+FileTool.getFileSystemSeparator()+fileName; /*temp_attachPath=temp_attachPath+FileTool.getFileSystemSeparator()+fileName; mob_attachPath=mob_attachPath+FileTool.getFileSystemSeparator()+fileName;*/ ZxingEncode qrcodeEncoder=new ZxingEncode(); qrcodeEncoder.encoderQRCode(content, attachPath,width,height); /*qrcodeEncoder.encoderQRCode(content, temp_attachPath,width,height); qrcodeEncoder.encoderQRCode(content, mob_attachPath,width,height); attachPath=attachPath.substring(attachPath.indexOf("userfiles"));*/ } catch(Exception err) { err.printStackTrace(); } return AttachFile.getWebAttachPath(attachPath); } /** * 生成二维码(QRCode)图片 * 用微信扫描GBK编码的中文二维码时出现乱码,用UTF-8编码时微信可正常识别 。 * 并且MultiFormatWriter.encode()时若传入hints参数来指定UTF-8编码中文时,微信压根就不识别所生成的二维码。 * 所以这里使用的是这种方式new String(content.getBytes("UTF-8"), "ISO-8859-1")。 * 生成的二维码图片默认背景为白色,前景为黑色,但是在加入logo图像后会导致logo也变为黑白色,至于是什么原因还没有仔细去读它的源码 。 * 所以这里对其第一个参数黑色将ZXing默认的前景色0xFF000000稍微改了一下0xFF000001,最终效果也是白色背景黑色前景的二维码,且logo颜色保持原有。 */ public void encoderQRCode(String content,String imgPath,int width,int height) { try { MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); Map hints = new HashMap<EncodeHintType, String>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); //hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = multiFormatWriter.encode(new String(content.getBytes("UTF-8"),"ISO-8859-1"), BarcodeFormat.QR_CODE, width, height,hints); File file = new File(imgPath); MatrixToImageWriter.writeToFile(bitMatrix, "png", file); } catch(Exception err) { err.printStackTrace(); } } /** * 暂不支持加入头象 * 为其二维码添加头象 * 1)生成二维码的纠错级别建议采用最高等级H,这样可以增加二维码的正确识别能力(我测试过,不设置级别时,二维码工具无法读取生成的二维码图片) * 2)头像大小最好不要超过二维码本身大小的1/5,而且只能放在正中间部位,这是由于二维码本身结构造成的(你就把它理解成图片水印吧) * 3)在仿照腾讯微信在二维码四周增加装饰框,那么一定要在装饰框和二维码之间留出白边,这是为了二维码可被识别 */ public void overlapImage(String imagePath, String logoPath) throws IOException { BufferedImage image = ImageIO.read(new File(imagePath)); int logoWidth = image.getWidth()/5; //设置logo图片宽度为二维码图片的五分之一 int logoHeight = image.getHeight()/5; //设置logo图片高度为二维码图片的五分之一 int logoX = (image.getWidth()-logoWidth)/2; //设置logo图片的位置,这里令其居中 int logoY = (image.getHeight()-logoHeight)/2; //设置logo图片的位置,这里令其居中 Graphics2D graphics = image.createGraphics(); graphics.drawImage(ImageIO.read(new File(logoPath)), logoX, logoY, logoWidth, logoHeight, null); graphics.dispose(); ImageIO.write(image, imagePath.substring(imagePath.lastIndexOf(".") + 1), new File(imagePath)); } private static final class MatrixToImageWriter { private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; private MatrixToImageWriter() { } public static BufferedImage toBufferedImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); } } return image; } public static void writeToFile(BitMatrix matrix, String format,File file) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, file)) { throw new IOException("Could not write an image of format " + format + " to " + file); } } public static void writeToStream(BitMatrix matrix, String format,OutputStream stream) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, stream)) { throw new IOException("Could not write an image of format " + format); } } } public static void main(String[] args) { String imgPath = "D:/Michael_QRCode.png"; ZxingEncode qrcodeEncoder=new ZxingEncode(); qrcodeEncoder.encoderQRCode("http://192.168.12.33:8080/fdsfsafj-fkdsfks343243.html", imgPath,120,120); }}附件的保存与删除
附件只保存在OhdFileMage项目下,图片二维码的工具类public class AttachFile {
public AttachFile() { } /** * 保存附件,返回文件路径,type=0保 存的是文件,type=1保存的是图片 * clsPath:文件的分类文件夹名 * 附件只保存在OhdFileMage项目下 */ public static String saveAttach(byte[] content,String extenName,int type,HttpServletRequest request,String clsPath) throws Exception { String attachPath=""; try { if(type==0) { attachPath=getAttachPath(request,clsPath); } else if(type==1) { attachPath=getImagePath(request,clsPath); } //String projectName=getProjectName(attachPath); /*String temp_attachPath=attachPath; String mob_attachPath=attachPath;*/ //attachPath=attachPath.replaceAll(projectName, "OhdFileMage.war"); /*temp_attachPath=temp_attachPath.replaceAll(projectName, "OhdStudio.war"); 同步文件夹:一个文件同时存储在二个项目下 mob_attachPath=mob_attachPath.replaceAll(projectName, "OhdMobile.war"); 同步文件夹:一个文件同时存储在二个项目下 */ attachPath=createAttachDir(attachPath); /*temp_attachPath=createAttachDir(temp_attachPath); mob_attachPath=createAttachDir(mob_attachPath);*/ String fileName=createFileName(extenName); attachPath=attachPath+FileTool.getFileSystemSeparator()+fileName; /*temp_attachPath=temp_attachPath+FileTool.getFileSystemSeparator()+fileName; mob_attachPath=mob_attachPath+FileTool.getFileSystemSeparator()+fileName;*/ FileTool.writeFile(attachPath, content); /*FileTool.writeFile(temp_attachPath, content); FileTool.writeFile(mob_attachPath, content);*/ } catch(Exception err) { throw err; } return getWebAttachPath(attachPath); } /** * 设置图片路径 */ public static String getWebAttachPath(String attachPath) { return "IdoFileMage/"+attachPath.substring(attachPath.indexOf("userfiles")); } /** * 返回项目名称 */ public static String getProjectName(String attachPath) throws Exception { String projectName=null; if(attachPath.indexOf("IdoManage.war")>=0) { projectName="IdoManage.war"; } else if(attachPath.indexOf("IdoStudio.war")>=0) { projectName="IdoStudio.war"; } else if(attachPath.indexOf("IdoMobile.war")>=0) { projectName="IdoMobile.war"; } return projectName; } /** * 按年月日创建文件夹 */ public static String createAttachDir(String attachPath) throws Exception { attachPath=attachPath+FileTool.getFileSystemSeparator()+DateTool.getYear(); createAttachPath(attachPath); attachPath=attachPath+FileTool.getFileSystemSeparator()+(DateTool.getMonth()+1); createAttachPath(attachPath); /*attachPath=attachPath+FileTool.getFileSystemSeparator()+DateTool.getDay(); //文件夹只需要到月,到日产生太多的文件夹。 createAttachPath(attachPath);*/ return attachPath; } /** * 删除文件 */ public static boolean deleteAttach(String attachPath) throws Exception { boolean deleteAttach=false; if(FileTool.isFileExist(attachPath)) { FileTool.deleteFile(attachPath); deleteAttach=true; } return deleteAttach; } /** * 创建指定的文件夹 */ private static void createAttachPath(String attachPath) throws Exception { if(!FileTool.isFileExist(attachPath)) { FileTool.createDir(attachPath); } } /** * 创建文件名 */ public static String createFileName(String extenName) { String filename=DateTool.dateToTimeString()+getRandom()+"."+extenName; return filename; } /** * 获取web项目路径 * 注:附件只存在OhdFileMage.war项目下 */ public static String getWebPath(HttpServletRequest request) throws Exception { String attachPath=request.getSession().getServletContext().getRealPath("/"); String projectName=getProjectName(attachPath); attachPath=attachPath.replaceAll(projectName, "IdoFileMage.war"); return attachPath; } /** * 获取附件的保存路径 * clsPath:文件的分类文件夹名 */ public static String getAttachPath(HttpServletRequest request,String clsPath) throws Exception { String attachPath=getWebPath(request); attachPath=attachPath+FileTool.getFileSystemSeparator()+"userfiles"+FileTool.getFileSystemSeparator()+"files"+FileTool.getFileSystemSeparator()+clsPath; createAttachPath(attachPath); return attachPath; } /** * 获取附件的保存路径 * clsPath:文件的分类文件夹名 */ public static String getImagePath(HttpServletRequest request,String clsPath) throws Exception { String attachPath=getWebPath(request); attachPath=attachPath+FileTool.getFileSystemSeparator()+"userfiles"+FileTool.getFileSystemSeparator()+"images"+FileTool.getFileSystemSeparator()+clsPath; createAttachPath(attachPath); return attachPath; } /** * 生成一个1到1000的随机数 */ public static int getRandom() { Random rd = new Random(); return (1+rd.nextInt(1000)); }} 支付成功后的回调接口<%
/* * 功能:微信服务器异步通知页面 日期:2017-05-16 * */%><%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%><%@ page import="java.text.*"%><%@ page import="java.util.*"%><%@ page import="java.io.*"%><%@ page import="java.lang.*"%><%@ page import="com.cn.service.error.*" %><%@ page import="com.cn.service.environment.*" %><%@ page import="com.cn.service.face.payment.weixinpay.util.*"%><%@ page import="com.cn.service.face.order.commodity.*"%><%@ page import="com.cn.dto.entity.ordermanage.*"%><%@ page import="com.cn.service.face.order.*"%><% String paymentno=null; String out_trade_no=null; try{ //读取参数 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, Object> m = new HashMap<String, Object>(); 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 =(String) m.get(parameter); String v = ""; if(null != parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter, v); } // 账号信息 String key = Configure.key; // 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 is_subscribe = (String)packageParams.get("is_subscribe"); out_trade_no = (String)packageParams.get("out_trade_no"); String total_fee = (String)packageParams.get("total_fee"); String transaction_id = (String)packageParams.get("transaction_id"); String time_end = (String)packageParams.get("time_end"); OrderPayRefundLogFace orderPayRefundLogFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderPayRefundLogFace.class); orderPayRefundLogFace.saveOrderPayLog(out_trade_no, "微信", packageParams.toString(), ""); //执行自己的业务逻辑 UserOrderFace userOrderFace= EnvironmentBean.getInstance().getBeanByBeanClass(UserOrderFace.class); UserOrder uo = userOrderFace.findUserOrder(out_trade_no); String money=String.valueOf(Double.valueOf(uo.getMoney().doubleValue()*100).intValue()); if(money.equals(total_fee.trim())) { userOrderFace.flushOrderStateSequence(out_trade_no,transaction_id,time_end); //out.println("支付成功"); //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { out.println("假通知"); } } else { out.println("支付失败,错误信息:" + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } out.println(resXml); } else{ out.println("通知签名验证失败"); } } catch(Exception ex) { out.println("通知签名验证失败"); ex.printStackTrace(); try { OrderPayRefundLogFace orderPayRefundLogFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderPayRefundLogFace.class); orderPayRefundLogFace.saveOrderPayLog(out_trade_no, "微信", "", ExceptionOut.writeException(ex)); } catch(Exception error) { error.printStackTrace(); } }%>退款的
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%><%@ page import="java.lang.*"%><%@ page import="com.cn.service.error.*" %><%@ page import="com.cn.service.environment.*" %><%@ page import="com.cn.service.system.tools.*" %><%@ page import="com.cn.dto.entity.ordermanage.*"%><%@ page import="com.cn.service.face.order.commodity.*"%><%@ page import="com.cn.service.face.payment.weixinpay.*"%><%@ page import="com.cn.service.face.payment.weixinpay.util.*"%><% String transaction_id=""; //微信流水号(订单号) try { ///微信扫码支付接口 请求参数/ String orderno = request.getParameter("orderno"); /* type:1-定金,type:2-尾款 */ String type=request.getParameter("type"); String txnAmt=""; //正式的金额 String serviceOrderno=""; //退款批次号 String refundMoney=""; //退款金额 int refundMoneyInt=0; UserOrderFace userOrderFace=EnvironmentBean.getInstance().getBeanByBeanClass(UserOrderFace.class); UserOrder uo = userOrderFace.findUserOrder(orderno); UserAfterSaleFace userAfterSaleFace=EnvironmentBean.getInstance().getBeanByBeanClass(UserAfterSaleFace.class); AfterSaleService afterSaleService=userAfterSaleFace.getAfterSaleServic(uo.getServiceOrderno()); refundMoneyInt=afterSaleService.getRefundMoney()!=null?afterSaleService.getRefundMoney().intValue()*100:afterSaleService.getMoney().intValue()*100; refundMoney=refundMoneyInt+""; serviceOrderno=CodeCreator.createCodeNum12(1)[0]; if("0".equals(uo.getPayType())) { //全款支付退款 transaction_id=uo.getTradeNo(); txnAmt =Double.valueOf(uo.getMoney().doubleValue()*100).intValue()+""; } else if("1".equals(uo.getPayType())) { //定金支付 OrderManyPayFace orderManyPayFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderManyPayFace.class); OrderManyPay orderManyPay1=orderManyPayFace.getOrderManyPay(orderno+"1"); OrderManyPay orderManyPay2=orderManyPayFace.getOrderManyPay(orderno+"2"); if("1".equals(type.trim())) { //定金退款 transaction_id=orderManyPay1.getTradeNo(); txnAmt=Double.valueOf(orderManyPay1.getPaidMoney().doubleValue()*100).intValue()+""; orderno=orderManyPay1.getPayOrderno(); if(refundMoneyInt>(orderManyPay1.getPaidMoney().intValue()*100)) { refundMoney=orderManyPay1.getPaidMoney().intValue()*100+""; } } else if("2".equals(type.trim())) { //尾款退款 transaction_id=orderManyPay2.getTradeNo(); txnAmt=Double.valueOf(orderManyPay2.getPaidMoney().doubleValue()*100).intValue()+""; orderno=orderManyPay2.getPayOrderno(); int toal=orderManyPay1.getPaidMoney().intValue()*100+orderManyPay2.getPaidMoney().intValue()*100; if(refundMoneyInt>=toal) { //退款金额不能多支付金额 refundMoney=orderManyPay2.getPaidMoney().intValue()*100+""; } else if(refundMoneyInt<toal && refundMoneyInt>(orderManyPay1.getPaidMoney().intValue()*100)) { refundMoney=refundMoneyInt-(orderManyPay1.getPaidMoney().intValue()*100)+""; } else if(refundMoneyInt<=(orderManyPay1.getPaidMoney().intValue()*100)) { refundMoney="0"; } } } SortedMap<String,String> parameters = new TreeMap<String,String>(); parameters.put("transaction_id", transaction_id); //微信订单号 parameters.put("out_refund_no", serviceOrderno); //商户退款单号 parameters.put("total_fee", txnAmt); //交易金额,单位分,不要带小数点 parameters.put("refund_fee", refundMoney); //退款金额 parameters.put("appid", Configure.appID); parameters.put("mch_id", Configure.mchID); parameters.put("nonce_str",Configure.getNonceStr()); parameters.put("refund_account","REFUND_SOURCE_RECHARGE_FUNDS"); String sign = PayCommonUtil.createSign("UTF-8", parameters,Configure.key); parameters.put("sign", sign); String requestXML = PayCommonUtil.getRequestXml(parameters); String resXml = HttpUtil.clientCustomSSLCall(Configure.REFUND_API, Configure.mchID,requestXML); Map map = XMLUtil.doXMLParse(resXml); String result_code =(String)map.get("result_code"); String err_code_des=(String)map.get("err_code_des"); String refund_id=(String)map.get("refund_id"); OrderPayRefundLogFace orderPayRefundLogFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderPayRefundLogFace.class); orderPayRefundLogFace.saveOrderRefundLog(transaction_id, "微信", parameters.toString()+resXml, ""); if("SUCCESS".equals(result_code)) { userAfterSaleFace.flushOrderStateSequence(transaction_id,refund_id); userOrderFace.saveBatchNoSingle(orderno, serviceOrderno); //保存退款批次号 response.sendRedirect("/IdoManage/UserOtoOrderAction!queryUserOrder.action"); } else{ out.println(err_code_des); } } catch(Exception err) { err.printStackTrace(); try { OrderPayRefundLogFace orderPayRefundLogFace=EnvironmentBean.getInstance().getBeanByBeanClass(OrderPayRefundLogFace.class); orderPayRefundLogFace.saveOrderRefundLog(transaction_id, "微信","", ExceptionOut.writeException(err)); } catch(Exception error) { error.printStackTrace(); } }%>