由于项目需求老大叫我开发“微信企业付款到零钱”的功能,这之前我做过一些微信支付的相关东西,对我而言微信封装的东西感觉比ALI难过一些。言归正传,在没有找到微信官方的API的情况下就只能借鉴之前写过的各位大佬的了,但是结合自身的水平发现有很多东西还是借鉴的。
1.开发“微信企业付款到零钱”的功能,首先需要登录微信商户-->产品中心-->查看“企业付款到零钱”是否开通
如果未开通,则需要开通。
2.仔细阅读-->企业付款到零钱API
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1 (必看)
3.证书的准备:java开发需要用到:apiclient_cert.p12证书的,在微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>证书中下载的 。
4.关于证书和参数
https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=4_3 (建议看看)
5.相关代码
@Controller
@RequestMapping("/transfer")
public class TransferController {
private static final Logger LOG = Logger.getLogger(TransferController.class);
// 获取需要发送的url地址
private static final String TRANSFERS_PAY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
// 企业付款查询
private static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
@Autowired
TokenMapper tokenMapper;
/**
* 企业向个人支付转账
*
* @param request
* @param response
* @param openid
* 用户openid
* @param callback
* @throws MyException
*/
@RequestMapping(value = "pay")
@ResponseBody
public Object transferPay(HttpServletRequest request, HttpServletResponse response, String token,BigDecimal amount) throws MyException {
LOG.info("[/transfer/pay]");
Map
这里需要着重注意这个方法
String restxml = HttpUtils.posts(TRANSFERS_PAY, XmlUtils.xmlFormat(parm, false));
方法Post进去
/**
* @description 功能描述: post https请求,服务器双向证书验证
* @param url 请求地址
* @param s 参数xml
* @return 请求失败返回null
*/
public static String posts(String url, String s) {
CloseableHttpClient httpClient = null;
HttpPost httpPost = new HttpPost(url);
String body = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClients.custom()
.setDefaultRequestConfig(REQUEST_CONFIG)
.setSSLSocketFactory(getSSLConnectionSocket())
.build();
httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
response = httpClient.execute(httpPost);
body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return body;
}
会有httpClient请求,这里是需要配置编码格式,链接超时时间,微信支付ssl证书(就是之前下载的证书)
httpClient = HttpClients.custom().setDefaultRequestConfig(REQUEST_CONFIG)
.setSSLSocketFactory(getSSLConnectionSocket())
.build();
进入配置类,这里的ClassPathResource里表示你证书的放置路径。
public class HttpUtils {
private static final String DEFAULT_CHARSET = "UTF-8";
private static final int CONNECT_TIME_OUT = 5000; //链接超时时间3秒
private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(CONNECT_TIME_OUT).build();
private static SSLContext wx_ssl_context = null; //微信支付ssl证书
static{
Resource resource = new ClassPathResource("spring/apiclient_cert.p12");
try {
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] keyPassword = "1494252162".toCharArray(); //证书密码
keystore.load(resource.getInputStream(), keyPassword);
wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我的路径(注意如果直接放在resources下面就是项目的根路径:ClassPathResource("apiclient_cert.p12")):
照理来说到这里项目就可以正常运行了,但是我在完成这些的后还遇见了另外一个错误:
[2018-04-17 19:01:06][ERROR] - caused by: org.xmlpull.v1.XmlPullParserException: resource not found: /META-INF/services/org.xmlpull.v1.XmlPullParserFactory make sure that parser implementing XmlPull API is available
org.xmlpull.v1.XmlPullParserException: caused by: org.xmlpull.v1.XmlPullParserException: resource not found: /META-INF/services/org.xmlpull.v1.XmlPullParserFactory make sure that parser implementing XmlPull API is available
at org.xmlpull.v1.XmlPullParserFactory.newInstance(XmlPullParserFactory.java:294)
at org.xmlpull.v1.XmlPullParserFactory.newInstance(XmlPullParserFactory.java:259)
at com.ejar.shop.utils.wxpay.XmlUtils.xmlParse(XmlUtils.java:73)
at com.ejar.shop.controller.front.TransferController.transferPay(TransferController.java:83)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at com.ejar.shop.utils.strideAcross.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:47)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1104)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
四月 17, 2018 7:01:06 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [shop] in context with path [/shop] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: getWriter() has already been called for this response] with root cause
java.lang.IllegalStateException: getWriter() has already been called for this response
做为一个小白刚开始确实很懵逼,网上资料也不多,就试着用deBug跑找问题出现在哪里,又在网上找相关资料,最后发现是少了一个kxml2-2.3.0.jar的包,导进去就OK了。
最后是相关API的下载链接:
https://download.csdn.net/download/qq_41187907/10355702
做为小白第一次写文章,有什么不足之处望各位多多包涵。