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

您所在的位置:网站首页 java开发微信小程序用什么软件打开 JAVA开发(后端):微信小程序API调用详细分析及步骤

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

2024-07-10 23:47:57| 来源: 网络整理| 查看: 265

 

关键词:微信登录、统一下单(支付)、统一下单通知(回调)、统一下单查询、企业付款至零钱、支付查询、获取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和openid

4.服务器通过前端给的rawData 加获取的session_key使用sha1加密,计算出signature1

5.比对前端传的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()+"\n\t\n"+" 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\n微信下单参数转换为xml:\n"+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 resp = template.postForEntity(url, xmlStr, String.class); if(resp == null || resp.getStatusCode() != HttpStatus.OK) { throw new UnExceptedException("连接通信失败"); } Map map = null; try{ map = WeChatUtil.transXMLStrToMap(resp.getBody()); }catch (ParserConfigurationException | IOException | SAXException e) { logger.error(apiDesc+"xml解析异常:"+e.getMessage()+"\n"); 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 resultMap); /** * 业务失败,业务码失败后的逻辑 * @param resultMap * @return */ protected abstract FlyResponse onFail(Map resultMap); /** * 响应失败,业务码失败后的逻辑 * @param resultMap * @return */ protected FlyResponse onLinkFail(Map 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("\n--------------开始回调----------\n"); 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 map = WeChatUtil.transXMLStrToMap(notityXml); String returnCode = (String) map.get("return_code"); if("SUCCESS".equals(returnCode)){ SortedMap payInfo = new TreeMap(map); String sign = WeChatUtil.getSignFromMap(payInfo); if(sign.equals(map.get("sign"))){//比对签名防止数据篡改 //这里写自己的逻辑 } //通知微信服务器已经支付成功 resXml = "" + "" + "" + " "; logger.info("回调成功!!!!!!!"); } else { resXml = "" + "" + "" + " "; logger.warn("\n\t微信支付回调失败!签名不一致\n\t"); } }else{ resXml = "" + "" + "" + " "; 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.根据请求参数生成signature

2.请求参数转为xml

3.发起请求,判断结果

 

 

/** * 查询订单情况 * @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 resultMap) { if("SUCCESS".equalsIgnoreCase(resultMap.get("trade_state"))){ return FlyResponse.Success(200,"支付成功",resultMap); }else{ return FlyResponse.Fail(501,"支付失败",resultMap,"支付失败"); } } @Override protected FlyResponse onFail(Map 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 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 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 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 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 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\n由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 map, String character) { if (map == null || map.size() == 0) { return null; } StringBuilder sb = new StringBuilder(); Set keys = map.keySet(); Iterator 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");//将返回结果的标签替换为返回结果类 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 transXMLStrToMap(String xmlStr) throws ParserConfigurationException, SAXException, IOException { Map data = new HashMap(); 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.weixin.qq.com/cgi-bin/message/wxopen/template/send"; }

 

 

public interface WechatInfo { /** * 小程序appid */ String appid = ""; /** * 商户号的Appid */ String mch_appid = ""; /** *商户号 */ String mch_id = ""; /** *回调地址 */ String notify_url = ""; /** *交易类型 */ String trade_type = "JSAPI"; /** * 签名类型 */ String sign_type = "MD5"; /** * 商户密匙 */ String key = ""; /** * 小程序ApiSecret */ String SECRET = ""; /** * 证书地址 */ String CERTIFICATE_ADDRESS = ""; /** * 二维码图片地址 */ String QRImgRootAddress =""; /** * 静态资源 */ String SourceUrl = ""; }

 

HTTP方法封装:

 

import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIUtils; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import javax.net.ssl.SSLContext; import java.io.*; import java.net.URI; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; public class HttpClientHelper { private static Logger logger = Logger.getLogger(HttpClientHelper.class); private static PoolingHttpClientConnectionManager connMgr; private static RequestConfig requestConfig; private static final int MAX_TIMEOUT = 7000; static { // 设置连接池 connMgr = new PoolingHttpClientConnectionManager(); // 设置连接池大小 connMgr.setMaxTotal(100); connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal()); RequestConfig.Builder configBuilder = RequestConfig.custom(); // 设置连接超时 configBuilder.setConnectTimeout(MAX_TIMEOUT); // 设置读取超时 configBuilder.setSocketTimeout(MAX_TIMEOUT); // 设置从连接池获取连接实例的超时 configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT); // 在提交请求之前 测试连接是否可用 configBuilder.setStaleConnectionCheckEnabled(true); requestConfig = configBuilder.build(); } /** * 发送GET请求(HTTP),K-V形式 * @param url * @author Charlie.chen; * @return */ public static String doGet(String url, Map params) throws Exception { URI uri = null; // 创建默认的HttpClient实例. try(CloseableHttpClient httpclient = HttpClients.createDefault();) { if(params != null){ List nameParams = paramsToNameValuePair(params); String queryString = URLEncodedUtils.format(nameParams, "utf-8"); uri = URIUtils.resolve(new URI(url),queryString); }else{ uri = new URI(url); } // 定义一个get请求方法 HttpGet httpget = new HttpGet(uri); // 执行get请求,返回response服务器响应对象, 其中包含了状态信息和服务器返回的数据 CloseableHttpResponse httpResponse = httpclient.execute(httpget); // 使用响应对象, 获得状态码, 处理内容 int statusCode = httpResponse.getStatusLine().getStatusCode(); logger.info("Send a http get request and the response code is :"+statusCode); if (statusCode == HttpStatus.SC_OK) { // 使用响应对象获取响应实体 HttpEntity entity = httpResponse.getEntity(); // 将响应实体转为字符串 String response = EntityUtils.toString(entity, "utf-8"); return response; } } catch (Exception e) { logger.info("Send a http get request occurred exception",e); throw e; } return null; } /** * 发送POST请求(HTTP),K-V形式 * @param url * @param params * @author Charlie.chen * @return 响应结果 */ public static String doPost(String url, Map params) throws IOException { try(CloseableHttpClient httpclient = HttpClients.createDefault();){// 创建默认的HttpClient实例. // 定义一个get请求方法 HttpPost httppost = new HttpPost(url); httppost.setHeader("Content-type","application/json,charset=utf-8"); httppost.setHeader("Accept", "application/json"); if (params!=null) { List list = paramsToNameValuePair(params); httppost.setEntity(new UrlEncodedFormEntity(list, "utf-8")); } // 执行post请求,返回response服务器响应对象, 其中包含了状态信息和服务器返回的数据 CloseableHttpResponse httpResponse = httpclient.execute(httppost); // 使用响应对象, 获得状态码, 处理内容 int statusCode = httpResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { // 使用响应对象获取响应实体 HttpEntity entity = httpResponse.getEntity(); // 将响应实体转为字符串 String response = EntityUtils.toString(entity, "utf-8"); return response; } } catch (Exception e) { logger.info("Send a http get request occurred exception",e); throw e; } return null; } /** * 转换参数 * @param params * @return */ private static List paramsToNameValuePair(Map params){ List pairList = new ArrayList(params.size()); for (Map.Entry entry : params.entrySet()) { NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue()==null ? null : entry.getValue().toString()); pairList.add(pair); } return pairList; } /** * 发送 不安全的SSL POST请求(信任所有证书) * (HTTPS),K-V形式 * @param url * @param params * @author Charlie.chen */ public static String doPostSSL_unSafe(String url, Map params,boolean isJson) { CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(createUnsafeSSLConn()) .setConnectionManager(connMgr) .setDefaultRequestConfig(requestConfig) .build(); HttpPost httpPost = new HttpPost(url); if(isJson){ httpPost.addHeader("Content-type","application/json;charset=UTF-8"); httpPost.addHeader("Accept","application/json"); httpPost.addHeader("Cache-Control: no-cache","Pragma: no-cache"); } String httpStr = null; try { httpPost.setConfig(requestConfig); if(isJson){ String paramsStr = JSON.toJSONString(params); StringEntity entity = new StringEntity(paramsStr,ContentType.APPLICATION_JSON); httpPost.setEntity(entity); } if(!isJson && params!=null&¶ms.size()>0){ List pairList = paramsToNameValuePair(params); httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8"))); } response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); logger.info("Send a PostSSL request and the response code is :"+statusCode); if (statusCode != HttpStatus.SC_OK) { return null; } HttpEntity entity = response.getEntity(); if (entity == null) { return null; } httpStr = EntityUtils.toString(entity, "utf-8"); } catch (Exception e) { logger.error("Http post unexpected exception",e); } finally { if (response != null) { try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { logger.error("Http client close response exception",e); } } } return httpStr; } public static File doPostToFileSSL_unSafe(String url, String paramJson,File file) throws IOException { CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(createUnsafeSSLConn()) .setConnectionManager(connMgr) .setDefaultRequestConfig(requestConfig) .build(); HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Content-type","application/json;charset=UTF-8"); httpPost.addHeader("Accept","application/json"); httpPost.addHeader("Cache-Control: no-cache","Pragma: no-cache"); CloseableHttpResponse response = null; String httpStr = null; try { httpPost.setConfig(requestConfig); httpPost.setEntity(entityParam); response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); logger.info("Send a PostSSL request and the response code is :"+statusCode); if (statusCode == HttpStatus.SC_OK) { // 使用响应对象获取响应实体 HttpEntity entity = response.getEntity(); entity.writeTo(new FileOutputStream(file)); return file; } } catch (Exception e) { logger.error("Http post unexpected exception",e); throw e; } finally { if (response != null) { try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { logger.error("Http client close response exception",e); } } } return null; } /** * 发送安全的SSL POST请求 * * (HTTPS),K-V形式 * @param url * @param params * @param certificateAddress 证书地址 * @param certificatePassword 证书密码 * @return */ public static String doPostSSL_Safe(String url, Map params,String certificateAddress, String certificatePassword) throws Exception { CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(createSafeSSLConn(certificateAddress,certificatePassword)) .setConnectionManager(connMgr) .setDefaultRequestConfig(requestConfig) .build(); HttpPost httpPost = new HttpPost(url); CloseableHttpResponse response = null; String httpStr = null; try { httpPost.setConfig(requestConfig); List pairList = paramsToNameValuePair(params); httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8"))); response = httpClient.execute(httpPost); int statusCode = response.getStatusLine().getStatusCode(); logger.info("Send a PostSSL request and the response code is :"+statusCode); if (statusCode != HttpStatus.SC_OK) { return null; } HttpEntity entity = response.getEntity(); if (entity == null) { return null; } httpStr = EntityUtils.toString(entity, "utf-8"); } catch (Exception e) { logger.error("Http post unexpected exception",e); } finally { if (response != null) { try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { logger.error("Http client close response exception",e); } } } } /** * 创建不安全的SSL连接 * @author Charlie.chen * @return */ private static SSLConnectionSocketFactory createUnsafeSSLConn() { SSLConnectionSocketFactory sslsf = null; try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); sslsf = new SSLConnectionSocketFactory(sslContext); } catch (GeneralSecurityException e) { e.printStackTrace(); } return sslsf; } /** * 建立给定证书的安全连接 * @param certificateAddress 证书地址 * @param password 证书密码 * @return */ //读取证书 KeyStore keyStore = KeyStore.getInstance("PKCS12");//PKCS12,java中的公匙加密标准 try (FileInputStream instream = new FileInputStream(new File(certificateAddress));){ keyStore.load(instream, password.toCharArray());//加载给定的证书 // keyStore.load(null,null); //若没有可用的证书的写法 } //建立证书连接工厂 SSLConnectionSocketFactory sslsf = null; try { SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore,password.toCharArray()).build(); sslsf = new SSLConnectionSocketFactory(sslContext); } catch (GeneralSecurityException e) { e.printStackTrace(); } return sslsf; } }

 

水平有限,如果有问题,欢迎指正,一起交流学习成长。转载请注明。

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭