当前位置:网站首页>Yygh-10-wechat payment
Yygh-10-wechat payment
2022-07-02 11:52:00 【What about Xiao Zhao】
Introduction to wechat payment
1. Payment application of wechat payment
Wechat code scanning payment refers to the payment QR code generated by the merchant system according to the wechat payment agreement , Wechat for users “ scan ” Mode of payment completion . This mode is applicable to PC Website Payment 、 Unit or order payment in physical stores 、 Media advertising payment and other scenarios .
Application steps :( understand )
First step : Official account number ( Type must be : Service number )
Please select the following subject registration according to the type of business license : Individual businesses | Enterprises / company | The government | The media | Other types .
The second step : Official account number
Only after the official account is certified can WeChat apply for payment , Certification fee :300 element / year .
The third step : Submit information and apply for wechat payment
Log on to the public platform , Click on the menu on the left 【 Wechat payment 】, Start filling in the information and wait for the review , The audit time is 1-5 Within 5 working days .
Step four : Account opened successfully , Log in to the merchant platform for verification
After the data is approved , Please login the contact email to check the merchant number and password , And log in to the merchant platform to fill in the amount of small amount of TenPay reserve , Complete account verification .
Step five : Sign the agreement online
This agreement is an online electronic agreement , The transaction and capital settlement can only be carried out after signing , It will take effect immediately after signing .
2. Developing documents
The overall idea of wechat payment interface call :
Press API Required assembly parameters , With XML Mode sending (POST) To wechat payment interface (URL), Wechat payment interface is also based on XML The way to respond . Based on the returned results ( Including payment URL) Generate QR code or judge order status .
Online wechat payment development document :
https://pay.weixin.qq.com/wiki/doc/api/index.html
appid: Wechat public account or open platform APP Unique identification of
mch_id: Merchant number ( In the configuration file partner)
partnerkey: Merchant key
sign: digital signature , An encrypted message generated according to the key officially provided by wechat and a set of algorithms , Just to ensure the security of the transaction
3. Wechat payment SDK
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
We mainly use wechat payment SDK The following functions of :
1. Get random string
WXPayUtil.*generateNonceStr()
2.MAP Convert to XML character string ( Automatically add signatures )
WXPayUtil.*generateSignedXml*(param, partnerkey)
3.XML String conversion to MAP
WXPayUtil.*xmlToMap*(result)
Wechat payment development
Display of QR code
Let's analyze the payment process
1. The user clicks pay at the front desk , The front end sends the order number to be paid to the back end
2.MVC Get this order number , Query the corresponding order according to the order number , utilize https The client sends a request to the wechat background
3. The wechat background request sent back the QR code , Display at front end
service
// Generate qr code
@Override
public Map createNative(Long orderId) {
try {
// Try first at redis Get data in
Map payMap = (Map) redisTemplate.opsForValue().get(orderId.toString());
if (payMap != null) {
return payMap;
}
//1. according to orderId Get order information
OrderInfo orderInfo = orderService.getById(orderId);
//2. Add information to the payment record table
paymentService.savePaymentInfo(orderInfo, PaymentTypeEnum.WEIXIN.getStatus());
//3. Set parameters , Call the interface of wechat to generate QR code
// Convert parameters to xml Format , Use merchant key To encrypt
Map paramMap = getMap(orderInfo);
//4. call HttpClient
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
// Set parameters
client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
client.setHttps(true);
client.post();
//5. Return relevant data
String xml = client.getContent();
// convert to map aggregate
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、 Encapsulate the return result set
Map map = new HashMap<>();
map.put("orderId", orderId);
map.put("totalFee", orderInfo.getAmount());
map.put("resultCode", resultMap.get("result_code"));
map.put("codeUrl", resultMap.get("code_url")); // QR code address
if (null != resultMap.get("result_code")) {
// Wechat payment QR code 2 Hours expired , We can take 2 Hour unpaid cancellation order
redisTemplate.opsForValue().set(orderId.toString(), map, 1000, TimeUnit.MINUTES);
}
return map;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
controller
// Generate QR code of wechat payment scanning
@GetMapping("/createNative/{orderId}")
public Result createNative(@PathVariable Long orderId) {
log.info(" Start creating QR code " + orderId);
Map aNative = weixinService.createNative(orderId);
return Result.ok(aNative);
}
Tool class
@Component
public class ConstantPropertiesUtils implements InitializingBean {
@Value("${weixin.appid}")
private String appid;
@Value("${weixin.partner}")
private String partner;
@Value("${weixin.partnerkey}")
private String partnerkey;
public static String APPID;
public static String PARTNER;
public static String PARTNERKEY;
@Override
public void afterPropertiesSet() throws Exception {
APPID = appid;
PARTNER = partner;
PARTNERKEY = partnerkey;
}
}
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** * http Requesting client */
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
private boolean isCert = false;
// Certificate password Wechat merchant No (mch_id)
private String certPassword;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public boolean isCert() {
return isCert;
}
public void setCert(boolean cert) {
isCert = cert;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public String getCertPassword() {
return certPassword;
}
public void setCertPassword(String certPassword) {
this.certPassword = certPassword;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/** * set http post,put param */
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // Parameters
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // Set parameters
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
if(isCert) {
FileInputStream inputStream = new FileInputStream(new File(ConstantPropertiesUtils.CERT));
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] partnerId2charArray = certPassword.toCharArray();
keystore.load(inputStream, partnerId2charArray);
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
SSLConnectionSocketFactory sslsf =
new SSLConnectionSocketFactory(sslContext,
new String[] {
"TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
} else {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// Trust all
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
}
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// Response content
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
front end
api/weixin.js
// Query order status
queryPayStatus(orderId) {
return request({
url: `${
weixin_api_name}/queryPayStatus/${
orderId}`,
method: 'get'
})
},
// Generate QR code of wechat payment
createNative(orderId) {
return request({
url: `${
weixin_api_name}/createNative/${
orderId}`,
method: `get`,
})
},
pages/order/show.vue
pay() {
this.dialogPayVisible = true
weixinApi.createNative(this.orderId).then(response => {
this.payObj = response.data
if(this.payObj.codeUrl === '') {
this.dialogPayVisible = false
this.$message.error(" Payment error ")
} else {
this.timer = setInterval(() => {
this.queryPayStatus(this.orderId)
}, 3000);
}
})
},
queryPayStatus(orderId) {
weixinApi.queryPayStatus(orderId).then(response => {
if (response.message === ' In the payment ') {
return
}
clearInterval(this.timer);
window.location.reload()
})
},
closeDialog() {
if(this.timer) {
clearInterval(this.timer);
}
In this way, we can see the QR code to be used for payment on the front end , When we choose to pay, we will get the data back in the wechat background
Monitor transaction status
Someone might have noticed
this.timer = setInterval(() => {
this.queryPayStatus(this.orderId)
}, 3000);
I have a set of such code here
This is every 3s Query transaction status once , If the transaction is successful, jump directly , This is what you do backstage
controller
// Query payment status
@GetMapping("/queryPayStatus/{orderId}")
public Result queryPayStatus(@PathVariable Long orderId) {
log.info(" Query payment order status ");
// Call wechat interface to realize payment status query
Map<String, String> resultMap = weixinService.queryPayStatus(orderId);
// Judge
if (resultMap == null) {
return Result.fail().message(" Payment error ");
}
if ("SUCCESS".equals(resultMap.get("trade_state"))) {
// Successful payment , Update order status
String tradeNo = resultMap.get("out_trade_no");
paymentService.paySuccess(tradeNo,resultMap);
return Result.ok().message(" Successful payment ");
}
return Result.ok().message(" In the payment ");
}
WeixinServiceImpl
@Override
public Map<String, String> queryPayStatus(Long orderId) {
try {
//1. according to orderId Get order information
OrderInfo orderInfo = orderService.getById(orderId);
//2. Encapsulate submission parameters
Map paramMap = new HashMap();
paramMap.put("appid", ConstantPropertiesUtils.APPID);
paramMap.put("mch_id", ConstantPropertiesUtils.PARTNER);
paramMap.put("out_trade_no", orderInfo.getOutTradeNo());
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
//3. Set the request content
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
client.setXmlParam(WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY));
client.setHttps(true);
client.post();
//3、 Return third-party data , Turn into Map
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
//4、 return
return resultMap;
} catch (Exception e) {
return null;
}
}
PaymentServiceImpl
// Update order status
@Override
public void paySuccess(String tradeNo, Map<String, String> resultMap) {
//1. Get the payment record according to the order number
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("out_trade_no", tradeNo);
queryWrapper.eq("payment_type", PaymentTypeEnum.WEIXIN.getStatus());
PaymentInfo paymentInfo = baseMapper.selectOne(queryWrapper);
//2. Update payment information
paymentInfo.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
paymentInfo.setCallbackTime(new Date());
paymentInfo.setTradeNo(resultMap.get("transaction_id"));
paymentInfo.setCallbackContent(resultMap.toString());
baseMapper.updateById(paymentInfo);
//3. Get the order information according to the order number
log.info(String.valueOf(paymentInfo.getOrderId()));
OrderInfo orderInfo = orderService.getById(paymentInfo.getOrderId());
orderInfo.setOrderStatus(OrderStatusEnum.PAID.getStatus());
//4. Update order information
orderService.updateById(orderInfo);
//5. Call the hospital interface , Update payment information
hospApi(orderInfo);
}
/** * Get payment records * * @param orderId * @param paymentType * @return */
@Override
public PaymentInfo getPaymentInfo(Long orderId, Integer paymentType) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("order_id", orderId);
queryWrapper.eq("payment_type", paymentType);
return baseMapper.selectOne(queryWrapper);
}
private void hospApi(OrderInfo orderInfo) {
SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());
if (null == signInfoVo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
Map<String, Object> reqMap = new HashMap<>();
reqMap.put("hoscode", orderInfo.getHoscode());
reqMap.put("hosRecordId", orderInfo.getHosRecordId());
reqMap.put("timestamp", HttpRequestHelper.getTimestamp());
String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());
reqMap.put("sign", sign);
JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl() + "/order/updatePayStatus");
if (result.getInteger("code") != 200) {
throw new YyghException(result.getString("message"), ResultCodeEnum.FAIL.getCode());
}
}
Wechat refund
Wechat refund process :
1. The order for refund came from the front page id
2. Backstage according to this id Get the corresponding order , Save a copy of the order information in the cancellation form , The status is refunding
3. Send a request to the wechat background , Get a refund if successful , Update order status ,
4. utilize rabbitmq
Back end
@Override
public Boolean cancelOrder(Long orderId) {
//1. According to the order id Get order information
OrderInfo orderInfo = orderService.getById(orderId);
//2. Decide whether to cancel
DateTime quitTime = new DateTime(orderInfo.getQuitTime());
// Check time , Compare the last time with the present
/*if (quitTime.isBeforeNow()) { throw new YyghException(ResultCodeEnum.CANCEL_ORDER_NO); }*/
//3. Call the hospital interface to cancel the appointment
SignInfoVo signInfoVo = hospitalFeignClient.getSignInfoVo(orderInfo.getHoscode());
if (null == signInfoVo) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
}
Map<String, Object> reqMap = new HashMap<>();
reqMap.put("hoscode", orderInfo.getHoscode());
reqMap.put("hosRecordId", orderInfo.getHosRecordId());
reqMap.put("timestamp", HttpRequestHelper.getTimestamp());
String sign = HttpRequestHelper.getSign(reqMap, signInfoVo.getSignKey());
reqMap.put("sign", sign);
JSONObject result = HttpRequestHelper.sendRequest(reqMap, signInfoVo.getApiUrl() + "/order/updateCancelStatus");
// Return data according to the hospital interface
if (result.getInteger("code") != 200) {
throw new YyghException(ResultCodeEnum.PARAM_ERROR);
} else {
// Judge whether the current order has been paid
if (orderInfo.getOrderStatus().intValue() == OrderStatusEnum.PAID.getStatus().intValue()) {
Boolean refund = this.refund(orderId);
if (!refund) {
throw new YyghException(ResultCodeEnum.CANCEL_ORDER_FAIL);
}
// Update order status
orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
orderService.updateById(orderInfo);
// The remaining quantity +1
// send out mq Number of information update appointments We use the same mq Information , Do not set the number of bookable and remaining bookings , The number of reservations available at the receiving end is reduced 1 that will do
rabbitMq(orderInfo);
}
return true;
}
}
private void rabbitMq(OrderInfo orderInfo) {
OrderMqVo orderMqVo = new OrderMqVo();
orderMqVo.setScheduleId(orderInfo.getScheduleId());
// Text message prompt
MsmVo msmVo = new MsmVo();
msmVo.setPhone(orderInfo.getPatientPhone());
msmVo.setTemplateCode("SMS_194640722");
String reserveDate = new DateTime(orderInfo.getReserveDate()).toString("yyyy-MM-dd") + (orderInfo.getReserveTime()==0 ? " In the morning ": " Afternoon ");
Map<String,Object> param = new HashMap<String,Object>(){
{
put("title", orderInfo.getHosname()+"|"+ orderInfo.getDepname()+"|"+ orderInfo.getTitle());
put("reserveDate", reserveDate);
put("name", orderInfo.getPatientName());
}};
msmVo.setParam(param);
orderMqVo.setMsmVo(msmVo);
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);
}
front end
// cancel reservation
cancelOrder() {
this.$confirm(' Are you sure to cancel the appointment ?', ' Tips ', {
confirmButtonText: ' determine ',
cancelButtonText: ' Cancel ',
type: 'warning'
}).then(() => {
// promise
// Click ok , The remote invocation
return weixinApi.cancelOrder(this.orderId)
}).then((response) => {
this.$message.success(' Cancellation successful ')
this.init()
}).catch(() => {
this.$message.info(' The appointment has been canceled ')
})
},
边栏推荐
- 2022年遭“挤爆”的三款透明LED显示屏
- How to Create a Beautiful Plots in R with Summary Statistics Labels
- MySQL stored procedure cursor traversal result set
- Wechat applet uses Baidu API to achieve plant recognition
- Dynamic memory (advanced 4)
- Principle of scalable contract delegatecall
- Introduction to interface debugging tools
- BEAUTIFUL GGPLOT VENN DIAGRAM WITH R
- php 根据经纬度查询距离
- 念念不忘,必有回响 | 悬镜诚邀您参与OpenSCA用户有奖调研
猜你喜欢
What is the relationship between digital transformation of manufacturing industry and lean production
由粒子加速器产生的反中子形成的白洞
HOW TO CREATE A BEAUTIFUL INTERACTIVE HEATMAP IN R
Tdsql | difficult employment? Tencent cloud database micro authentication to help you
Three transparent LED displays that were "crowded" in 2022
6. Introduce you to LED soft film screen. LED soft film screen size | price | installation | application
A white hole formed by antineutrons produced by particle accelerators
在连接mysql数据库的时候一直报错
The position of the first underline selected by the vant tabs component is abnormal
Mish-撼动深度学习ReLU激活函数的新继任者
随机推荐
Beautiful and intelligent, Haval H6 supreme+ makes Yuanxiao travel safer
Esp32 audio frame esp-adf add key peripheral process code tracking
php 根据经纬度查询距离
QT meter custom control
Cluster Analysis in R Simplified and Enhanced
由粒子加速器产生的反中子形成的白洞
to_ Bytes and from_ Bytes simple example
6. Introduce you to LED soft film screen. LED soft film screen size | price | installation | application
GGHIGHLIGHT: EASY WAY TO HIGHLIGHT A GGPLOT IN R
qt 仪表自定义控件
YYGH-BUG-05
PYQT5+openCV项目实战:微循环仪图片、视频记录和人工对比软件(附源码)
The computer screen is black for no reason, and the brightness cannot be adjusted.
Dynamic memory (advanced 4)
CTF record
Mmrotate rotation target detection framework usage record
HOW TO ADD P-VALUES TO GGPLOT FACETS
文件操作(详解!)
预言机链上链下调研
Writing contract test cases based on hardhat