前些日子做的微信扫码支付,现在都有点忘了怎么做的了,赶紧记录一下。。
首先先看比较好的案例,帮了我好多好多,太感谢无私奉献的人们了,我选择的模式二开发
一、场景:公司需要在网站上进行微信支付。
二、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";
}
还有各种工具类:HttpUtil
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("
");
}
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{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; 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();
}
}
%>