This commit is contained in:
xiangwbs
2018-03-26 21:12:20 +08:00
parent 2fd160a5df
commit 3cbb075e96
11 changed files with 13 additions and 945 deletions
@@ -1,12 +1,12 @@
package com.xwbing.service.other;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
import com.xwbing.domain.entity.wxpay.*;
import com.xwbing.exception.BusinessException;
import com.xwbing.exception.PayException;
import com.xwbing.util.RandomUtil;
import com.xwbing.util.payWxpay.ClientCustomSSL;
import com.xwbing.util.payWxpay.RandomKit;
import com.xwbing.util.payWxpay.WxSignKit;
import com.xwbing.util.payWxpay.XmlUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
@@ -173,7 +173,7 @@ public class WxPayService {
logger.info(content + "===========++++");
// 解析返回值
Map<String, String> returnMap;
returnMap = XmlUtil.doXMLParse(content);
returnMap = com.xwbing.util.payWxpay.XmlUtil.doXMLParse(content);
//返回状态码SUCCESS/FAIL
result.setResultCode(returnMap.get("return_code"));
//返回信息 非空,为错误原因
@@ -369,7 +369,7 @@ public class WxPayService {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appId);
params.put("mch_id", mchId);
String nonce_str = RandomKit.buildRandom(32);
String nonce_str = RandomUtil.buildRandom(32);
params.put("nonce_str", nonce_str);
params.put("body", param.getBody());
params.put("out_trade_no", param.getOutTradeNo());
@@ -401,7 +401,7 @@ public class WxPayService {
Map<String, String> params = new HashMap<String, String>();
params.put("appid", appId);
params.put("mch_id", mchId);
String nonce_str = RandomKit.buildRandom(32);
String nonce_str = RandomUtil.buildRandom(32);
params.put("nonce_str", nonce_str);
if (StringUtils.isEmpty(param.getTransactionId()) && StringUtils.isEmpty(param.getOutTradeNo())) {
throw new PayException("商户订单号和微信订单号不能同时为空!");
@@ -450,7 +450,7 @@ public class WxPayService {
if (StringUtils.isNotEmpty(outTradeNo)) {
params.put("out_trade_no", outTradeNo);
}
String nonce_str = RandomKit.buildRandom(32);
String nonce_str = RandomUtil.buildRandom(32);
params.put("nonce_str", nonce_str);
//签名放最后的
String sign = WxSignKit.buildSign(params, apiKey);
@@ -494,7 +494,7 @@ public class WxPayService {
if (StringUtils.isNotEmpty(refundid)) {
params.put("refund_id", refundid);
}
String nonce_str = RandomKit.buildRandom(32);
String nonce_str = RandomUtil.buildRandom(32);
params.put("nonce_str", nonce_str);
//签名放最后的
String sign = WxSignKit.buildSign(params, apiKey);
@@ -35,7 +35,7 @@ public class PassWordUtil {
public static String[] getUserSecret(String password, String pwdSalt) {
String[] str = new String[3];
if (StringUtils.isEmpty(password)) {
password = RadomUtil.buildRandom(PWD_LENGTH);
password = RandomUtil.buildRandom(PWD_LENGTH);
}
// 密码盐值
byte[] salt;
@@ -8,7 +8,7 @@ import java.util.Random;
* 说明:生成随机码
* 作者: xiangwb
*/
public class RadomUtil {
public class RandomUtil {
public static String buildRandom(int length) {
if (length < 1) {
throw new UtilException("参数异常!!!");
@@ -1,94 +0,0 @@
package com.xwbing.util.payAlipay;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.methods.multipart.FilePartSource;
import org.apache.commons.httpclient.methods.multipart.PartSource;
import java.io.File;
import java.io.IOException;
import java.util.*;
/* *
*类名:AlipayFunction
*功能:支付宝接口公用函数类
*详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改
*版本:3.3
*日期:2012-08-14
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public class AlipayCore {
/**
* 除去数组中的空值和签名参数
*
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
* 生成文件摘要
*
* @param strFilePath 文件路径
* @param file_digest_type 摘要算法
* @return 文件摘要结果
*/
public static String getAbstract(String strFilePath, String file_digest_type) throws IOException {
PartSource file = new FilePartSource(new File(strFilePath));
if (file_digest_type.equals("MD5")) {
return DigestUtils.md5Hex(file.createInputStream());
} else if (file_digest_type.equals("SHA")) {
return DigestUtils.sha256Hex(file.createInputStream());
} else {
return "";
}
}
}
@@ -1,123 +0,0 @@
package com.xwbing.util.payAlipay;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
/* *
*类名:AlipayNotify
*功能:支付宝通知处理类
*详细:处理支付宝各接口通知返回
*版本:3.3
*日期:2012-08-17
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考
*************************注意*************************
*调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
*/
public class AlipayNotify {
/**
* 支付宝消息验证地址
*/
private static final String HTTPS_VERIFY_URL = "https://mapi.payAlipay.com/gateway.do?service=notify_verify&";
/**
* 验证消息是否是支付宝发出的合法消息
* @param params 通知返回来的参数数组
* @return 验证结果
*/
public static boolean verify(Map<String, String> params) {
//判断responsetTxt是否为true,isSign是否为true
//responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
String responseTxt = "false";
if(params.get("notify_id") != null) {
String notify_id = params.get("notify_id");
responseTxt = verifyResponse(notify_id,params.get("partner"));
}
String sign = "";
if(params.get("sign") != null) {sign = params.get("sign");}
boolean isSign = getSignVeryfy(params, sign);
//写日志记录(若要调试,请取消下面两行注释)
//String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n 返回回来的参数:" + AlipayCore.createLinkString(params);
//AlipayCore.logResult(sWord);
if (isSign && responseTxt.equals("true")) {
return true;
} else {
return false;
}
}
/**
* 根据反馈回来的信息,生成签名结果
* @param Params 通知返回来的参数数组
* @param sign 比对的签名结果
* @return 生成的签名结果
*/
private static boolean getSignVeryfy(Map<String, String> Params, String sign) {
//过滤空值、sign与sign_type参数
Map<String, String> sParaNew = AlipayCore.paraFilter(Params);
//获取待签名字符串
String preSignStr = AlipayCore.createLinkString(sParaNew);
//获得签名验证结果
boolean isSign = false;
if(Params.get("sign_type").equals("MD5") ) {
isSign = MD5.verify(preSignStr, sign, Params.get("key"), "utf-8");
}else{
isSign = RSA.verify(preSignStr, sign, Params.get("key"), "utf-8");
}
return isSign;
}
/**
* 获取远程服务器ATN结果,验证返回URL
* @param notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
private static String verifyResponse(String notify_id,String partner) {
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;
return checkUrl(veryfy_url);
}
/**
* 获取远程服务器ATN结果
* @param urlvalue 指定URL路径地址
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
private static String checkUrl(String urlvalue) {
String inputLine = "";
try {
URL url = new URL(urlvalue);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
.getInputStream()));
inputLine = in.readLine().toString();
} catch (Exception e) {
e.printStackTrace();
inputLine = "";
}
return inputLine;
}
}
@@ -1,218 +0,0 @@
package com.xwbing.util.payAlipay;
import org.apache.commons.httpclient.NameValuePair;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/* *
*类名:AlipaySubmit
*功能:支付宝各接口请求提交类
*详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据
*版本:3.3
*日期:2012-08-13
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/
public class AlipaySubmit {
/**
* 支付宝提供给商户的服务接入网关URL(新)
*/
private static final String ALIPAY_GATEWAY_NEW = "https://mapi.payAlipay.com/gateway.do?";
/**
* 生成签名结果
* @param sPara 要签名的数组
* @return 签名结果字符串
*/
public static String buildRequestMysign(Map<String, String> sPara) {
String prestr = AlipayCore.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
String mysign = "";
if(sPara.get("sign_type") !=null && sPara.get("sign_type").equals("RSA") ) {
mysign = RSA.sign(prestr, sPara.get("key"),sPara.get("_input_charset"));
}else{
mysign = MD5.sign(prestr, sPara.get("key"),sPara.get("_input_charset"));
}
return mysign;
}
/**
* 生成要请求给支付宝的参数数组
* @param sParaTemp 请求前的参数数组
* @return 要请求的参数数组
*/
private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
//除去数组中的空值和签名参数
Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
//生成签名结果
String mysign = buildRequestMysign(sPara);
//签名结果与签名方式加入请求提交参数组中
sPara.put("sign", mysign);
sPara.put("sign_type", sParaTemp.get("sign_type"));
return sPara;
}
/**
* 建立请求,以表单HTML形式构造(默认)
* @param sParaTemp 请求参数数组
* @param strMethod 提交方式。两个值可选:post、get
* @param strButtonName 确认按钮显示文字
* @return 提交表单HTML文本
*/
public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName) {
//待请求参数数组
Map<String, String> sPara = buildRequestPara(sParaTemp);
List<String> keys = new ArrayList<String>(sPara.keySet());
StringBuffer sbHtml = new StringBuffer();
sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW
+ "_input_charset=utf-8\" method=\"" + strMethod
+ "\">");
for (int i = 0; i < keys.size(); i++) {
String name = (String) keys.get(i);
if("_input_charset".equals(name))
continue;
String value = (String) sPara.get(name);
sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
}
//submit按钮控件请不要含有name属性
sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
return sbHtml.toString();
}
/**
* 建立请求,以表单HTML形式构造,带文件上传功能
* @param sParaTemp 请求参数数组
* @param strMethod 提交方式。两个值可选:post、get
* @param strButtonName 确认按钮显示文字
* @param strParaFileName 文件上传的参数名
* @return 提交表单HTML文本
*/
public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName, String strParaFileName) {
//待请求参数数组
Map<String, String> sPara = buildRequestPara(sParaTemp);
List<String> keys = new ArrayList<String>(sPara.keySet());
StringBuffer sbHtml = new StringBuffer();
sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" enctype=\"multipart/form-data\" action=\"" + ALIPAY_GATEWAY_NEW
+ "_input_charset=utf-8\" method=\"" + strMethod
+ "\">");
for (int i = 0; i < keys.size(); i++) {
String name = (String) keys.get(i);
String value = (String) sPara.get(name);
sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
}
sbHtml.append("<input type=\"file\" name=\"" + strParaFileName + "\" />");
//submit按钮控件请不要含有name属性
sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
return sbHtml.toString();
}
/**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
* 如果接口中没有上传文件参数,那么strParaFileName与strFilePath设置为空值
* 如:buildRequest("", "",sParaTemp)
* @param strParaFileName 文件类型的参数名
* @param strFilePath 文件路径
* @param sParaTemp 请求参数数组
* @return 支付宝处理结果
* @throws Exception
*/
public static String buildRequest(String strParaFileName, String strFilePath,Map<String, String> sParaTemp) throws Exception {
//待请求参数数组
Map<String, String> sPara = buildRequestPara(sParaTemp);
HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
HttpRequest request = new HttpRequest(HttpResultType.BYTES);
//设置编码集
request.setCharset("utf-8");
request.setParameters(generatNameValuePair(sPara));
request.setUrl(ALIPAY_GATEWAY_NEW+"_input_charset=utf-8");
HttpResponse response = httpProtocolHandler.execute(request,strParaFileName,strFilePath);
if (response == null) {
return null;
}
String strResult = response.getStringResult();
return strResult;
}
/**
* MAP类型数组转换成NameValuePair类型
* @param properties MAP类型数组
* @return NameValuePair类型数组
*/
private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
int i = 0;
for (Map.Entry<String, String> entry : properties.entrySet()) {
nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
}
return nameValuePair;
}
/**
* 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
* 注意:远程解析XML出错,与服务器是否支持SSL等配置有关
* @return 时间戳字符串
* @throws IOException
* @throws DocumentException
* @throws MalformedURLException
*/
public static String query_timestamp(String partner) throws MalformedURLException,
DocumentException, IOException {
//构造访问query_timestamp接口的URL串
String strUrl = ALIPAY_GATEWAY_NEW + "service=query_timestamp&partner=" + partner + "&_input_charset=utf-8";
StringBuffer result = new StringBuffer();
SAXReader reader = new SAXReader();
Document doc = reader.read(new URL(strUrl).openStream());
List<Node> nodeList = doc.selectNodes("//alipay/*");
for (Node node : nodeList) {
// 截取部分不需要解析的信息
if (node.getName().equals("is_success") && node.getText().equals("T")) {
// 判断是否有成功标示
List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
for (Node node1 : nodeList1) {
result.append(node1.getText());
}
}
}
return result.toString();
}
}
@@ -1,68 +0,0 @@
package com.xwbing.util.payWxpay;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* Created by drore-wzm on 2015/11/23.
*/
public class IPKit {
public static String getIp2(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = ip.indexOf(",");
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
return ip;
}
return request.getRemoteAddr();
}
public static String getIPAddress(HttpServletRequest request) {
// 获取X-Forwarded-For
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
// 获取Proxy-Client-IP
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
// WL-Proxy-Client-IP
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
// 获取的IP实际上是代理服务器的地址,并不是客户端的IP地址
ip = request.getRemoteAddr();
}
/*
*
* 如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
*
* X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
* 192.168.1.100
*
* 用户真实IP为: 192.168.1.110
*/
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
return ip;
}
}
@@ -4,6 +4,7 @@
package com.xwbing.util.payWxpay;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
@@ -30,7 +31,7 @@ public class MD5Signature {
try {
String mySign = DigestUtils.md5Hex(getContentBytes(tosign, "utf-8"));
return StringUtil.equals(mySign, sign) ? true : false;
return StringUtils.equals(mySign, sign) ? true : false;
} catch (UnsupportedEncodingException e) {
throw new SignatureException("MD5验证签名[content = " + content + "; charset =utf-8 " + "; signature = " + sign + "]发生异常!", e);
}
@@ -41,7 +42,7 @@ public class MD5Signature {
try {
String mySign = DigestUtils.md5Hex(getContentBytes(tosign, charset));
return StringUtil.equals(mySign, sign) ? true : false;
return StringUtils.equals(mySign, sign) ? true : false;
} catch (UnsupportedEncodingException e) {
throw new SignatureException("MD5验证签名[content = " + content + "; charset =" + charset + "; signature = " + sign + "]发生异常!", e);
}
@@ -55,7 +56,7 @@ public class MD5Signature {
* @throws UnsupportedEncodingException
*/
protected static byte[] getContentBytes(String content, String charset) throws UnsupportedEncodingException {
if (StringUtil.isEmpty(charset)) {
if (StringUtils.isEmpty(charset)) {
return content.getBytes();
}
@@ -1,54 +0,0 @@
package com.xwbing.util.payWxpay;
import java.security.MessageDigest;
/**
* MD5加密工具类
* Created by drore-wzm on 2015/11/23.
*/
public class MD5Util {
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
/***
* 默认UTF-8
* @param origin
* @return
*/
public static String MD5Encode(String origin) {
return MD5Encode(origin, "UTF-8");
}
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()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
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 String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
}
@@ -1,30 +0,0 @@
package com.xwbing.util.payWxpay;
import java.util.Random;
/**
* Created by drore-wzm on 2015/11/23.
*/
public class RandomKit {
static String[] la_arrs={"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","S","X","Y","Z","0","1","2","3","4","5","6","7","8","9"};
/****
* 生成len个长度的随机字符
* @param len
* @return
*/
public static synchronized String buildRandom(int len){
if (len<=0) {
throw new RuntimeException("参数异常!!!");
}
StringBuffer random=new StringBuffer();
for (int i = 0; i < len; i++) {
random.append(la_arrs[new Random().nextInt(la_arrs.length)]);
}
return random.toString();
}
public static void main(String[] args) {
System.out.println(buildRandom(32));
}
}
@@ -1,346 +0,0 @@
/**
* Alipay.com Inc.
* Copyright (c) 2005-2006 All Rights Reserved.
*/
package com.xwbing.util.payWxpay;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 字符串处理的工具类
* @author stone.zhangjl
* @version $Id: StringUtil.java, v 0.1 2008-8-21 上午10:47:41 stone.zhangjl Exp $
*/
public class StringUtil {
/** 空字符串。 */
public static final String EMPTY_STRING = "";
/**
* 比较两个字符串(大小写敏感)。
* <pre>
* StringUtil.equals(null, null) = true
* StringUtil.equals(null, "abc") = false
* StringUtil.equals("abc", null) = false
* StringUtil.equals("abc", "abc") = true
* StringUtil.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>
* StringUtil.equalsIgnoreCase(null, null) = true
* StringUtil.equalsIgnoreCase(null, "abc") = false
* StringUtil.equalsIgnoreCase("abc", null) = false
* StringUtil.equalsIgnoreCase("abc", "abc") = true
* StringUtil.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);
}
/**
* 检查字符串是否是空白:<code>null</code>、空字符串<code>""</code>或只有空白字符。
* <pre>
* StringUtil.isBlank(null) = true
* StringUtil.isBlank("") = true
* StringUtil.isBlank(" ") = true
* StringUtil.isBlank("bob") = false
* StringUtil.isBlank(" bob ") = false
* </pre>
*
* @param str 要检查的字符串
*
* @return 如果为空白, 则返回<code>true</code>
*/
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 (!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
return true;
}
/**
* 检查字符串是否不是空白:<code>null</code>、空字符串<code>""</code>或只有空白字符。
* <pre>
* StringUtil.isBlank(null) = false
* StringUtil.isBlank("") = false
* StringUtil.isBlank(" ") = false
* StringUtil.isBlank("bob") = true
* StringUtil.isBlank(" bob ") = true
* </pre>
*
* @param str 要检查的字符串
*
* @return 如果为空白, 则返回<code>true</code>
*/
public static boolean isNotBlank(String str) {
int length;
if ((str == null) || ((length = str.length()) == 0)) {
return false;
}
for (int i = 0; i < length; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
/**
* 检查字符串是否为<code>null</code>或空字符串<code>""</code>。
* <pre>
* StringUtil.isEmpty(null) = true
* StringUtil.isEmpty("") = true
* StringUtil.isEmpty(" ") = false
* StringUtil.isEmpty("bob") = false
* StringUtil.isEmpty(" bob ") = false
* </pre>
*
* @param str 要检查的字符串
*
* @return 如果为空, 则返回<code>true</code>
*/
public static boolean isEmpty(String str) {
return ((str == null) || (str.length() == 0));
}
/**
* 检查字符串是否不是<code>null</code>和空字符串<code>""</code>。
* <pre>
* StringUtil.isEmpty(null) = false
* StringUtil.isEmpty("") = false
* StringUtil.isEmpty(" ") = true
* StringUtil.isEmpty("bob") = true
* StringUtil.isEmpty(" bob ") = true
* </pre>
*
* @param str 要检查的字符串
*
* @return 如果不为空, 则返回<code>true</code>
*/
public static boolean isNotEmpty(String str) {
return ((str != null) && (str.length() > 0));
}
/**
* 在字符串中查找指定字符串,并返回第一个匹配的索引值。如果字符串为<code>null</code>或未找到,则返回<code>-1</code>。
* <pre>
* StringUtil.indexOf(null, *) = -1
* StringUtil.indexOf(*, null) = -1
* StringUtil.indexOf("", "") = 0
* StringUtil.indexOf("aabaabaa", "a") = 0
* StringUtil.indexOf("aabaabaa", "b") = 2
* StringUtil.indexOf("aabaabaa", "ab") = 1
* StringUtil.indexOf("aabaabaa", "") = 0
* </pre>
*
* @param str 要扫描的字符串
* @param searchStr 要查找的字符串
*
* @return 第一个匹配的索引值。如果字符串为<code>null</code>或未找到,则返回<code>-1</code>
*/
public static int indexOf(String str, String searchStr) {
if ((str == null) || (searchStr == null)) {
return -1;
}
return str.indexOf(searchStr);
}
/**
* 在字符串中查找指定字符串,并返回第一个匹配的索引值。如果字符串为<code>null</code>或未找到,则返回<code>-1</code>。
* <pre>
* StringUtil.indexOf(null, *, *) = -1
* StringUtil.indexOf(*, null, *) = -1
* StringUtil.indexOf("", "", 0) = 0
* StringUtil.indexOf("aabaabaa", "a", 0) = 0
* StringUtil.indexOf("aabaabaa", "b", 0) = 2
* StringUtil.indexOf("aabaabaa", "ab", 0) = 1
* StringUtil.indexOf("aabaabaa", "b", 3) = 5
* StringUtil.indexOf("aabaabaa", "b", 9) = -1
* StringUtil.indexOf("aabaabaa", "b", -1) = 2
* StringUtil.indexOf("aabaabaa", "", 2) = 2
* StringUtil.indexOf("abc", "", 9) = 3
* </pre>
*
* @param str 要扫描的字符串
* @param searchStr 要查找的字符串
* @param startPos 开始搜索的索引值,如果小于0,则看作0
*
* @return 第一个匹配的索引值。如果字符串为<code>null</code>或未找到,则返回<code>-1</code>
*/
public static int indexOf(String str, String searchStr, int startPos) {
if ((str == null) || (searchStr == null)) {
return -1;
}
// JDK1.3及以下版本的bug:不能正确处理下面的情况
if ((searchStr.length() == 0) && (startPos >= str.length())) {
return str.length();
}
return str.indexOf(searchStr, startPos);
}
/**
* 取指定字符串的子串。
*
* <p>
* 负的索引代表从尾部开始计算。如果字符串为<code>null</code>,则返回<code>null</code>。
* <pre>
* StringUtil.substring(null, *, *) = null
* StringUtil.substring("", * , *) = "";
* StringUtil.substring("abc", 0, 2) = "ab"
* StringUtil.substring("abc", 2, 0) = ""
* StringUtil.substring("abc", 2, 4) = "c"
* StringUtil.substring("abc", 4, 6) = ""
* StringUtil.substring("abc", 2, 2) = ""
* StringUtil.substring("abc", -2, -1) = "b"
* StringUtil.substring("abc", -4, 2) = "ab"
* </pre>
* </p>
*
* @param str 字符串
* @param start 起始索引,如果为负数,表示从尾部计算
* @param end 结束索引(不含),如果为负数,表示从尾部计算
*
* @return 子串,如果原始串为<code>null</code>,则返回<code>null</code>
*/
public static String substring(String str, int start, int end) {
if (str == null) {
return null;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return EMPTY_STRING;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
/**
* 检查字符串中是否包含指定的字符串。如果字符串为<code>null</code>,将返回<code>false</code>。
* <pre>
* StringUtil.contains(null, *) = false
* StringUtil.contains(*, null) = false
* StringUtil.contains("", "") = true
* StringUtil.contains("abc", "") = true
* StringUtil.contains("abc", "a") = true
* StringUtil.contains("abc", "z") = false
* </pre>
*
* @param str 要扫描的字符串
* @param searchStr 要查找的字符串
*
* @return 如果找到,则返回<code>true</code>
*/
public static boolean contains(String str, String searchStr) {
if ((str == null) || (searchStr == null)) {
return false;
}
return str.indexOf(searchStr) >= 0;
}
/**
* <p>Checks if the String contains only unicode digits.
* A decimal point is not a unicode digit and returns false.</p>
*
* <p><code>null</code> will return <code>false</code>.
* An empty String ("") will return <code>true</code>.</p>
*
* <pre>
* StringUtils.isNumeric(null) = false
* StringUtils.isNumeric("") = true
* StringUtils.isNumeric(" ") = false
* StringUtils.isNumeric("123") = true
* StringUtils.isNumeric("12 3") = false
* StringUtils.isNumeric("ab2c") = false
* StringUtils.isNumeric("12-3") = false
* StringUtils.isNumeric("12.3") = false
* </pre>
*
* @param str the String to check, may be null
* @return <code>true</code> if only contains digits, and is non-null
*/
public static boolean isNumeric(String str) {
if (str == null) {
return false;
}
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isDigit(str.charAt(i)) == false) {
return false;
}
}
return true;
}
//java去除字符串中的空格、回车、换行符、制表符
public static String replaceBlank(String str) {
String dest = "";
if (str!=null) {
Pattern p = Pattern.compile("\\s*|\t|\r|\n");
Matcher m = p.matcher(str);
dest = m.replaceAll("");
}
return dest;
}
}