Java PC端微信、支付宝扫码支付(一)
Java PC端微信、支付寶掃碼支付(一)
前端時間寫的項目用到了微信和支付寶的掃碼支付,因為是第一次寫,網上關于支付的資料也不多,所以用的時間比較長,趁現在工作不是太忙的時候對以前的工作總結一下。
一、微信
先附上微信的支付文檔地址 https://pay.weixin.qq.com/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 java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.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 2019/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 2019/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.weixin.qq.com/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.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2
查詢接口跟下單接口差不多,可以寫在WeixinPay這個類里面。
話不多說,直接上代碼
1.Controller層
在這里需要前端把下單接口返回的訂單號傳過來,在這里我們是用這個訂單號查詢訂單的支付狀態,不過還可以用微信的訂單號(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 = " ";public static final String HTML_AMP = "&";public static final String HTML_QUOTE = """;public static final String HTML_LT = "<";public static final String HTML_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, "default") = "default"* nullToDefault("", "default") = ""* nullToDefault(" ", "default") = " "* nullToDefault("bat", "default") = "bat"* </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("") = ""* trim(" ") = ""* trim("abc") = "abc"* trim(" abc ") = "abc"* </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("") = ""* trimStart("abc") = "abc"* trimStart(" abc") = "abc"* trimStart("abc ") = "abc "* trimStart(" abc ") = "abc "* </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("") = ""* trimEnd("abc") = "abc"* trimEnd(" abc") = " abc"* trimEnd("abc ") = "abc"* trimEnd(" abc ") = " abc"* </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, "abc") = false* equals("abc", null) = false* equals("abc", "abc") = true* equals("abc", "ABC") = 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, "abc") = false* equalsIgnoreCase("abc", null) = false* equalsIgnoreCase("abc", "abc") = true* equalsIgnoreCase("abc", "ABC") = 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 2016年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 java.net.URL; import java.net.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端微信、支付宝扫码支付(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 当当网图书项目
- 下一篇: java美元兑换,(Java实现) 美元