首先需要在微信公众平台(注意不是微信开放平台)注册一个账号,并开通微信认证,微信认证一次需要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 2000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
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 1;
}
@Override
public int getReportBatchSize() {
return 2;
}
}
@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(100)));
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 = 200;
int height = 200;
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(100))).compareTo(new BigDecimal("0.1"))>0){//判断金额
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/
微信支付