E企盈营销工具技术服务商 热线:4006-838-530

JAVA开发(后端):微信小程序API调用详细分析及步骤

E企盈直播平台营销卖货系统

关键词:微信登录、统一下单(支付)、统一下单通知(回调)、统一下单查询、企业付款至零钱、支付查询、获取ACCESS_Token、获取小程序二维码 因为做项目涉及到微信这些接口的调用,尽管看了很多博客,比对了官方文档,仍还是踩了很多很多的坑,这里做一个记录及分享,提醒自己,帮助他人。文章如果有讲的不对得地方,欢迎指正。 首先根据官方文档分析流程,工具类见最后:一、登录官方时序图如下:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html图里其实说的很清楚了,清理下流程:1.前端调用wx.login()获取code值2.前端通过调用wx.getUserInfo获取iv、rawData、signature、encryptedData等加密数据,传递给后端3.服务器通过code请求api换回session_key和openid4.服务器通过前端给的rawData 加获取的session_key使用sha1加密,计算出signature15.比对前端传的signature和自己算出来的signature1是否一致(防止数据不一致)6.用AES算法解密encryptedData里的敏感数据7.拿着敏感数据后做自己的逻辑8.通知前端登陆成功 ** 这里如果你只是想拿到用户的openid,则直接1,3就可以做到了。如下: public WeChatUserInfo loginSimple(String code) throws Exception {    String url = new StringBuilder().append(WeChatAPIInfo.loginUrl)            .append(“?appid=”+ WechatInfo.appid)            .append(“&secret=”+WechatInfo.SECRET)            .append(“&js_code=”+code)            .append(“&grant_type=authorization_code”)            .toString();    String result = HttpClientHelper.doGet(url,null);    if(result == null ) {//请求失败        throw new UnExceptedException(“获取会话失败”);    }    JSONObject jsonObj = JSON.parseObject(result);    String openId = jsonObj.getString(“openid”);    WeChatUserInfo weUser = new WeChatUserInfo();    weUser.setOpenId(openId);    return weUser;} /** * 登录并验证:验证数据完整性 * @param req * @return */public WeChatUserInfo loginAndSign(WeChatAppLoginReq req) throws Exception {    //获取 session_key 和 openId    String url = new StringBuilder().append(WeChatAPIInfo.loginUrl)            .append(“?appid=”+ WechatInfo.appid)            .append(“&secret=”+WechatInfo.SECRET)            .append(“&js_code=”+req.getCode())            .append(“&grant_type=authorization_code”)            .toString();    String result = HttpClientHelper.doGet(url,null);    if(result == null ) {//请求失败        throw new UnExceptedException(“获取会话失败”);    }    JSONObject jsonObj = JSON.parseObject(result);    String sessionKey = jsonObj.getString(“session_key”);    String str = req.getRawData()+sessionKey;    String signature = Algorithm.useSHA1(str);//用SHA-1算法计算签名    if(!signature.equals(req.getSignature())){        logger.info(” req signature=”+req.getSignature()+”t”+” java signature=”+signature);        throw new CheckSignatureFailException(“签名无法解析,或被篡改,无法登录”);    }    byte[] resultByte = null;    try {//解密敏感数据        resultByte = WeChatUtil.decrypt(Base64.decodeBase64(req.getEncryptedData()),                                        Base64.decodeBase64(sessionKey),                                        Base64.decodeBase64(req.getIv()));    } catch (Exception e) {        throw new DecryptFailedException(“数据无法解析!”);    }    if( null != resultByte && resultByte.length > 0){        try {            String userInfoStr = new String(resultByte, “UTF-8”);            WeChatUserInfo weUser = JSON.parseObject(userInfoStr,WeChatUserInfo.class);            return weUser;        } catch (UnsupportedEncodingException e){            logger.error(“对象转换错误”,e);        }    }    return null;} 二、⑴统一下单官方api: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1 同样清理下流程:1.计算signature:把这个文档中提及的必填参数及你需要的通过字典顺序连接(字典顺序就是你查字典时,单词的顺序),然后在最后拼接&key=商户key,然后用MD5计算signature,微信服务器会用这个signature及自己生成的作比对,防止数据被篡改。2.把你请求的参数转换为xml格式:腾讯接口采用的xml通讯,这个是他要求的格式,没办法,老老实实转吧。内容就是你上面请求的参数+你刚生成的signature,signature腾讯服务器要用来比对的。3.发起请求,获取prepay_id:这里状态真的炒鸡多的,不过你怎么处理就看自己需要了。4.返回前段调用支付接口需要的参数,并根据这些参数生成一个新的signature,然后返回给前端,这里的signature是下一次请求腾讯服务器时的签名,和第一个一个作用,一次请求一个。5.前端拿着返回的参数,发起wx.requestPayment(Object object)6.微信服务器会进行回调,回调地址是前面请求参数的notify_url,用来通知你支付成功了,然后你可以做相应的逻辑操作,然后告诉微信服务器你知道了,不然他会通知很多次(9次)。7.支付成功,前端收到通知,继续其他逻辑。/** * 统一下单 * @param orderParams * @param resultParse * @return * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException */public FlyResponse pay(CreateOrderParams orderParams, WeChatResultParseAbstract resultParse)        throws UnsupportedEncodingException, NoSuchAlgorithmException {    //解析参数    String  urlParam = WeChatUtil.concatOrderParams(orderParams);//参数按字典顺序连接起来    String sign = WeChatUtil.getSign(urlParam);//MD5加密形成签名sign,官方文档固定格式    orderParams.setSign(sign);//将生成的签名放入    String xmlStr = WeChatUtil.transToXML(orderParams);//转为xml    logger.info(“t微信下单参数转换为xml:”+xmlStr);    resultParse.setUrl(WeChatAPIInfo.Create_Order_Prefix_Url);    resultParse.setXmlStr(xmlStr);    resultParse.setApiDesc(“<< 统一下单 >>”);    return resultParse.ResultParse();} /** * @ClassName: WeChatResultParseAbstract * @Description:    结果解析抽象类 * @Version: 1.0 */public abstract class WeChatResultParseAbstract {    private static Logger logger = LoggerFactory.getLogger(WeChatResultParseAbstract.class);    /**     * 调用api的描述,如:统一下单     */    private String apiDesc;    /**     * 调用api的url     */    private String url;    /**     * 调用APi需要的xml格式参数     */    private String xmlStr;    public WeChatResultParseAbstract(String apiDesc, String url, String xmlStr) {        this.apiDesc = apiDesc;        this.url = url;        this.xmlStr = xmlStr;    }    public WeChatResultParseAbstract(String apiDesc, String xmlStr) {        this.apiDesc = apiDesc;        this.xmlStr = xmlStr;    }    public WeChatResultParseAbstract() {    }    public FlyResponse ResultParse(){        FlyResponse flyResponse = null;        RestTemplate template = new RestTemplate();        template.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));        ResponseEntity<String> resp = template.postForEntity(url, xmlStr, String.class);        if(resp == null || resp.getStatusCode() != HttpStatus.OK) {            throw new UnExceptedException(“连接通信失败”);        }        Map<String,String> map = null;        try{            map = WeChatUtil.transXMLStrToMap(resp.getBody());        }catch (ParserConfigurationException | IOException | SAXException e) {            logger.error(apiDesc+”xml解析异常:”+e.getMessage()+””);            return FlyResponse.Fail(501,apiDesc+”失败”,null,apiDesc+”xml解析异常!”);        }        if (“SUCCESS”.equals(map.get(“return_code”))) {            if(“SUCCESS”.equals(map.get(“result_code”))){                flyResponse = onSuccess(map);            }else{                flyResponse = onFail(map);            }        }else{            flyResponse = onLinkFail(map);        }        return flyResponse;    }    /**     * 响应成功,业务状态成功后要做的业务逻辑     * @param resultMap     * @return     */    protected abstract FlyResponse onSuccess(Map<String,String> resultMap);    /**     * 业务失败,业务码失败后的逻辑     * @param resultMap     * @return     */    protected abstract FlyResponse onFail(Map<String,String> resultMap);    /**     * 响应失败,业务码失败后的逻辑     * @param resultMap     * @return     */    protected FlyResponse onLinkFail(Map<String,String> resultMap){        return FlyResponse.Fail(505,”通信失败”,resultMap,”通信失败”);    } ⑵下单回调官方api: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8 流程:1.接收微信服务器发送的数据,xml格式2.根据响应结果,完成自己的业务逻辑3.通知微信服务器接收到通知  /** * 支付回调 * * @param request * @param response * @return */public void payback(HttpServletRequest request, HttpServletResponse response) throws Exception {    logger.info(“————–<><><><>开始回调<><><>———-“);    BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));    String line = null;    StringBuilder sb = new StringBuilder();    while((line = br.readLine()) != null){        sb.append(line);    }    br.close();    String notityXml = sb.toString();    String resXml = “”;    Map<String,String> map = WeChatUtil.transXMLStrToMap(notityXml);    String returnCode = (String) map.get(“return_code”);    if(“SUCCESS”.equals(returnCode)){        SortedMap<String,String> payInfo = new TreeMap<>(map);        String sign = WeChatUtil.getSignFromMap(payInfo);        if(sign.equals(map.get(“sign”))){//比对签名防止数据篡改           //这里写自己的逻辑            }            //通知微信服务器已经支付成功            resXml = “<xml>” + “<return_code><![CDATA[SUCCESS]]></return_code>”                    + “<return_msg><![CDATA[OK]]></return_msg>” + “</xml> “;            logger.info(“回调成功!!!!!!!”);        } else {            resXml = “<xml>” + “<return_code><![CDATA[FAIL]]></return_code>”                    + “<return_msg><![CDATA[签名不一致]]></return_msg>” + “</xml> “;            logger.warn(“t微信支付回调失败!签名不一致t”);        }    }else{        resXml = “<xml>” + “<return_code><![CDATA[FAIL]]></return_code>”                + “<return_msg><![CDATA[报文为空]]></return_msg>” + “</xml> “;        logger.warn(“回调失败!!!!!!!”);    }     BufferedOutputStream out = new BufferedOutputStream(            response.getOutputStream());    out.write(resXml.getBytes());    out.flush();    out.close();} ⑶下单查询官方api: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2 流程:1.根据请求参数生成signature2.请求参数转为xml3.发起请求,判断结果  /** * 查询订单情况 * @param orderNo * @return */public FlyResponse checkOrder(String orderNo) throws UnsupportedEncodingException,NoSuchAlgorithmException {    CheckOrderVO check = WechatVOFactory.createCheck(orderNo);    String sign = WeChatUtil.getSign(WeChatUtil.concatOrderParams(check));//参数按字典顺序连接起来    check.setSign(sign);    String xml = WeChatUtil.transToXML(check);    //调用统计下单接口验证    WeChatResultParseAbstract reParse = new WeChatResultParseAbstract(“查询订单”,Order_check_Url,xml) {        @Override        protected FlyResponse onSuccess(Map<String, String> resultMap) {            if(“SUCCESS”.equalsIgnoreCase(resultMap.get(“trade_state”))){                return FlyResponse.Success(200,”支付成功”,resultMap);            }else{                return FlyResponse.Fail(501,”支付失败”,resultMap,”支付失败”);            }        }        @Override        protected FlyResponse onFail(Map<String, String> resultMap) {            return FlyResponse.Fail(500,”【查询订单】失败”,resultMap,”微信API调用Fail”);        }    };    return reParse.ResultParse();}三、企业付款至零钱官方api: https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 企业付款有支付到零钱和银行卡,这里我使用的是支付到零钱。签名什么的大同小异,直接上代码。/** * 企业付款至用户零钱 * @param request * @param fee * @param openid * @param payDesc * @return * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException */public synchronized FlyResponse CompanyPayToUser(HttpServletRequest request,String fee, String openid,String payDesc)        throws Exception {    FlyResponse flyResponse = null;    final String orderno = createAnTransferOrderNum();//创建一个唯一的订单号,这个看自己的情况实现    CompanyPayVO payVO = WechatVOFactory.createCompanyPayVO(request, orderno, openid, fee, payDesc);    String sign = WeChatUtil.getSign(WeChatUtil.concatOrderParams(payVO));    payVO.setSign(sign);    String xmlStr = WeChatUtil.transToXML(payVO);    String result = WeChatUtil.HttpsPost(WeChatAPIInfo.Company_Transfer_Url,xmlStr);    if(result != null && result.length()>0 ){        Map<String, String> resultMap = WeChatUtil.transXMLStrToMap(result);        if (“SUCCESS”.equals(resultMap.get(“return_code”))) {            if(“SUCCESS”.equals(resultMap.get(“result_code”))){                flyResponse = FlyResponse.Success(200,”提现成功”,resultMap);            }else{                flyResponse = FlyResponse.Fail(500,”提现失败”,resultMap,”提现失败”);            }        }else{            if(TransgerErrorCode.isUnsureState(resultMap.get(“err_code”))){//不确定状态,再查一次                try {                    flyResponse = checkTransfer(orderno);                } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {                    e.printStackTrace();//已经解析过                }            }else{                flyResponse = FlyResponse.Fail(500,”提现失败”,resultMap,”提现失败”);            }        }    }else{        flyResponse = FlyResponse.Fail(505,”通信失败”,null,”通信失败”);    }    if(flyResponse.getCode() == 200){//成功       //写自己要的逻辑    }else if(flyResponse.getCode() == 201){//处理中        //写自己要的逻辑    }    logger.info(“返回结果:”+JSON.toJSON(flyResponse));    return flyResponse;}/** * 查询企业付款情况 * @param orderNo * @return * @throws UnsupportedEncodingException * @throws NoSuchAlgorithmException */public synchronized FlyResponse checkTransfer(String orderNo) throws Exception {    FlyResponse flyResponse = null;    TransferCheckVO check = WechatVOFactory.createTransferCheckVO(orderNo);    String sign = WeChatUtil.getSign(WeChatUtil.concatOrderParams(check));    check.setSign(sign);    String xmlStr = WeChatUtil.transToXML(check);    String result = WeChatUtil.HttpsPost(WeChatAPIInfo.Transfer_Check_Url,xmlStr);    if(result != null && result.length()>0 ){        Map<String, String> resultMap = WeChatUtil.transXMLStrToMap(result);        if (“SUCCESS”.equals(resultMap.get(“return_code”))) {            if(“SUCCESS”.equalsIgnoreCase(resultMap.get(“status”))){                return FlyResponse.Success(200,”提现成功”,resultMap);            }            if(“PROCESSING”.equalsIgnoreCase(resultMap.get(“status”))){//处理中                return FlyResponse.Success(201,”提现处理中”,resultMap);            }else{                return FlyResponse.Fail(501,”提现失败”,resultMap,”提现失败”);            }        }else{            return FlyResponse.Fail(500,”【提现查询】失败”,resultMap,”微信API调用Fail”);        }    }else{        flyResponse = FlyResponse.Fail(505,”提现查询通信失败”,null,”通信失败”);    }    if(flyResponse.getCode() == 200){        //查询支付成功了,写自己逻辑    }    return flyResponse;} 四、获取小程序二维码小程序二维码获取之前得获取accesstoken,然后调用接口获取二维码,我是保存在项目本地,然后返回地址供请求访问,代码如下: /** * 获取小程序二维码 * @param qrCode * @param imageName * @return * @throws Exception */public  String getQRCode(QRCodeVO qrCode,String imageName) throws Exception {    imageName += “.jpg”;    String url = new StringBuilder().append(WeChatAPIInfo.QRcode)            .append(“?access_token=”+getAccessToken().getAccess_token())            .toString();    //获取web目录    String rootpath = ContextLoader.getCurrentWebApplicationContext().getServletContext().getRealPath(“/”);    Path path = Paths.get(rootpath,WechatInfo.QRImgRootAddress,imageName);    File file = path.toFile();    File result = HttpClientHelper.doPostToFileSSL_unSafe(url,JSON.toJSONString(qrCode),file);    return WechatInfo.SourceUrl +imageName;} /** *获取全局Access_Token验证凭证 * @return */public AccessResult getAccessToken() throws Exception {       String url = new StringBuilder().append(WeChatAPIInfo.ACCESS_TOKEN)                .append(“&appid=”+ WechatInfo.appid)                .append(“&secret=”+WechatInfo.SECRET)                .toString();        String str = HttpClientHelper.doGet(url,null);        if(str == null ) {//请求失败            throw new UnExceptedException(“获取会话失败”);        }        AccessResult result = JSON.parseObject(str,AccessResult.class);        if(result.getAccess_token() == null){            throw new UnExceptedException(“获取accessToken失败:”+result.getErrcode()+”;”+result.getErrmsg());        }        if(result.getErrcode()==null){//没有错误码,成功,替换新的accesstoken            //这里可以把accesstoken保存下来,官方说有2小时有效期,我是采用的redis,怎么实现看个人喜好了        }        return result;} /** * AccessToken结果内部类 */public static class AccessResult{    private String access_token;    private String expires_in;    private String errcode;    private String errmsg;//get、set、、、、} 嗯。。。基本是这样,接下来是自建的工具类:*ps: 因为参考过很多人的代码,也修改过很多次,但是 有些地方并没有去调整。比如http相关的工具类的东西,可能有些乱。不过因为可以用,而且很懒,所以就那样吧先。。。。import com.thoughtworks.xstream.XStream;import com.thoughtworks.xstream.XStreamException;import org.apache.http.HttpEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.ssl.SSLContexts;import org.apache.http.util.EntityUtils;import org.apache.log4j.Logger;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.springframework.util.StringUtils;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import javax.net.ssl.SSLContext;import javax.servlet.http.HttpServletRequest;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import java.io.*;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.security.*;import java.util.*;/** * @ClassName: WeChatUtil * @Description:    微信工具类 * @Author: totors * @Version: 1.0 */public class WeChatUtil {    private static Logger logger = Logger.getLogger(WeChatUtil.class);    public static boolean initialized = false;    /**     * 获取一个32位的随机字符串     *     * @return     */    public static String getOneRandomString() {        String base = “abcdefghijklmnopqrstuvwxyz0123456789”;        Random random = new Random();        StringBuilder sb = new StringBuilder();        for (int i = 0; i < 31; i++) {            int number = random.nextInt(31);            sb.append(base.charAt(number));        }        return sb.toString();    }    /**     * 获取真实的ip地址     *     * @param request     * @return     */    public static String getIpAddr(HttpServletRequest request) {        Enumeration<String> headers = request.getHeaderNames();        String ip = request.getHeader(“X-Forwarded-For”);        if (!StringUtils.isEmpty(ip) && !”unKnown”.equalsIgnoreCase(ip)) {            int index = ip.indexOf(“,”);            if (index != -1) {                return ip.substring(0, index);            } else {                return ip;            }        }        ip = request.getHeader(“X-Real-IP”);        if (!StringUtils.isEmpty(ip) && !”unKnown”.equalsIgnoreCase(ip)) {            return ip;        }        return request.getRemoteAddr();    }    /**     * 连接订单参数,空则忽略,连接符&     * 使用详解:符合条件的参数按字段名称由小到大(字典顺序)排序,并连接     *     * @param createOrderParams     * @return     */    public static String concatOrderParams(Object createOrderParams) throws UnExceptedException {        TreeMap<String, String> tree = new TreeMap<>(); //用于排序        Class clazz = createOrderParams.getClass();        Field[] fields = clazz.getDeclaredFields();        //查找字段        for (Field field : fields) {            field.setAccessible(true);            String fieldName = field.getName();            String methodName = getFiledMethodName(fieldName);            try {                Method method = clazz.getMethod(methodName);                Object value = method.invoke(createOrderParams);                if (value != null) {//不为空                    tree.put(fieldName, value.toString());                }            } catch (NoSuchMethodException e) {                logger.error(e.getMessage());            } catch (IllegalAccessException e) {                logger.error(e.getMessage());            } catch (InvocationTargetException e) {                logger.error(e.getMessage());            }        }        if (tree.size() == 0) {            throw new UnExceptedException(“No field can be linked ! “);        }        String str = linkMapKeyValue(tree, “&”);        return str.substring(1);//截取第一个&符号之后的内容    }    /**     * 从map创建签名     * @param parameters     * @return     */    public static String getSignFromMap(SortedMap<String, String> parameters){        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();            Object v = entry.getValue();            if (null != v && !””.equals(v) && !”sign”.equals(k) && !”key”.equals(k)){                sb.append(k + “=” + v + “&”);            }        }        sb.append(“key=” + WechatInfo.key);        logger.info(“t由MAP生产的字符串:”+sb.toString());        String sign = null;        try {            sign = Algorithm.MD5(sb.toString()).toUpperCase();        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {            logger.error(“MD5加密失败:”+e.getClass()+”>>>>”+e.getMessage());        }        return sign;    }    /**     * 连接字符串:     *      * 将map值连接为key = value & key = value……形式     * @param map     * @param character 连接符号,如:&     * @return     */    public static String linkMapKeyValue(TreeMap<String, String> map, String character) {        if (map == null || map.size() == 0) {            return null;        }        StringBuilder sb = new StringBuilder();        Set<String> keys = map.keySet();        Iterator<String> it = keys.iterator();        while (it.hasNext()) {            String key = it.next();            sb.append(character + key + “=” + map.get(key));        }        return sb.toString();    }    /**     * 获取字段方法名称     *     * @param fieldName     * @return     */    public static String getFiledMethodName(String fieldName) {        char firstChar = fieldName.toCharArray()[0];        return “get” + String.valueOf(firstChar).toUpperCase() + fieldName.substring(1, fieldName.length());    }    /**     * 将对象非空参数转化为XML     *     * @param obj     * @return     */    public static String transToXML(Object obj) {        //解决XStream对出现双下划线的bug//        XStream xstream = new XStream(new DomDriver(“UTF-8”, new XmlFriendlyNameCoder(“-_”, “_”)));        XStream xstream = XStreamFactory.getXStream();        xstream.alias(“xml”, obj.getClass());        return xstream.toXML(obj);    }    /**     * 将字符串格式的xml内容转化为对象     * 注意:该方法存在一个不可避免风险,即:当微信官方文档反馈字段增加或改变时,该方法将不能映射进pojo里。     *       因为本地pojo(OrderResult)可能没有做对应调整。     * @param str     * @return     */    public static OrderResult transToObject(String str) throws XStreamException {        str = str.replaceAll(“xml”,”OrderResult”);//将返回结果的<xml>标签替换为返回结果类        XStream xstream = new XStream();        xstream.alias(“OrderResult”, OrderResult.class);        OrderResult orderResult = new OrderResult();        return (OrderResult) xstream.fromXML(str,orderResult);    }    /**     * 将xml字符串解析为map集合,兼容性高     * @param xmlStr     * @return     * @throws ParserConfigurationException     */    public static Map<String,String> transXMLStrToMap(String xmlStr) throws ParserConfigurationException,            SAXException, IOException {        Map<String, String> data = new HashMap<String, String>();        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();        try(InputStream stream = new ByteArrayInputStream(xmlStr.getBytes(“UTF-8”));) {            org.w3c.dom.Document doc = documentBuilder.parse(stream);            doc.getDocumentElement().normalize();            NodeList nodeList = doc.getDocumentElement().getChildNodes();            for (int idx = 0; idx < nodeList.getLength(); ++idx) {                Node node = nodeList.item(idx);                if (node.getNodeType() == Node.ELEMENT_NODE) {                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;                    data.put(element.getNodeName(), element.getTextContent());                }            }        } catch (UnsupportedEncodingException e) {            logger.error(“解析xml结果失败!字符编码不匹配!”);            throw e;        } catch (IOException e) {            logger.error(“解析xml结果失败!无法读入流”);            throw e;        }        return data;    }    /**     * 获取签名     * @param signStr     * @return     */    public static String getSign(String signStr) throws UnsupportedEncodingException, NoSuchAlgorithmException {        return Algorithm.MD5(signStr + “&key=”+ WechatInfo.key).toUpperCase();    }    /**     * 敏感数据对称解密     * @param content   ——被加密的数据     * @param keyByte   ——加密密匙     * @param ivByte ——偏移量     * @return     * @throws InvalidAlgorithmParameterException     */    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {        initialize();        try {            Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS7Padding”);            Key sKeySpec = new SecretKeySpec(keyByte, “AES”);            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化            byte[] result = cipher.doFinal(content);            return result;        }        return null;    }    /**     * 添加算法     */    public static void initialize(){        if (initialized) return;        Security.addProvider(new BouncyCastleProvider());        initialized = true;    }    /**     * @Description 生成iv     * @Param [iv]     * @return java.security.AlgorithmParameters     **/    public static AlgorithmParameters generateIV(byte[] iv) throws Exception{        AlgorithmParameters params = AlgorithmParameters.getInstance(“AES”);        params.init(new IvParameterSpec(iv));        return params;    }    public static String HttpsPost(String url,String xmlStr) throws Exception {        KeyStore keyStore = KeyStore.getInstance(“PKCS12”);        try (FileInputStream instream = new FileInputStream(new File(WechatInfo.CERTIFICATE_ADDRESS));){            keyStore.load(instream, WechatInfo.mch_id.toCharArray());        }        // Trust own CA and all self-signed certs        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WechatInfo.mch_id.toCharArray()).build();        // Allow TLSv1 protocol only        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext);//        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{“TLSv1”}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();        HttpPost httpPost = new HttpPost(url);        httpPost.addHeader(“Connection”, “keep-alive”);        httpPost.addHeader(“Accept”, “*/*”);        httpPost.addHeader(“Content-Type”, “application/x-www-form-urlencoded; charset=UTF-8”);        httpPost.addHeader(“Host”, “api.mch.weixin.qq.com”);        httpPost.addHeader(“X-Requested-With”, “XMLHttpRequest”);        httpPost.addHeader(“Cache-Control”, “max-age=0”);//        httpPost.addHeader(“User-Agent”, “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) “);        httpPost.setEntity(new StringEntity(xmlStr, “UTF-8”));        logger.info(“执行请求” + httpPost.getRequestLine());        CloseableHttpResponse response = httpclient.execute(httpPost);        StringBuffer sbf = new StringBuffer();        try {            HttpEntity entity = response.getEntity();            if (entity != null) {                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), “UTF-8”));                String text;                while ((text = bufferedReader.readLine()) != null) {                    sbf.append(text);                }            }            EntityUtils.consume(entity);        } finally {            response.close();            httpclient.close();        }        return sbf.toString();    }}  算法工具类:public class Algorithm {    private static final char[] HEX_DIGITS = {‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’,            ‘6’, ‘7’, ‘8’, ‘9’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’};    public static String useSHA1(String str) {        if (str == null) {            return null;        }        try {            MessageDigest messageDigest = MessageDigest.getInstance(“SHA1”);            messageDigest.update(str.getBytes(“utf-8”));            String result = getFormattedText(messageDigest.digest());            return result;        } catch (Exception e) {            throw new RuntimeException(e);        }    }    private static String getFormattedText(byte[] bytes) {        int len = bytes.length;        StringBuilder buf = new StringBuilder(len * 2);        // 把密文转换成十六进制的字符串形式        for (int j = 0; j < len; j++) {            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);        }        return buf.toString();    }    /**     * MD5加密     * @param text     * @return     * @throws NoSuchAlgorithmException     * @throws UnsupportedEncodingException     */    public static String MD5(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {        return MD5.MD5Encode(text);    }}   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 resultString = null;        try {            resultString = origin;            MessageDigest md = MessageDigest.getInstance(“MD5”);            resultString = byteArrayToHexString(md.digest(resultString.getBytes(“UTF-8”)));        } catch (Exception e) {            e.printStackTrace();        }        return resultString;    }} 微信小程序及商户的配置信息,你也可以写在配置文件来引用: public interface WeChatAPIInfo {    /**     * 获取access_token     */     String ACCESS_TOKEN = “https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential”;    /**     * 登录地址     */     String loginUrl = “https://api.weixin.qq.com/sns/jscode2session”;    /**     * 统一下单url     */     String Create_Order_Prefix_Url = “https://api.mch.weixin.qq.com/pay/unifiedorder”;    /**     * 订单情况查询url     */     String Order_check_Url = “https://api.mch.weixin.qq.com/pay/orderquery”;    /**     * 企业付款到零钱     */     String Company_Transfer_Url = “https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers”;    /**     * 企业付款查询url     */     String Transfer_Check_Url = “https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo”;    /**     * 二维码url     */     String QRcode = “https://api.weixin.qq.com/wxa/getwxacodeunlimit”;    String SendTemplateMsg_Url = “https://api.we

赞(0) 打赏
未经允许不得转载:E企盈小程序开发-热线:4006-838-530 » JAVA开发(后端):微信小程序API调用详细分析及步骤
分享到: 更多 (0)
E企盈小程序直播营销卖货系统
E企盈直播平台营销卖货系统

评论 抢沙发

E企盈小程序开发

联系我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏