失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java PC端微信 支付宝扫码支付(一)

Java PC端微信 支付宝扫码支付(一)

时间:2022-10-06 01:50:04

相关推荐

Java PC端微信 支付宝扫码支付(一)

Java PC端微信、支付宝扫码支付(一)

前端时间写的项目用到了微信和支付宝的扫码支付,因为是第一次写,网上关于支付的资料也不多,所以用的时间比较长,趁现在工作不是太忙的时候对以前的工作总结一下。

一、微信

先附上微信的支付文档地址 https://pay./wiki/doc/api/native.php?chapter=6_3

关于扫码支付微信给出了两种模式,具体官方文档都有说明,这里用的是模式二。

先说一下我在写的时候遇到的一个问题:在最开始写好支付的时候,测试也测试成功了,但是前端就是接收不到支付成功的通知,最后看了下官方文档,发现在支付回调里面支付成功的通知只是通知给支付的用户,也就是你用微信支付成功后会跳转到支付成功的界面,但是我们的前端却是收不到通知的。关于这个问题微信官方也给出了相应的对策,就是在用户发起支付请求的时候前端去轮询微信的查询订单的接口,每个五秒或者三秒一次,直到收到支付成功的通知或者交易关闭才结束。这时候你可能就会想到这样做会不会对我们服务端的压力过大,但是这也是没办法的事情,毕竟我们调的事第三方的接口。我当时也想到了这个问题,然后我在京东的下单页面看了一下人家的请求,发现京东也是通过轮询去查询订单状态,以此来判定订单是否支付成功。

既然大佬都这样做了想必也是最好的办法了。

京东是大概每隔五秒去查询以此订单状态。

下面是具体的代码

1.Controller层

//微信支付接口@ApiOperation("微信支付")@PostMapping("/wxPay")public Result wxPay(WeChatParams ps) throws Exception {return tbPaymentRecordService.wxPay(ps);}

2.Service层

/*** 微信支付* @param ps* @return* @throws Exception*/Result wxPay(WeChatParams ps) throws Exception;

3.Impl

@Overridepublic Result wxPay(WeChatParams ps) throws Exception {TbPaymentAmount tbPaymentAmount = new TbPaymentAmount().selectById(ps.getAmountId());String numberCode = getNumberCode();Long doctorId = Login.userId();ps.setBody("服务充值");ps.setAttach(doctorId.toString());ps.setAmount(tbPaymentAmount.getAmount().multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString());ps.setOrderNo(numberCode);//ps.setDoctorId(doctorId.toString());ps.setDoctorId(doctorId.toString());String orderId = getNumberCode();//在这里生成订单信息,此时订单是未支付状态String urlCode = WeixinPay.getCodeUrl(ps);Map<String,Object> maps=new HashMap<>();maps.put("urlCode",urlCode);maps.put("orderNo",numberCode);return Result.success(maps);}

上面是用户发起支付请求,生成二维码链接,然后返回给前端,前端有工具可以直接生成二维码展示在页面,在这里给前端返回了订单号,方便前端用来查询支付的交易状态,这个在后面会说到。在这里注意微信支付的支付金额是以分为单位的,就是在这里ps.setAmount()传入的金额要把你的实际金额乘以100。支付宝是没有这个问题的。

下面是支付用到的工具

public static Logger lg=Logger.getLogger(WeixinPay.class);/*** 获取微信支付的二维码地址* @return* @author chenp* @throws Exception*/public static String getCodeUrl(WeChatParams ps) throws Exception {/*** 账号信息*/String appid = WeChatConfig.APPID;//微信服务号的appidString mch_id = WeChatConfig.MCHID; //微信支付商户号String key = WeChatConfig.APIKEY; // 微信支付的API密钥String notify_url = WeChatConfig.WECHAT_NOTIFY_URL_PC;//回调地址【注意,这里必须要使用外网的地址】String ufdoder_url=WeChatConfig.UFDODER_URL;//微信下单API地址String trade_type = "NATIVE"; //类型【网页扫码支付】/*** 时间字符串*/String currTime = PayForUtil.getCurrTime();String strTime = currTime.substring(8, currTime.length());String strRandom = PayForUtil.buildRandom(4) + "";String nonce_str = strTime + strRandom;//修改到期时间Calendar cal = Calendar.getInstance();cal.setTime(new Date());//设置起始时间cal.add(Calendar.MINUTE, 1);//增加一分钟DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");String format = df.format(cal.getTime());System.out.println(format);/*** 参数封装*/SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();packageParams.put("appid", appid);packageParams.put("mch_id", mch_id);packageParams.put("nonce_str", nonce_str);//随机字符串packageParams.put("body", ps.body);//支付的商品名称packageParams.put("out_trade_no", ps.orderNo);//商户订单号【备注:每次发起请求都需要随机的字符串,否则失败。】packageParams.put("total_fee", ps.amount);//支付金额packageParams.put("spbill_create_ip", PayForUtil.localIp());//客户端主机packageParams.put("notify_url", notify_url);packageParams.put("trade_type", trade_type);packageParams.put("attach", ps.attach);//额外的参数【业务类型+会员ID+支付类型】packageParams.put("time_expire", format);//额外的参数【业务类型+会员ID+支付类型】String sign = PayForUtil.createSign("UTF-8", packageParams,key); //获取签名packageParams.put("sign", sign);String requestXML = PayForUtil.getRequestXml(packageParams);//将请求参数转换成String类型lg.info("微信支付请求参数的报文"+requestXML);String resXml = HttpUtils.postData(ufdoder_url,requestXML); //解析请求之后的xml参数并且转换成String类型Map map = XMLUtil.doXMLParse(resXml);lg.info("微信支付响应参数的报文"+resXml);String urlCode = (String) map.get("code_url");return urlCode;}

/*** 微信支付需要的一些参数* @author chenp**/@Data//此注解代替了set、get方法,如果不想用这个注解也可以自己写set、get方法。public class WeChatParams {@ApiModelProperty(value = "订单金额",hidden = true)public String amount;//订单金额【备注:以分为单位】@ApiModelProperty(value = "商品名称",hidden = true)public String body;//商品名称@ApiModelProperty(value = "商户订单号",hidden = true)public String orderNo;//商户订单号@ApiModelProperty(value = "附加参数",hidden = true)public String attach;//附加参数@ApiModelProperty(value = "医生ID",hidden = true)public String doctorId;//会员ID@ApiModelProperty("缴费金额id")public Long amountId;}

package com.jgntech.medicine.core.kit.util;import .Inet4Address;import .InetAddress;import .InterfaceAddress;import workInterface;import .SocketException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Enumeration;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.SortedMap;import org.apache.log4j.Logger;/*** Created by hcs on /4/30 13:32*/public class PayForUtil {private static Logger lg=Logger.getLogger(PayForUtil.class);/*** 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。* @return boolean*/public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {StringBuffer sb = new StringBuffer();Set es = packageParams.entrySet();Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();String v = (String)entry.getValue();if(!"sign".equals(k) && null != v && !"".equals(v)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + API_KEY);//算出摘要String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();return tenpaySign.equals(mysign);}/*** @author chenp* @Description:sign签名* @param characterEncoding* 编码格式* @param parameters* 请求参数* @return*/public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {StringBuffer sb = new StringBuffer();Set es = packageParams.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + API_KEY);String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();return sign;}/*** @author chenp* @Description:将请求参数转换为xml格式的string* @param parameters* 请求参数* @return*/public static String getRequestXml(SortedMap<Object, Object> parameters) {StringBuffer sb = new StringBuffer();sb.append("<xml>");Set es = parameters.entrySet();Iterator it = es.iterator();while (it.hasNext()) {Map.Entry entry = (Map.Entry) it.next();String k = (String) entry.getKey();String v = (String) entry.getValue();if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");} else {sb.append("<" + k + ">" + v + "</" + k + ">");}}sb.append("</xml>");return sb.toString();}/*** 取出一个指定长度大小的随机正整数.** @param length* int 设定所取出随机数的长度。length小于11* @return int 返回生成的随机数。*/public static int buildRandom(int length) {int num = 1;double random = Math.random();if (random < 0.1) {random = random + 0.1;}for (int i = 0; i < length; i++) {num = num * 10;}return (int) ((random * num));}/*** 获取当前时间 yyyyMMddHHmmss* @author chenp* @return String*/public static String getCurrTime() {Date now = new Date();SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");String s = outFormat.format(now);return s;}/*** 获取本机IP地址* @author chenp* @return*/public static String localIp(){String ip = null;Enumeration allNetInterfaces;try {allNetInterfaces = NetworkInterface.getNetworkInterfaces();while (allNetInterfaces.hasMoreElements()) {NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();for (InterfaceAddress add : InterfaceAddress) {InetAddress Ip = add.getAddress();if (Ip != null && Ip instanceof Inet4Address) {ip = Ip.getHostAddress();}}}} catch (SocketException e) {lg.warn("获取本机Ip失败:异常信息:"+e.getMessage());}return ip;}}

package com.jgntech.medicine.core.config;/*** Created by hcs on /4/30 13:53*/public class WeChatConfig {/*** 微信服务号APPID*/public static String APPID="";/*** 微信支付的商户号*/public static String MCHID="";/*** 微信支付的API密钥*/public static String APIKEY="";/*** 微信支付成功之后的回调地址【注意:当前回调地址必须是公网能够访问的地址】*/public static String WECHAT_NOTIFY_URL_PC="";/*** 微信统一下单API地址*/public static String UFDODER_URL="https://api.mch./pay/unifiedorder";/*** true为使用真实金额支付,false为使用测试金额支付(1分)*/public static String WXPAY="true";}

上面就是生成支付二维码的代码了

下面就是支付回调,这个回调地址是在WeChatConfig 里面配置的,记住一定是外网可以访问的地址,如果没有服务器可以去百度内网穿透工具,我在这里用的是花生壳。

1.Controller层

@ApiOperation("微信支付回调")@PostMapping("/wxNotify")public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {tbPaymentRecordService.wechatNotifyUrlPc(request, response);}

2.Service层

/*** 微信支付回调* @param request* @param response* @throws Exception*/void wechatNotifyUrlPc(HttpServletRequest request, HttpServletResponse response) throws Exception;

3.Impl

@Overridepublic void wechatNotifyUrlPc(HttpServletRequest request, HttpServletResponse response) throws Exception {//读取参数InputStream inputStream;StringBuffer sb = new StringBuffer();inputStream = request.getInputStream();String s;BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));while ((s = in.readLine()) != null) {sb.append(s);}in.close();inputStream.close();//解析xml成mapMap<String, String> m = new HashMap<String, String>();m = XMLUtil.doXMLParse(sb.toString());//过滤空 设置 TreeMapSortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();Iterator<String> it = m.keySet().iterator();while (it.hasNext()) {String parameter = it.next();String parameterValue = m.get(parameter);String v = "";if (null != parameterValue) {v = parameterValue.trim();}packageParams.put(parameter, v);}// 微信支付的API密钥String key = WeChatConfig.APIKEY; // keylg.info("微信支付返回回来的参数:" + packageParams);//判断签名是否正确if (PayForUtil.isTenpaySign("UTF-8", packageParams, key)) {//------------------------------//处理业务开始//------------------------------String resXml = "";//商户订单号String out_trade_no = (String) packageParams.get("out_trade_no");TbOrder to = tbOrderDao.selectTbOrderByOrderNo(out_trade_no);if (to == null || to.getStatus() != 1) {if ("SUCCESS".equals((String) packageParams.get("result_code"))) {// 这里是支付成功//执行自己的业务逻辑开始(修改订单状态)String app_id = (String) packageParams.get("appid");String mch_id = (String) packageParams.get("mch_id");String openid = (String) packageParams.get("openid");String is_subscribe = (String) packageParams.get("is_subscribe");//是否关注公众号//附加参数【商标申请_0bda32824db44d6f9611f1047829fa3b_15460】--【业务类型_会员ID_订单号】String attach = (String) packageParams.get("attach");//付款金额【以分为单位】String total_fee = (String) packageParams.get("total_fee");//微信生成的交易订单号String transaction_id = (String) packageParams.get("transaction_id");//微信支付订单号//支付完成时间String time_end = (String) packageParams.get("time_end");lg.info("app_id:" + app_id);lg.info("mch_id:" + mch_id);lg.info("openid:" + openid);lg.info("is_subscribe:" + is_subscribe);lg.info("out_trade_no:" + out_trade_no);lg.info("total_fee:" + total_fee);lg.info("额外参数_attach:" + attach);lg.info("time_end:" + time_end);//执行自己的业务逻辑结束lg.info("支付成功");//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";} else {lg.info("支付失败,错误信息:" + packageParams.get("err_code"));resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";}} else {lg.info("无需重复支付");resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";}//------------------------------//处理业务完毕//------------------------------BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());out.write(resXml.getBytes());out.flush();out.close();} else {lg.info("通知签名验证失败");}}

在这里支付成功会给微信一个"SUCCESS",但是我们的前端却是收不到这个success的,这就需要我们写一个查询接口了,具体的参数和返回值信息可以查看微信的api文档 https://pay./wiki/doc/api/native.php?chapter=9_2

查询接口跟下单接口差不多,可以写在WeixinPay这个类里面。

话不多说,直接上代码

1.Controller层

//微信支付订单查询@ApiOperation("微信支付订单查询")@PostMapping("/wxPayExample")public Result wxPayExample(HttpServletRequest request,String out_trade_no) throws Exception {return tbPaymentRecordService.wxPayExample(request, out_trade_no);}

在这里需要前端把下单接口返回的订单号传过来,在这里我们是用这个订单号查询订单的支付状态,不过还可以用微信的订单号(transaction_id)去查,但是据我了解这个订单号是在用户支付成功,也就是回调里面生成的订单号,如果真是这样的话在生成订单的时候我们就拿不到这个订单号了。

2.Service层

/*** 微信支付订单查询* @return* @throws Exception*/Result wxPayExample(HttpServletRequest request,String out_trade_no) throws Exception;

3.Impl

@Overridepublic Result wxPayExample(HttpServletRequest request,String out_trade_no) throws Exception {Map<String, String> resultMap = new HashMap();lg.info("*************************调用支付查询 start*************************");if( out_trade_no == null || out_trade_no.trim().equals("")){ThrowsKit.error(BizExceptionEnum.VALIDA_ERROR.msg("订单号为空"));}//查询微信支付状态try {//TbRechargeRecord tbRechargeRecord = new TbRechargeRecord().selectOne(new EntityWrapper().eq("order_no",out_trade_no));//Map<String, String> map = WeixinPay.queryWeiXinPay(tbRechargeRecord.getVoucherNo());Map<String, String> map = WeixinPay.queryWeiXinPay(out_trade_no);lg.info("js定时器查询微信订单结果为=="+map);if(map==null||map.isEmpty()){ThrowsKit.error(BizExceptionEnum.VALIDA_ERROR.msg("查询支付状态失败"));}else{String total_fee = map.get("total_fee");//交易金额resultMap.put("return_code", "1");resultMap.put("total_fee", total_fee);resultMap.put("orderId", out_trade_no);}} catch (Exception e) {e.printStackTrace();ThrowsKit.error(BizExceptionEnum.STATUS_ERROR.msg("查询支付状态失败"));}return Result.success(resultMap);}

4.WeixinPay类

/*** 调用微信支付查询接口,返回支付信息* @param orderId* @return* @throws Exception*/public static Map<String, String> queryWeiXinPay(String orderId)throws Exception{Map<String, String> resp = null;MyConfig config = new MyConfig();WXPay wxpay = new WXPay(config,WXPayConstants.SignType.MD5,false);//true为测试环境Map<String, String> data = new HashMap<String, String>();data.put("out_trade_no", orderId);//订单号//data.put("transaction_id", orderId);//微信支付单号try{resp = wxpay.orderQuery(data);String return_code = (String)resp.get("return_code");String return_msg = (String)resp.get("return_msg");String result_code = (String)resp.get("result_code");String err_code = (String)resp.get("err_code");String err_code_des = (String)resp.get("err_code_des");String trade_state = (String)resp.get("trade_state");String trade_state_desc = (String)resp.get("trade_state_desc");if("SUCCESS".equals(return_code)){//微信返回状态码为成功if("SUCCESS".equals(result_code)){//业务结果状态码为成功if("SUCCESS".equals(trade_state)){//交易状态为成功return resp;}else if("USERPAYING".equals(trade_state)){//支付中return resp;}else{//交易状态为不是成功lg.info("***************支付平台订单ID:"+orderId+"查询微信支付接口异常:trade_state="+trade_state+",trade_state_desc="+trade_state_desc);resp = null;return resp;}}else{//业务结果状态码为失败lg.info("***************支付平台订单ID:"+orderId+"查询微信支付接口异常:err_code="+err_code+",err_code_des="+err_code_des);resp = null;return resp;}}else{//微信返回状态码为失败lg.info("***************支付平台订单ID:"+orderId+"查询微信支付接口异常:"+err_code);resp = null;return resp;}}catch(Exception e){lg.info("***************支付平台订单ID:"+orderId+"查询微信支付接口:"+e.getMessage());e.printStackTrace();resp = null;}//仅返回交易状态trade_state是SUCCESS的值return resp;}

到这里微信扫码支付的流程已经结束了。

第一次写文章,有什么遗漏的地方欢迎大家在下面评论。

下面补充遗漏的工具类(代码过长,可创建对应类名的java文件,直接复制粘贴即可)

字符串工具类

import java.io.StringReader;import java.io.StringWriter;import java.io.UnsupportedEncodingException;import java.nio.ByteBuffer;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Map.Entry;/*** 字符串工具类** @author xiaoleilu*/public class StrKit {public static final String SPACE = " ";public static final String DOT = ".";public static final String SLASH = "/";public static final String BACKSLASH = "\\";public static final String EMPTY = "";public static final String CRLF = "\r\n";public static final String NEWLINE = "\n";public static final String UNDERLINE = "_";public static final String COMMA = ",";public static final String HTML_NBSP = "&nbsp;";public static final String HTML_AMP = "&amp";public static final String HTML_QUOTE = "&quot;";public static final String HTML_LT = "&lt;";public static final String HTML_GT = "&gt;";public static final String EMPTY_JSON = "{}";/*** 首字母变小写*/public static String firstCharToLowerCase(String str) {char firstChar = str.charAt(0);if (firstChar >= 'A' && firstChar <= 'Z') {char[] arr = str.toCharArray();arr[0] += ('a' - 'A');return new String(arr);}return str;}/*** 首字母变大写*/public static String firstCharToUpperCase(String str) {char firstChar = str.charAt(0);if (firstChar >= 'a' && firstChar <= 'z') {char[] arr = str.toCharArray();arr[0] -= ('a' - 'A');return new String(arr);}return str;}// ------------------------------------------------------------------------ Blank/*** 字符串是否为空白 空白的定义如下: <br>* 1、为null <br>* 2、为不可见字符(如空格)<br>* 3、""<br>** @param str 被检测的字符串* @return 是否为空*/public static boolean isBlank(String str) {int length;if ((str == null) || ((length = str.length()) == 0)) {return true;}for (int i = 0; i < length; i++) {// 只要有一个非空字符即为非空字符串if (false == Character.isWhitespace(str.charAt(i))) {return false;}}return true;}/*** 字符串是否为非空白 空白的定义如下: <br>* 1、不为null <br>* 2、不为不可见字符(如空格)<br>* 3、不为""<br>** @param str 被检测的字符串* @return 是否为非空*/public static boolean notBlank(String str) {return false == isBlank(str);}/*** 是否包含空字符串** @param strs 字符串列表* @return 是否包含空字符串*/public static boolean hasBlank(String... strs) {if (CollectionKit.isEmpty(strs)) {return true;}for (String str : strs) {if (isBlank(str)) {return true;}}return false;}/*** 给定所有字符串是否为空白** @param strs 字符串* @return 所有字符串是否为空白*/public static boolean isAllBlank(String... strs) {if (CollectionKit.isEmpty(strs)) {return true;}for (String str : strs) {if (notBlank(str)) {return false;}}return true;}// ------------------------------------------------------------------------ Empty/*** 字符串是否为空,空的定义如下 1、为null <br>* 2、为""<br>** @param str 被检测的字符串* @return 是否为空*/public static boolean isEmpty(String str) {return str == null || str.length() == 0;}/*** 字符串是否为非空白 空白的定义如下: <br>* 1、不为null <br>* 2、不为""<br>** @param str 被检测的字符串* @return 是否为非空*/public static boolean isNotEmpty(String str) {return false == isEmpty(str);}/*** 当给定字符串为null时,转换为Empty** @param str 被转换的字符串* @return 转换后的字符串*/public static String nullToEmpty(String str) {return nullToDefault(str, EMPTY);}/*** 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。** <pre>* nullToDefault(null, &quot;default&quot;) = &quot;default&quot;* nullToDefault(&quot;&quot;, &quot;default&quot;) = &quot;&quot;* nullToDefault(&quot; &quot;, &quot;default&quot;) = &quot; &quot;* nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;* </pre>** @param str 要转换的字符串* @param defaultStr 默认字符串* @return 字符串本身或指定的默认字符串*/public static String nullToDefault(String str, String defaultStr) {return (str == null) ? defaultStr : str;}/*** 当给定字符串为空字符串时,转换为<code>null</code>** @param str 被转换的字符串* @return 转换后的字符串*/public static String emptyToNull(String str) {return isEmpty(str) ? null : str;}/*** 是否包含空字符串** @param strs 字符串列表* @return 是否包含空字符串*/public static boolean hasEmpty(String... strs) {if (CollectionKit.isEmpty(strs)) {return true;}for (String str : strs) {if (isEmpty(str)) {return true;}}return false;}/*** 是否全部为空字符串** @param strs 字符串列表* @return 是否全部为空字符串*/public static boolean isAllEmpty(String... strs) {if (CollectionKit.isEmpty(strs)) {return true;}for (String str : strs) {if (isNotEmpty(str)) {return false;}}return true;}// ------------------------------------------------------------------------ Trim/*** 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。** <p>* 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。** <pre>* trim(null)= null* trim(&quot;&quot;) = &quot;&quot;* trim(&quot;&quot;) = &quot;&quot;* trim(&quot;abc&quot;) = &quot;abc&quot;* trim(&quot; abc &quot;) = &quot;abc&quot;* </pre>** </p>** @param str 要处理的字符串* @return 除去空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code>*/public static String trim(String str) {return (null == str) ? null : trim(str, 0);}/*** 给定字符串数组全部做去首尾空格** @param strs 字符串数组*/public static void trim(String[] strs) {if (null == strs) {return;}String str;for (int i = 0; i < strs.length; i++) {str = strs[i];if (null != str) {strs[i] = str.trim();}}}/*** 除去字符串头部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。** <p>* 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。** <pre>* trimStart(null) = null* trimStart(&quot;&quot;) = &quot;&quot;* trimStart(&quot;abc&quot;) = &quot;abc&quot;* trimStart(&quot; abc&quot;)= &quot;abc&quot;* trimStart(&quot;abc &quot;)= &quot;abc &quot;* trimStart(&quot; abc &quot;)= &quot;abc &quot;* </pre>** </p>** @param str 要处理的字符串* @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code>*/public static String trimStart(String str) {return trim(str, -1);}/*** 除去字符串尾部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。** <p>* 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。** <pre>* trimEnd(null) = null* trimEnd(&quot;&quot;) = &quot;&quot;* trimEnd(&quot;abc&quot;)= &quot;abc&quot;* trimEnd(&quot; abc&quot;) = &quot; abc&quot;* trimEnd(&quot;abc &quot;) = &quot;abc&quot;* trimEnd(&quot; abc &quot;) = &quot; abc&quot;* </pre>** </p>** @param str 要处理的字符串* @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code>*/public static String trimEnd(String str) {return trim(str, 1);}/*** 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。** @param str 要处理的字符串* @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd* @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code>*/public static String trim(String str, int mode) {if (str == null) {return null;}int length = str.length();int start = 0;int end = length;// 扫描字符串头部if (mode <= 0) {while ((start < end) && (Character.isWhitespace(str.charAt(start)))) {start++;}}// 扫描字符串尾部if (mode >= 0) {while ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) {end--;}}if ((start > 0) || (end < length)) {return str.substring(start, end);}return str;}/*** 是否以指定字符串开头** @param str被监测字符串* @param prefix 开头字符串* @param isIgnoreCase 是否忽略大小写* @return 是否以指定字符串开头*/public static boolean startWith(String str, String prefix, boolean isIgnoreCase) {if (isIgnoreCase) {return str.toLowerCase().startsWith(prefix.toLowerCase());} else {return str.startsWith(prefix);}}/*** 是否以指定字符串结尾** @param str被监测字符串* @param suffix 结尾字符串* @param isIgnoreCase 是否忽略大小写* @return 是否以指定字符串结尾*/public static boolean endWith(String str, String suffix, boolean isIgnoreCase) {if (isIgnoreCase) {return str.toLowerCase().endsWith(suffix.toLowerCase());} else {return str.endsWith(suffix);}}/*** 是否包含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true** @param str被检测字符串* @param testStr 被测试是否包含的字符串* @return 是否包含*/public static boolean containsIgnoreCase(String str, String testStr) {if (null == str) {//如果被监测字符串和return null == testStr;}return str.toLowerCase().contains(testStr.toLowerCase());}/*** 获得set或get方法对应的标准属性名<br/>* 例如:setName 返回 name** @param getOrSetMethodName* @return 如果是set或get方法名,返回field, 否则null*/public static String getGeneralField(String getOrSetMethodName) {if (getOrSetMethodName.startsWith("get") || getOrSetMethodName.startsWith("set")) {return cutPreAndLowerFirst(getOrSetMethodName, 3);}return null;}/*** 生成set方法名<br/>* 例如:name 返回 setName** @param fieldName 属性名* @return setXxx*/public static String genSetter(String fieldName) {return upperFirstAndAddPre(fieldName, "set");}/*** 生成get方法名** @param fieldName 属性名* @return getXxx*/public static String genGetter(String fieldName) {return upperFirstAndAddPre(fieldName, "get");}/*** 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/>* 例如:str=setName, preLength=3 -> return name** @param str 被处理的字符串* @param preLength 去掉的长度* @return 处理后的字符串,不符合规范返回null*/public static String cutPreAndLowerFirst(String str, int preLength) {if (str == null) {return null;}if (str.length() > preLength) {char first = Character.toLowerCase(str.charAt(preLength));if (str.length() > preLength + 1) {return first + str.substring(preLength + 1);}return String.valueOf(first);}return null;}/*** 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get -> return getName** @param str 被处理的字符串* @param preString 添加的首部* @return 处理后的字符串*/public static String upperFirstAndAddPre(String str, String preString) {if (str == null || preString == null) {return null;}return preString + upperFirst(str);}/*** 大写首字母<br>* 例如:str = name, return Name** @param str 字符串* @return 字符串*/public static String upperFirst(String str) {return Character.toUpperCase(str.charAt(0)) + str.substring(1);}/*** 小写首字母<br>* 例如:str = Name, return name** @param str 字符串* @return 字符串*/public static String lowerFirst(String str) {if (isBlank(str)) {return str;}return Character.toLowerCase(str.charAt(0)) + str.substring(1);}/*** 去掉指定前缀** @param str 字符串* @param prefix 前缀* @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串*/public static String removePrefix(String str, String prefix) {if (isEmpty(str) || isEmpty(prefix)) {return str;}if (str.startsWith(prefix)) {return str.substring(prefix.length());}return str;}/*** 忽略大小写去掉指定前缀** @param str 字符串* @param prefix 前缀* @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串*/public static String removePrefixIgnoreCase(String str, String prefix) {if (isEmpty(str) || isEmpty(prefix)) {return str;}if (str.toLowerCase().startsWith(prefix.toLowerCase())) {return str.substring(prefix.length());}return str;}/*** 去掉指定后缀** @param str 字符串* @param suffix 后缀* @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串*/public static String removeSuffix(String str, String suffix) {if (isEmpty(str) || isEmpty(suffix)) {return str;}if (str.endsWith(suffix)) {return str.substring(0, str.length() - suffix.length());}return str;}/*** 获得字符串对应byte数组** @param str字符串* @param charset 编码,如果为<code>null</code>使用系统默认编码* @return bytes*/public static byte[] getBytes(String str, Charset charset) {if (null == str) {return null;}return null == charset ? str.getBytes() : str.getBytes(charset);}/*** 忽略大小写去掉指定后缀** @param str 字符串* @param suffix 后缀* @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串*/public static String removeSuffixIgnoreCase(String str, String suffix) {if (isEmpty(str) || isEmpty(suffix)) {return str;}if (str.toLowerCase().endsWith(suffix.toLowerCase())) {return str.substring(0, str.length() - suffix.length());}return str;}/*** 如果给定字符串不是以prefix开头的,在开头补充 prefix** @param str 字符串* @param prefix 前缀* @return 补充后的字符串*/public static String addPrefixIfNot(String str, String prefix) {if (isEmpty(str) || isEmpty(prefix)) {return str;}if (false == str.startsWith(prefix)) {str = prefix + str;}return str;}/*** 如果给定字符串不是以suffix结尾的,在尾部补充 suffix** @param str 字符串* @param suffix 后缀* @return 补充后的字符串*/public static String addSuffixIfNot(String str, String suffix) {if (isEmpty(str) || isEmpty(suffix)) {return str;}if (false == str.endsWith(suffix)) {str += suffix;}return str;}/*** 清理空白字符** @param str 被清理的字符串* @return 清理后的字符串*/public static String cleanBlank(String str) {if (str == null) {return null;}return str.replaceAll("\\s*", EMPTY);}/*** 切分字符串<br>* a#b#c -> [a,b,c] <br>* a##b#c -> [a,"",b,c]** @param str 被切分的字符串* @param separator 分隔符字符* @return 切分后的集合*/public static List<String> split(String str, char separator) {return split(str, separator, 0);}/*** 切分字符串** @param str 被切分的字符串* @param separator 分隔符字符* @param limit限制分片数* @return 切分后的集合*/public static List<String> split(String str, char separator, int limit) {if (str == null) {return null;}List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit);if (limit == 1) {list.add(str);return list;}boolean isNotEnd = true; // 未结束切分的标志int strLen = str.length();StringBuilder sb = new StringBuilder(strLen);for (int i = 0; i < strLen; i++) {char c = str.charAt(i);if (isNotEnd && c == separator) {list.add(sb.toString());// 清空StringBuildersb.delete(0, sb.length());// 当达到切分上限-1的量时,将所剩字符全部作为最后一个串if (limit != 0 && list.size() == limit - 1) {isNotEnd = false;}} else {sb.append(c);}}list.add(sb.toString());// 加入尾串return list;}/*** 切分字符串<br>* from jodd** @param str 被切分的字符串* @param delimiter 分隔符* @return 字符串*/public static String[] split(String str, String delimiter) {if (str == null) {return null;}if (str.trim().length() == 0) {return new String[]{str};}int dellen = delimiter.length(); // del lengthint maxparts = (str.length() / dellen) + 2; // one more for the lastint[] positions = new int[maxparts];int i, j = 0;int count = 0;positions[0] = -dellen;while ((i = str.indexOf(delimiter, j)) != -1) {count++;positions[count] = i;j = i + dellen;}count++;positions[count] = str.length();String[] result = new String[count];for (i = 0; i < count; i++) {result[i] = str.substring(positions[i] + dellen, positions[i + 1]);}return result;}/*** 改进JDK subString<br>* index从0开始计算,最后一个字符为-1<br>* 如果from和to位置一样,返回 "" <br>* 如果from或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length<br>* 如果经过修正的index中from大于to,则互换from和to* example: <br>* abcdefgh 2 3 -> c <br>* abcdefgh 2 -3 -> cde <br>** @param string String* @param fromIndex 开始的index(包括)* @param toIndex 结束的index(不包括)* @return 字串*/public static String sub(String string, int fromIndex, int toIndex) {int len = string.length();if (fromIndex < 0) {fromIndex = len + fromIndex;if (fromIndex < 0) {fromIndex = 0;}} else if (fromIndex >= len) {fromIndex = len - 1;}if (toIndex < 0) {toIndex = len + toIndex;if (toIndex < 0) {toIndex = len;}} else if (toIndex > len) {toIndex = len;}if (toIndex < fromIndex) {int tmp = fromIndex;fromIndex = toIndex;toIndex = tmp;}if (fromIndex == toIndex) {return EMPTY;}char[] strArray = string.toCharArray();char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex);return new String(newStrArray);}/*** 切割前部分** @param string 字符串* @param toIndex 切割到的位置(不包括)* @return 切割后的字符串*/public static String subPre(String string, int toIndex) {return sub(string, 0, toIndex);}/*** 切割后部分** @param string 字符串* @param fromIndex 切割开始的位置(包括)* @return 切割后的字符串*/public static String subSuf(String string, int fromIndex) {if (isEmpty(string)) {return null;}return sub(string, fromIndex, string.length());}/*** 给定字符串是否被字符包围** @param str 字符串* @param prefix 前缀* @param suffix 后缀* @return 是否包围,空串不包围*/public static boolean isSurround(String str, String prefix, String suffix) {if (StrKit.isBlank(str)) {return false;}if (str.length() < (prefix.length() + suffix.length())) {return false;}return str.startsWith(prefix) && str.endsWith(suffix);}/*** 给定字符串是否被字符包围** @param str 字符串* @param prefix 前缀* @param suffix 后缀* @return 是否包围,空串不包围*/public static boolean isSurround(String str, char prefix, char suffix) {if (StrKit.isBlank(str)) {return false;}if (str.length() < 2) {return false;}return str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix;}/*** 重复某个字符** @param c被重复的字符* @param count 重复的数目* @return 重复字符字符串*/public static String repeat(char c, int count) {char[] result = new char[count];for (int i = 0; i < count; i++) {result[i] = c;}return new String(result);}/*** 重复某个字符串** @param str 被重复的字符* @param count 重复的数目* @return 重复字符字符串*/public static String repeat(String str, int count) {// 检查final int len = str.length();final long longSize = (long) len * (long) count;final int size = (int) longSize;if (size != longSize) {throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize);}final char[] array = new char[size];str.getChars(0, len, array, 0);int n;for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2System.arraycopy(array, 0, array, n, n);}System.arraycopy(array, 0, array, n, size - n);return new String(array);}/*** 比较两个字符串(大小写敏感)。** <pre>* equals(null, null) = true* equals(null, &quot;abc&quot;) = false* equals(&quot;abc&quot;, null) = false* equals(&quot;abc&quot;, &quot;abc&quot;) = true* equals(&quot;abc&quot;, &quot;ABC&quot;) = false* </pre>** @param str1 要比较的字符串1* @param str2 要比较的字符串2* @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>*/public static boolean equals(String str1, String str2) {if (str1 == null) {return str2 == null;}return str1.equals(str2);}/*** 比较两个字符串(大小写不敏感)。** <pre>* equalsIgnoreCase(null, null) = true* equalsIgnoreCase(null, &quot;abc&quot;) = false* equalsIgnoreCase(&quot;abc&quot;, null) = false* equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true* equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true* </pre>** @param str1 要比较的字符串1* @param str2 要比较的字符串2* @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>*/public static boolean equalsIgnoreCase(String str1, String str2) {if (str1 == null) {return str2 == null;}return str1.equalsIgnoreCase(str2);}/*** 格式化文本, {} 表示占位符<br>* 例如:format("aaa {} ccc", "bbb") ----> aaa bbb ccc** @param template 文本模板,被替换的部分用 {} 表示* @param values 参数值* @return 格式化后的文本*/public static String format(String template, Object... values) {if (CollectionKit.isEmpty(values) || isBlank(template)) {return template;}final StringBuilder sb = new StringBuilder();final int length = template.length();int valueIndex = 0;char currentChar;for (int i = 0; i < length; i++) {if (valueIndex >= values.length) {sb.append(sub(template, i, length));break;}currentChar = template.charAt(i);if (currentChar == '{') {final char nextChar = template.charAt(++i);if (nextChar == '}') {sb.append(values[valueIndex++]);} else {sb.append('{').append(nextChar);}} else {sb.append(currentChar);}}return sb.toString();}/*** 格式化文本,使用 {varName} 占位<br>* map = {a: "aValue", b: "bValue"}* format("{a} and {b}", map) ----> aValue and bValue** @param template 文本模板,被替换的部分用 {key} 表示* @param map参数值对* @return 格式化后的文本*/public static String format(String template, Map<?, ?> map) {if (null == map || map.isEmpty()) {return template;}for (Entry<?, ?> entry : map.entrySet()) {template = template.replace("{" + entry.getKey() + "}", entry.getValue().toString());}return template;}/*** 编码字符串** @param str字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 编码后的字节码*/public static byte[] bytes(String str, String charset) {return bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));}/*** 编码字符串** @param str字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 编码后的字节码*/public static byte[] bytes(String str, Charset charset) {if (str == null) {return null;}if (null == charset) {return str.getBytes();}return str.getBytes(charset);}/*** 将byte数组转为字符串** @param bytes byte数组* @param charset 字符集* @return 字符串*/public static String str(byte[] bytes, String charset) {return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));}/*** 解码字节码** @param data 字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 解码后的字符串*/public static String str(byte[] data, Charset charset) {if (data == null) {return null;}if (null == charset) {return new String(data);}return new String(data, charset);}/*** 将编码的byteBuffer数据转换为字符串** @param data 数据* @param charset 字符集,如果为空使用当前系统字符集* @return 字符串*/public static String str(ByteBuffer data, String charset) {if (data == null) {return null;}return str(data, Charset.forName(charset));}/*** 将编码的byteBuffer数据转换为字符串** @param data 数据* @param charset 字符集,如果为空使用当前系统字符集* @return 字符串*/public static String str(ByteBuffer data, Charset charset) {if (null == charset) {charset = Charset.defaultCharset();}return charset.decode(data).toString();}/*** 字符串转换为byteBuffer** @param str字符串* @param charset 编码* @return byteBuffer*/public static ByteBuffer byteBuffer(String str, String charset) {return ByteBuffer.wrap(StrKit.bytes(str, charset));}/*** 以 conjunction 为分隔符将多个对象转换为字符串** @param conjunction 分隔符* @param objs 数组* @return 连接后的字符串*/public static String join(String conjunction, Object... objs) {StringBuilder sb = new StringBuilder();boolean isFirst = true;for (Object item : objs) {if (isFirst) {isFirst = false;} else {sb.append(conjunction);}sb.append(item);}return sb.toString();}/*** 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br>* 例如:HelloWorld->hello_world** @param camelCaseStr 转换前的驼峰式命名的字符串* @return 转换后下划线大写方式命名的字符串*/public static String toUnderlineCase(String camelCaseStr) {if (camelCaseStr == null) {return null;}final int length = camelCaseStr.length();StringBuilder sb = new StringBuilder();char c;boolean isPreUpperCase = false;for (int i = 0; i < length; i++) {c = camelCaseStr.charAt(i);boolean isNextUpperCase = true;if (i < (length - 1)) {isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1));}if (Character.isUpperCase(c)) {if (!isPreUpperCase || !isNextUpperCase) {if (i > 0) sb.append(UNDERLINE);}isPreUpperCase = true;} else {isPreUpperCase = false;}sb.append(Character.toLowerCase(c));}return sb.toString();}/*** 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>* 例如:hello_world->HelloWorld** @param name 转换前的下划线大写方式命名的字符串* @return 转换后的驼峰式命名的字符串*/public static String toCamelCase(String name) {if (name == null) {return null;}if (name.contains(UNDERLINE)) {name = name.toLowerCase();StringBuilder sb = new StringBuilder(name.length());boolean upperCase = false;for (int i = 0; i < name.length(); i++) {char c = name.charAt(i);if (c == '_') {upperCase = true;} else if (upperCase) {sb.append(Character.toUpperCase(c));upperCase = false;} else {sb.append(c);}}return sb.toString();} elsereturn name;}/*** 包装指定字符串** @param str 被包装的字符串* @param prefix 前缀* @param suffix 后缀* @return 包装后的字符串*/public static String wrap(String str, String prefix, String suffix) {return format("{}{}{}", prefix, str, suffix);}/*** 指定字符串是否被包装** @param str 字符串* @param prefix 前缀* @param suffix 后缀* @return 是否被包装*/public static boolean isWrap(String str, String prefix, String suffix) {return str.startsWith(prefix) && str.endsWith(suffix);}/*** 指定字符串是否被同一字符包装(前后都有这些字符串)** @param str字符串* @param wrapper 包装字符串* @return 是否被包装*/public static boolean isWrap(String str, String wrapper) {return isWrap(str, wrapper, wrapper);}/*** 指定字符串是否被同一字符包装(前后都有这些字符串)** @param str字符串* @param wrapper 包装字符* @return 是否被包装*/public static boolean isWrap(String str, char wrapper) {return isWrap(str, wrapper, wrapper);}/*** 指定字符串是否被包装** @param str 字符串* @param prefixChar 前缀* @param suffixChar 后缀* @return 是否被包装*/public static boolean isWrap(String str, char prefixChar, char suffixChar) {return str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar;}/*** 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001"** @param str 字符串* @param minLength 最小长度* @param padChar 补充的字符* @return 补充后的字符串*/public static String padPre(String str, int minLength, char padChar) {if (str.length() >= minLength) {return str;}StringBuilder sb = new StringBuilder(minLength);for (int i = str.length(); i < minLength; i++) {sb.append(padChar);}sb.append(str);return sb.toString();}/*** 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100"** @param str 字符串* @param minLength 最小长度* @param padChar 补充的字符* @return 补充后的字符串*/public static String padEnd(String str, int minLength, char padChar) {if (str.length() >= minLength) {return str;}StringBuilder sb = new StringBuilder(minLength);sb.append(str);for (int i = str.length(); i < minLength; i++) {sb.append(padChar);}return sb.toString();}/*** 创建StringBuilder对象** @return StringBuilder对象*/public static StringBuilder builder() {return new StringBuilder();}/*** 创建StringBuilder对象** @return StringBuilder对象*/public static StringBuilder builder(int capacity) {return new StringBuilder(capacity);}/*** 创建StringBuilder对象** @return StringBuilder对象*/public static StringBuilder builder(String... strs) {final StringBuilder sb = new StringBuilder();for (String str : strs) {sb.append(str);}return sb;}/*** 获得StringReader** @param str 字符串* @return StringReader*/public static StringReader getReader(String str) {return new StringReader(str);}/*** 获得StringWriter** @return StringWriter*/public static StringWriter getWriter() {return new StringWriter();}/*** 编码字符串** @param str字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 编码后的字节码*/public static byte[] encode(String str, String charset) {if (str == null) {return null;}if (isBlank(charset)) {return str.getBytes();}try {return str.getBytes(charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException(format("Charset [{}] unsupported!", charset));}}/*** 解码字节码** @param data 字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 解码后的字符串*/public static String decode(byte[] data, String charset) {if (data == null) {return null;}if (isBlank(charset)) {return new String(data);}try {return new String(data, charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException(format("Charset [{}] unsupported!", charset));}}}

XML工具类

import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import org.jdom.Document;import org.jdom.Element;import org.jdom.JDOMException;import org.jdom.input.SAXBuilder;public class XMLUtil {/*** 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。* @param strxml* @return* @throws JDOMException* @throws IOException*/public static Map doXMLParse(String strxml) throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");if(null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();Iterator it = list.iterator();while(it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List children = e.getChildren();if(children.isEmpty()) {v = e.getTextNormalize();} else {v = XMLUtil.getChildrenText(children);}m.put(k, v);}//关闭流in.close();return m;}/*** 获取子结点的xml* @param children* @return String*/public static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if(!children.isEmpty()) {Iterator it = children.iterator();while(it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<" + name + ">");if(!list.isEmpty()) {sb.append(XMLUtil.getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}}

MD5加密工具

import com.jgntech.medicine.core.kit.support.StrKit;import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/*** MD5加密类(封装jdk自带的md5加密方法)** @author fengshuonan* @date 12月2日 下午4:14:22*/public class MD5Util {public static String encrypt(String source) throws UnsupportedEncodingException {if (StrKit.isNotEmpty(source)) {return encodeMd5(source.getBytes("UTF-8"));}return null;}private static String encodeMd5(byte[] source) {try {return encodeHex(MessageDigest.getInstance("MD5").digest(source));} catch (NoSuchAlgorithmException e) {throw new IllegalStateException(e.getMessage(), e);}}private static String encodeHex(byte[] bytes) {StringBuffer buffer = new StringBuffer(bytes.length * 2);for (int i = 0; i < bytes.length; i++) {if (((int) bytes[i] & 0xff) < 0x10)buffer.append("0");buffer.append(Long.toString((int) bytes[i] & 0xff, 16));}return buffer.toString();}public static String MD5Encode(String origin, String charsetname) {String resultString = null;try {resultString = new String(origin);MessageDigest md = MessageDigest.getInstance("MD5");if (charsetname == null || "".equals(charsetname))resultString = byteArrayToHexString(md.digest(resultString.getBytes()));elseresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));} catch (Exception exception) {}return resultString;}private static String byteArrayToHexString(byte b[]) {StringBuffer resultSb = new StringBuffer();for (int i = 0; i < b.length; i++)resultSb.append(byteToHexString(b[i]));return resultSb.toString();}private static String byteToHexString(byte b) {int n = b;if (n < 0)n += 256;int d1 = n / 16;int d2 = n % 16;return hexDigits[d1] + hexDigits[d2];}private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5","6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };public static void main(String[] args) throws UnsupportedEncodingException {System.out.println(encrypt("123456"));}}

http请求工具类

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import .URL;import .URLConnection;import org.apache.log4j.Logger;/*** http请求工具类* @author chenp**/public class HttpUtils {private final static int CONNECT_TIMEOUT = 5000; // in milliseconds 连接超时的时间private final static String DEFAULT_ENCODING = "UTF-8"; //字符串编码private static Logger lg=Logger.getLogger(HttpUtils.class);public static String postData(String urlStr, String data){return postData(urlStr, data, null);}/*** post数据请求* @param urlStr* @param data* @param contentType* @return*/public static String postData(String urlStr, String data, String contentType){BufferedReader reader = null;try {URL url = new URL(urlStr);URLConnection conn = url.openConnection();conn.setDoOutput(true);conn.setConnectTimeout(CONNECT_TIMEOUT);conn.setReadTimeout(CONNECT_TIMEOUT);if(contentType != null)conn.setRequestProperty("content-type", contentType);OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);if(data == null)data = "";writer.write(data);writer.flush();writer.close();reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));StringBuilder sb = new StringBuilder();String line = null;while ((line = reader.readLine()) != null) {sb.append(line);sb.append("\r\n");}return sb.toString();} catch (IOException e) {lg.info("Error connecting to " + urlStr + ": " + e.getMessage());} finally {try {if (reader != null)reader.close();} catch (IOException e) {}}return null;}}

如果觉得《Java PC端微信 支付宝扫码支付(一)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。