首先需要在微信公衆平台(注意不是微信開放平台)注冊一個賬号,并開通微信認證,微信認證一次需要300塊(太tm的貴了),并且需要送出各種資料。
稽核過後, 進入 開發-》基本配置
開發者ID,開發者密碼都需要記住後面需要用,開發者密碼需要自己設定,很多人找不到32位密鑰,這裡可以用第三方軟體生成! 百度:線上密碼生成器——選擇百度應用——随機密碼生成器。微信掃碼支付模式有兩種,第一種需要配置很多的東西,有點麻煩,第二種比較友善。是以采用第二種模式。
微信支付的開發api我是直接把他拿過來,自己研究一下,然後在改一下,裡面的檔案有點多,就不一一貼出來了。貼出來幾個重要的:
package com.github.wxpay.sdk;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class WXPayConfigImpl extends WXPayConfig{
private byte[] certData;
private static WXPayConfigImpl INSTANCE;
private WXPayConfigImpl() throws Exception{
/*String certPath = "D://CERT/common/apiclient_cert.p12";
File file = new File(certPath);
if(!file.exists()){
file.mkdirs();
}
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();*/
}
public static WXPayConfigImpl getInstance() throws Exception{
if (INSTANCE == null) {
synchronized (WXPayConfigImpl.class) {
if (INSTANCE == null) {
INSTANCE = new WXPayConfigImpl();
}
}
}
return INSTANCE;
}
public String getAppID() {
return "";//公衆賬号ID,必填
}
public String getMchID() {
return "";//商戶号,必填
}
public String getKey() {
return "";//秘鑰,必填
}
public InputStream getCertStream() {
ByteArrayInputStream certBis;
certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
public int getHttpConnectTimeoutMs() {
return ;
}
public int getHttpReadTimeoutMs() {
return ;
}
IWXPayDomain getWXPayDomain() {
return WXPayDomainSimpleImpl.instance();
}
public String getPrimaryDomain() {
return "api.mch.weixin.qq.com";
}
public String getAlternateDomain() {
return "api2.mch.weixin.qq.com";
}
@Override
public int getReportWorkerNum() {
return ;
}
@Override
public int getReportBatchSize() {
return ;
}
}
@Controller
public class WXOrderController {
@Autowired
private HttpServletRequest request;
@Autowired
private ReqProductService reqproductService;
@Autowired
private TransreqService transreqService;
@Autowired
private AddressService addressService;
@Autowired
private OrderService orderService;
private Logger log = Logger.getLogger(WXOrderController.class);
@RequestMapping("dobuyByWX")
public String dobuyByWX(Model model,HttpServletRequest request,HttpServletResponse response){
User u = (User) request.getSession().getAttribute("user");
if(u==null||DataUtil.isNullStr(u.getUserName())){
return "login";
}
String flag = request.getParameter(ITag.Flag);
Map map = null;
if("0".equals(flag)){//表示第一次生成訂單
map = orderService.generateOrder(request);
}else if("1".equals(flag)){//表示訂單之前已經生成,現在來付款
map = orderService.getOrderinfo(request);
}
if(map == null){
model.addAttribute(ITag.ReturnCode, "-1");
model.addAttribute(ITag.ErrorMessage, "該産品不存在或者已經被其他買家購買");
return "trade.page.pay";
}
Transreq transreq = (Transreq) map.get("transreq");
ReqProduct reqproduct = (ReqProduct) map.get("reqproduct");
request.setAttribute("transreq", transreq);
request.setAttribute("reqproduct", reqproduct);
DecimalFormat df = new DecimalFormat("0.00");
String amt = df.format(transreq.getAmt().doubleValue());
request.setAttribute("Amt", amt);
return "wxpay";
}
/**
* 生成訂單
* @param orderId
* @return
* @throws Exception
*/
private Map<String,String> createOrderInfo(HttpServletRequest req, Map map) throws Exception {
Transreq transreq = (Transreq) map.get("transreq");
ReqProduct reqproduct = (ReqProduct) map.get("reqproduct");
HashMap<String, String> data = new HashMap<String, String>();
WXPayConfigImpl config = WXPayConfigImpl.getInstance();
WXPay wxpay = new WXPay(config);//
data.put("body", reqproduct.getPrdName());//商品描述
data.put("out_trade_no", transreq.getSerialNo());//商戶訂單号
data.put("device_info", "");
data.put("fee_type", "CNY");//人民币
DecimalFormat dft = new DecimalFormat("0");//這裡不能帶小數,否則會報錯
String amt = dft.format(transreq.getAmt().multiply(BigDecimal.valueOf()));
data.put("total_fee", amt);//金額需要擴大100倍:1代表支付時是0.01
data.put("notify_url", "");//必輸
data.put("trade_type", "NATIVE");//JSAPI--公衆号支付、NATIVE--原生掃碼支付、APP--app支付
data.put("product_id", String.valueOf(reqproduct.getPrdId()));
data.put("nonce_str", StringUtil.makeUUID());//随機字元串
data.put("spbill_create_ip", StringUtil.getIpAddr(req));//終端IP
// data.put("sign_type", "MD5");
log.info("請求支付的請求參數:"+data);
Map<String, String> r = null;
try {
r = wxpay.unifiedOrder(data);//這是官方給的demo裡面的接口,統一下單
log.info("請求支付傳回的資料:"+r);
} catch (Exception e) {
e.printStackTrace();
}
return r;
}
@RequestMapping("createQrcode")
public void createQrcode(HttpServletRequest request,HttpServletResponse response){
log.info("微信支付生成二維碼 -- --------beg ---------------------");
Map map = null;
Map<String,String> r = null;
map = orderService.getOrderinfo(request);
//生成訂單
try {
r = createOrderInfo(request,map);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//調統一下單API
String code_url = "";
if("SUCCESS".equalsIgnoreCase(r.get("return_code"))){
code_url = r.get("code_url");
}else{
log.info("生成二維碼支付連結失敗,原因:"+r.get("return_msg"));
return;
}
if(DataUtil.isNullStr(code_url)){
log.info("生成二維碼支付連結失敗");
return;
}
log.info("生成的二維碼連結:"+code_url);
//将傳回預支付交易連結(code_url)生成二維碼圖檔
//這裡使用的是zxing
try {
int width = ;
int height = ;
String format = "png";
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
OutputStream out = null;
out = response.getOutputStream();
BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);
MatrixToImageWriter.writeToStream(bitMatrix, format, out);
out.flush();
out.close();
} catch (Exception e) {
log.info("微信支付生成二維碼失敗");
}
log.info("微信支付生成二維碼 -- --------end ---------------------");
}
@RequestMapping("wxpaynotify")
public String wxpaynotify(HttpServletRequest request,HttpServletResponse response){
String result="";//傳回給微信的處理結果
result = setXml("SUCCESS", "處理成功");
String inputLine;
String notityXml = "";
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
//微信給傳回的東西
try {
while ((inputLine = request.getReader().readLine()) != null) {
notityXml += inputLine;
}
request.getReader().close();
} catch (Exception e) {
e.printStackTrace();
result = setXml("fail","xml擷取失敗");
}
if (DataUtil.isNullStr(notityXml)) {
result = setXml("fail","xml為空");
}
log.info("微信支付異步回調傳回資料:"+notityXml);
Map<String,String> r = null;
try {
r = WXPayUtil.xmlToMap(notityXml);
} catch (Exception e1) {
log.error("xml轉化成map失敗");
}
if("SUCCESS".equalsIgnoreCase(r.get("return_code"))){
WXPayConfigImpl config = null;
try {
config = WXPayConfigImpl.getInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean flag = false;
try {
flag = WXPayUtil.isSignatureValid(r, config.getKey(),SignType.HMACSHA256);//**驗簽,不知道這裡為什麼不是MD5驗簽,官方文檔預設是MD5,微信文檔真垃圾,之前在這裡困擾了好久**
} catch (Exception e) {
log.error("微信支付異步回調驗簽出現異常");
flag = false;
}
if(flag){
log.info("微信支付異步回調驗簽成功!");
try {
log.info("微信支付異步回調進行商戶業務邏輯處理--------------beg-------------");
dologic(request,r,config);
log.info("微信支付異步回調進行商戶業務邏輯處理--------------end-------------");
} catch (Exception e) {
log.info(e.getMessage());
}
}else{
log.info("微信支付異步回調驗簽失敗!");
}
}
//傳回成功樣例
//
PrintWriter out = null;
try {
out = response.getWriter();
out.write(result);
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "wxpaysucc";
}
private void dologic(HttpServletRequest request,Map<String,String> r,WXPayConfigImpl config) throws Exception{
//公衆賬号ID
String appid = r.get("appid");
//商戶号
String mchid = r.get("mch_id");
//商戶系統訂單号
String out_trade_no = r.get("out_trade_no");
//微信支付交易号
String trade_no = r.get("transaction_id");
//金額,這裡傳回的是以分為機關的金額
String total_amount = r.get("total_fee");
if(!config.getAppID().equals(appid)){//判斷appid是否相同
throw new Exception("微信支付異步反回的appid與商戶appid不一緻,商戶邏輯處理失敗,相應的訂單号為:"+out_trade_no);
}
if(!config.getMchID().equals(mchid)){//判斷商戶号是否相同
throw new Exception("微信支付異步反回的商戶号與商戶資訊不一緻,商戶邏輯處理失敗,相應的訂單号為:"+out_trade_no);
}
Transreq transreq = transreqService.selectByPrimaryKey(out_trade_no);//購買流水
if(transreq == null){
throw new Exception("未查詢到購買流水資訊,商戶邏輯處理失敗,訂單号為:"+out_trade_no);
}
if(!IDict.REQ_STATUS.REQ_STATUS_DFK.equals(transreq.getStatus())){//判斷狀态
throw new Exception("該購買流水資訊狀态不為待付款,商戶邏輯處理失敗,訂單号為:"+out_trade_no);
}
if(transreq.getAmt().subtract(new BigDecimal(total_amount).multiply(new BigDecimal())).compareTo(new BigDecimal("0.1"))>){//判斷金額
throw new Exception("微信支付支付的金額與訂單中的金額不一緻,商戶邏輯處理失敗,訂單号為:"+out_trade_no);
};
Transreq uploadtransreq = transreqService.selectByPrimaryKey(transreq.getAssoSerial());
if(uploadtransreq == null){
throw new Exception("微信支付異步回調時未找到與訂單資訊相關的上傳商品的資訊,商戶邏輯處理失敗,訂單号為:"+out_trade_no);
}
if(!IDict.REQ_STATUS.REQ_STATUS_SUCCESS.equals(uploadtransreq.getStatus())){
throw new Exception("微信支付異步回調時找到的與訂單資訊相關的上傳商品的資訊狀态不正确,商戶邏輯處理失敗,訂單号為:"+out_trade_no);
}
try {
orderService.pay(transreq, uploadtransreq,trade_no);
} catch (Exception e) {
throw new Exception("資料更新失敗,訂單号為:"+out_trade_no);
}
return;
}
//通過xml 發給微信消息
public String setXml(String return_code, String return_msg) {
SortedMap<String, String> parameters = new TreeMap<String, String>();
parameters.put("return_code", return_code);
parameters.put("return_msg", return_msg);
return "<xml><return_code><![CDATA[" + return_code + "]]>" +
"</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
}
}
驗簽的時候容易出錯,可以線上驗簽,https://pay.weixin.qq.com/wiki/tools/signverify/
微信支付