package com.etnetchina.servlet.util;
import com.etnetchina.id.IdGenerate;
import com.etnetchina.log.LogUtil;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.LogFactory;
/**
* WEB相关的工具方法。
*/
public class WebUtil {
private static final LogUtil logger = new LogUtil(LogFactory.getLog(
WebUtil.class));
private WebUtil() {
}
/**
* 取实际用户的访问地址。
* @param request 当前请求。
* @return 客户端IP地址。
*/
public static String getIpAddr(HttpServletRequest request) {
String ips = request.getHeader("x-forwarded-for");
if (ips == null || ips.length() == 0 || "unknown".equalsIgnoreCase(ips)) {
ips = request.getHeader("Proxy-Client-IP");
}
if (ips == null || ips.length() == 0 || "unknown".equalsIgnoreCase(ips)) {
ips = request.getHeader("WL-Proxy-Client-IP");
}
if (ips == null || ips.length() == 0 || "unknown".equalsIgnoreCase(ips)) {
ips = request.getRemoteAddr();
}
String[] ipArray = ips.split(",");
String clientIP = null;
for (String ip : ipArray) {
if (!("unknown".equalsIgnoreCase(ip))) {
clientIP = ip;
break;
}
}
return clientIP;
}
/**
* 查找指定请求中的指定名称的Cookie。
* @param request 请求。
* @param name cookie名称。
* @return 如果有相应名称的Cookie,则返回相应Cookie实例。没有返回null。
*/
public static Cookie findCookie(HttpServletRequest request, String name) {
if (request != null) {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie;
}
}
}
}
return null;
}
/**
* 查找指定请求中的指定名称Cookie的值,如果不存在将返回null。
* @param request 请求。
* @param name Cookie名称。
* @return cookie的值。
*/
public static String findCookieValue(HttpServletRequest request, String name) {
Cookie cookie = findCookie(request, name);
return cookie != null ? cookie.getValue() : null;
}
/**
* 增加一个Cookie,使用默认域名。
* @param request 请求。
* @param response 响应。
* @param name Cookie名称 。
* @param value Cookie的值。
* @param maxAge 生命周期。
*/
public static void addCookie(
HttpServletRequest request,
HttpServletResponse response,
String name,
String value,
int maxAge) {
addCookie(request, response, name, value, null, maxAge);
}
/**
* 增加一个Cookie,使用指定域名。
* @param request 请求。
* @param response 响应。
* @param name Cookie名称 。
* @param value Cookie的值。
* @param maxAge 生命周期。
*/
public static void addCookie(
HttpServletRequest request,
HttpServletResponse response,
String name,
String value,
String domain,
int maxAge) {
String contextPath = request.getContextPath();
if (contextPath == null || contextPath.isEmpty()) {
contextPath = "/";
}
addCookie(request, response, name, value, domain, contextPath, maxAge);
}
/**
* 增加一个Cookie.ContextPath如果为空或者长度为0,将使用"/".
* @param request 当前请求。
* @param response 当前响应。
* @param name cookie名称
* @param value cookie值
* @param domain cookie域名
* @param contextPath cookie路径。
* @param maxAge 有效时间。
*/
public static void addCookie(
HttpServletRequest request,
HttpServletResponse response,
String name,
String value,
String domain,
String contextPath,
int maxAge) {
if (request != null && response != null) {
Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
cookie.setSecure(request.isSecure());
if (contextPath == null || contextPath.isEmpty()) {
cookie.setPath("/");
} else {
cookie.setPath(contextPath);
}
if (domain != null && !domain.isEmpty()) {
cookie.setDomain(domain);
}
response.addCookie(cookie);
logger.debugLog(
"Cookie update the sessionID.[name={0},value={1},maxAge={2},secure={3},path={4},domain={5}]",
cookie.getName(),
cookie.getValue(),
String.valueOf(cookie.getMaxAge()),
String.valueOf(cookie.getSecure()),
cookie.getPath(),
cookie.getDomain());
}
}
/**
* 失效一个Cookie.
* @param request 当前请求。
* @param response 当前响应。
* @param name Cookie名称。
* @param domain Cookie域名。
* @param contextPath 有效路径。
*/
public static void failureCookie(
HttpServletRequest request,
HttpServletResponse response,
String name,
String domain,
String contextPath) {
if (request != null && response != null) {
addCookie(request, response, name, null, domain, contextPath, 0);
}
}
/**
* 将指定的Cookie失效掉。
* @param request 请求
* @param response 响应。
* @param name cookie名称。
* @param domain cookie的域名。
*/
public static void failureCookie(HttpServletRequest request,
HttpServletResponse response, String name, String domain) {
String contextPath = request.getContextPath();
if (contextPath == null || contextPath.isEmpty()) {
contextPath = "/";
}
failureCookie(request, response, name, domain, contextPath);
}
/**
* 将指定的Cookie失效掉。
* @param request 请求
* @param response 响应。
* @param name cookie名称。
*/
public static void failureCookie(HttpServletRequest request,
HttpServletResponse response, String name) {
failureCookie(request, response, name, null);
}
/**
* 获取请求的完整地址。
* @param request 请求。
* @return 完整地址。
*/
public static String completeTheRequestAddress(HttpServletRequest request) {
StringBuilder buff = new StringBuilder(
request.getRequestURL().toString());
String queryString = request.getQueryString();
if (queryString != null) {
buff.append("?").append(queryString);
}
return buff.toString();
}
/**
* 将换行符替换成html页面使用的换行元素。
* @param source 原始字符串。
* @return 替换后的字符串。
*/
public static String enterToHtmlWrap(String source) {
if (source == null || source.trim().isEmpty()) {
return source;
} else {
return source.replaceAll("\r\n", "<br />");
}
}
/**
* 一个客户端转向的方便工具方法.可以选择使用301或者302方式进行跳转.
* @param response 当前响应.
* @param url 需要转向的地址.
* @param movePermanently true表示进行301永久跳转,false表示302临时跳转.
* @throws IOException I/O异常.
*/
public static void redirect(
HttpServletResponse response,
String url,
boolean movePermanently) throws IOException {
if (!movePermanently) {
response.sendRedirect(url);
} else {
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location", url);
}
}
/**
* 代理的名称,也代理了判断的顺序..
*/
private static final String[] AGENT_INDEX = {
"MSIE", "Firefox", "Chrome", "Opera", "Safari"
};
/**
* 存放用户代理解析的正则容器.
*/
private static final Map<String, Pattern> AGENT_PATTERNS =
new HashMap<String, Pattern>(AGENT_INDEX.length);
static {
AGENT_PATTERNS.put(AGENT_INDEX[0], Pattern.compile("MSIE ([\\d.]+)"));
AGENT_PATTERNS.put(AGENT_INDEX[1], Pattern.compile("Firefox/(\\d.+)"));
AGENT_PATTERNS.put(AGENT_INDEX[2], Pattern.compile("Chrome/([\\d.]+)"));
AGENT_PATTERNS.put(AGENT_INDEX[3], Pattern.compile("Opera[/\\s]([\\d.]+)"));
AGENT_PATTERNS.put(AGENT_INDEX[4], Pattern.compile("Version/([\\d.]+)"));
}
/**
* 获取用户代理信息.
* @param userAgent 用户代理信息字符串.
* @return 用户代理信息.
*/
public static UserAgent checkUserAgent(String userAgent) {
if (userAgent == null || userAgent.isEmpty()) {
return null;
}
Pattern pattern = null;
Matcher matcher = null;
for (int point = 0; point < AGENT_INDEX.length; point++) {
pattern = AGENT_PATTERNS.get(AGENT_INDEX[point]);
matcher = pattern.matcher(userAgent);
if (matcher.find()) {
return new UserAgent(AGENT_INDEX[point], matcher.group(1));
} else {
continue;
}
}
return null;
}
/**
* 获取指定请求中的用户代理.
* @param request 请求.
* @return 用户代理信息.
*/
public static UserAgent checkUserAgent(HttpServletRequest request) {
if (request == null) {
return null;
}
String userAgentHead = request.getHeader("User-Agent");
return checkUserAgent(userAgentHead);
}
/**
* 表示一个用户代理的信息.
*/
public static class UserAgent {
private String name = "";
private String version = "";
/**
* 构造一个用户代理信息.
* @param name 代理名称.
* @param version 代理版本号.
*/
public UserAgent(String name, String version) {
this.name = name;
this.version = version;
}
/**
* 获取代理名称.
* @return 代理名称.
*/
public String getName() {
return name;
}
/**
* 获取版本号.
* @return 版本号.
*/
public String getVersion() {
return version;
}
}
/**
* 票据名称
*/
public static final String TICKET_NAME = "ticket";
/**
* 创建票据.
* @param request 当前请求
*/
public static String createTicket(HttpServletRequest request) {
HttpSession session = request.getSession();
String ticket = IdGenerate.getUUIDString();
session.setAttribute(TICKET_NAME, ticket);
return ticket;
}
/**
* 验证票据.
* 请求中必须带有票据数据.
* @param request 当前请求.
* @return true验证通过,false验证不通过.
*/
public static boolean testTicket(HttpServletRequest request) {
HttpSession session = request.getSession();
String serverTicket = (String) session.getAttribute(TICKET_NAME);
String clientTicket = request.getParameter(TICKET_NAME);
try {
if (serverTicket == null) {
return true;
} else {
if (serverTicket.equals(clientTicket)) {
return true;
} else {
return false;
}
}
} finally {
session.removeAttribute(TICKET_NAME);
}
}
}
package com.etnetchina.log;
import com.etnetchina.util.CheckUtil;
import org.apache.commons.logging.Log;
/**
* 一个日志记录的帮助对象。
* 记录消息时消息中可以使用{0}之类的来表示一个占位符,此占位符会在写入日志后被指定的数据替换。
*
* 例如:写入一下DEBUG消息。LogUtil.debugLog("当前时间是{0}.","12:00");
* 那么最终写入日志的将是这样一条语句,"当前时间是12:00."。
* 其中占位符中的数字代表是需要使用第几个参数来替换。
* 参考"com.etnetchina.util.CheckUtil"中的"replaceArgs"方法。
*
* @see com.etnetchina.util.CheckUtil
*/
public class LogUtil {
private Log logger;//日志记录器。
private static Object[] empty = null;
/**
* 构造一个新的日志帮助实例。
* @param logger 使用的日志记录器。
*/
public LogUtil(final Log logger) {
this.logger = logger;
}
/**
* 记录一个无参数的消息。
* @param message 消息。
*/
public void infoLog(String message) {
infoLog(message, empty);
}
/**
* 记录一个消息,消息中的参数将替换成params指定的值。
* @param message 消息。
* @param params 消息中的替换值。
*/
public void infoLog(String message, Object... params) {
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException(
"Can not record the message blank.");
}
if (logger != null) {
if (logger.isInfoEnabled()) {
logger.info(
CheckUtil.replaceArgs(message, params));
}
}
}
/**
* 记录一个DEBUG消息。
* @param message 消息。
*/
public void debugLog(String message) {
debugLog(message, empty);
}
/**
* 记录一个DEBUG消息,消息中的参数将替换成params指定的值。
* @param message DEBUG消息。
* @param params 消息中的替换值。
*/
public void debugLog(String message, Object... params) {
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException(
"Can not record the message blank.");
}
if (logger != null) {
if (logger.isDebugEnabled()) {
logger.debug(
CheckUtil.replaceArgs(message, params));
}
}
}
/**
* 记录一个警告消息。
* @param message 警告消息。
*/
public void warnLog(String message) {
warnLog(message, empty);
}
/**
* 记录一个警告消息,消息中的参数将替换成params指定的值。
* @param message 警告消息。
* @param params 消息中的替换值。
*/
public void warnLog(String message, Object... params) {
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException(
"Can not record the message blank.");
}
if (logger != null) {
if (logger.isWarnEnabled()) {
logger.warn(
CheckUtil.replaceArgs(message, params));
}
}
}
/**
* 记录一个错误消息。
* @param ex 错误消息。
*/
public void errorLog(Exception ex) {
errorLog(ex, ex.getMessage() == null ? "" : ex.getMessage(), empty);
}
/**
* 往日志中输出一个错误。错误和错误消息必须设置。
* @param ex 错误实例。
* @param message 错误消息。
* @param params 消息中的替换值。
*/
public void errorLog(Exception ex, String message, Object... params) {
if (ex == null) {
throw new IllegalArgumentException(
"Can not record the error message empty.");
}
if (message == null) {
throw new IllegalArgumentException(
"Can not record the message blank.");
}
if (logger != null) {
if (logger.isErrorEnabled()) {
String nowMessage = CheckUtil.replaceArgs(message, params);
logger.error(nowMessage, ex);
}
}
}
/**
* 是否打开了警告日志缓别.
* @return true打开,false没有打开.
*/
public boolean isWarnEnabled() {
return logger.isWarnEnabled();
}
/**
* 是否打开了DEBUG日志缓别.
* @return true打开,false没有打开.
*/
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
/**
* 是否打开了信息日志缓别.
* @return true打开,false没有打开.
*/
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
/**
* 是否打开了错误日志缓别.
* @return true打开,false没有打开.
*/
public boolean isErrorEnabled() {
return logger.isErrorEnabled();
}
}
package com.etnetchina.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* 一些字节处理的方便方法。
*/
public class ByteUtil {
/**
* 构造新字节时需要与的值表
*/
private static final byte[] BUILD_BYTE_TABLE = new byte[]{
(byte) 128,
(byte) 64,
(byte) 32,
(byte) 16,
(byte) 8,
(byte) 4,
(byte) 2,
(byte) 1
};
private ByteUtil() {
}
/**
* short转换到字节数组
* @param number 需要转换的数据。
* @return 转换后的字节数组。
*/
public static byte[] shortToByte(short number) {
byte[] b = new byte[2];
for (int i = 1; i >= 0; i--) {
b[i] = (byte) (number % 256);
number >>= 8;
}
return b;
}
/**
* 字节到short转换
* @param b short的字节数组
* @return short数值。
*/
public static short byteToShort(byte[] b) {
return (short) ((((b[0] & 0xff) << 8) | b[1] & 0xff));
}
/**
* 整型转换到字节数组
* @param number 整形数据。
* @return 整形数据的字节数组。
*/
public static byte[] intToByte(int number) {
byte[] b = new byte[4];
for (int i = 3; i >= 0; i--) {
b[i] = (byte) (number % 256);
number >>= 8;
}
return b;
}
/**
* 字节数组到整型转换
* @param b 整形数据的字节数组。
* @return 字节数组转换成的整形数据。
*/
public static int byteToInt(byte[] b) {
return ((((b[0] & 0xff) << 24)
| ((b[1] & 0xff) << 16)
| ((b[2] & 0xff) << 8)
| (b[3] & 0xff)));
}
/**
* long转换到字节数组
* @param number 长整形数据。
* @return 长整形转换成的字节数组。
*/
public static byte[] longToByte(long number) {
byte[] b = new byte[8];
for (int i = 7; i >= 0; i--) {
b[i] = (byte) (number % 256);
number >>= 8;
}
return b;
}
/**
* 字节数组到整型的转换
* @param b 长整形字节数组。
* @return 长整形数据。
*/
public static long byteToLong(byte[] b) {
return ((((long) b[0] & 0xff) << 56)
| (((long) b[1] & 0xff) << 48)
| (((long) b[2] & 0xff) << 40)
| (((long) b[3] & 0xff) << 32)
| (((long) b[4] & 0xff) << 24)
| (((long) b[5] & 0xff) << 16)
| (((long) b[6] & 0xff) << 8)
| ((long) b[7] & 0xff));
}
/**
* double转换到字节数组
* @param d 双精度浮点。
* @return 双精度浮点的字节数组。
*/
public static byte[] doubleToByte(double d) {
byte[] bytes = new byte[8];
long l = Double.doubleToLongBits(d);
for (int i = 0; i < bytes.length; i++) {
bytes[i] = Long.valueOf(l).byteValue();
l = l >> 8;
}
return bytes;
}
/**
* 字节数组到double转换
* @param b 双精度浮点字节数组。
* @return 双精度浮点数据。
*/
public static double byteToDouble(byte[] b) {
long l;
l = b[0];
l &= 0xff;
l |= ((long) b[1] << 8);
l &= 0xffff;
l |= ((long) b[2] << 16);
l &= 0xffffff;
l |= ((long) b[3] << 24);
l &= 0xffffffffl;
l |= ((long) b[4] << 32);
l &= 0xffffffffffl;
l |= ((long) b[5] << 40);
l &= 0xffffffffffffl;
l |= ((long) b[6] << 48);
l &= 0xffffffffffffffl;
l |= ((long) b[7] << 56);
return Double.longBitsToDouble(l);
}
/**
* float转换到字节数组
* @param d 浮点型数据。
* @return 浮点型数据转换后的字节数组。
*/
public static byte[] floatToByte(float d) {
byte[] bytes = new byte[4];
int l = Float.floatToIntBits(d);
for (int i = 0; i < bytes.length; i++) {
bytes[i] = Integer.valueOf(l).byteValue();
l = l >> 8;
}
return bytes;
}
/**
* 字节数组到float的转换
* @param b 浮点型数据字节数组。
* @return 浮点型数据。
*/
public static float byteToFloat(byte[] b) {
int l;
l = b[0];
l &= 0xff;
l |= ((long) b[1] << 8);
l &= 0xffff;
l |= ((long) b[2] << 16);
l &= 0xffffff;
l |= ((long) b[3] << 24);
l &= 0xffffffffl;
return Float.intBitsToFloat(l);
}
/**
* 字符串到字节数组转换
* @param s 字符串。
* @param charset 字符编码
* @return 字符串按相应字符编码编码后的字节数组。
*/
public static byte[] stringToByte(String s, Charset charset) {
return s.getBytes(charset);
}
/**
* 字节数组带字符串的转换
* @param b 字符串按指定编码转换的字节数组。
* @param charset 字符编码。
* @return 字符串。
*/
public static String byteToString(byte[] b, Charset charset) {
return new String(b, charset);
}
/**
* 对象转换成字节数组。
* @param obj 字节数组。
* @return 对象实例相应的序列化后的字节数组。
* @throws IOException
*/
public static byte[] objectToByte(Object obj) throws IOException {
ByteArrayOutputStream buff = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(buff);
out.writeObject(obj);
try {
return buff.toByteArray();
} finally {
out.close();
}
}
/**
* 序死化字节数组转换成实际对象。
* @param b 字节数组。
* @return 对象。
* @throws IOException
* @throws ClassNotFoundException
*/
public static Object byteToObject(byte[] b)
throws IOException, ClassNotFoundException {
ByteArrayInputStream buff = new ByteArrayInputStream(b);
ObjectInputStream in = new ObjectInputStream(buff);
Object obj = in.readObject();
try {
return obj;
} finally {
in.close();
}
}
/**
* 比较两个字节的每一个bit位是否相等.
* @param a 比较的字节.
* @param b 比较的字节
* @return ture 两个字节每一位都相等,false有至少一位不相等.
*/
public static boolean equalsBit(byte a, byte b) {
return Arrays.equals(byteToBitArray(a), byteToBitArray(b));
}
/**
* 比较两个数组中的每一个字节,两个字节必须二进制字节码每一位都相同才表示两个
* byte相同.
* @param a 比较的字节数组.
* @param b 被比较的字节数.
* @return ture每一个元素的每一位两个数组都是相等的,false至少有一位不相等.
*/
public static boolean equalsBit(byte[] a, byte[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
int length = a.length;
if (b.length != length) {
return false;
}
for (int count = 0; count < a.length; count++) {
if (!equalsBit(a[count], b[count])) {
return false;
}
}
return true;
}
/**
* 返回某个字节的bit组成的字符串.
* @param b 字节.
* @return Bit位组成的字符串.
*/
public static String bitString(byte b) {
StringBuilder buff = new StringBuilder();
boolean[] array = byteToBitArray(b);
for (int i = 0; i < array.length; i++) {
buff.append(array[i] ? 1 : 0);
}
return buff.toString();
}
/**
* 计算出给定byte中的每一位,并以一个布尔数组返回.
* true表示为1,false表示为0.
* @param b 字节.
* @return 指定字节的每一位bit组成的数组.
*/
public static boolean[] byteToBitArray(byte b) {
boolean[] buff = new boolean[8];
int index = 0;
for (int i = 7; i >= 0; i--) {
buff[index++] = ((b >>> i) & 1) == 1;
}
return buff;
}
/**
* 返回指定字节中指定bit位,true为1,false为0.
* 指定的位从0-7,超出将抛出数据越界异常.
*
* @param b 需要判断的字节.
* @param index 字节中指定位.
* @return 指定位的值.
*/
public static boolean byteBitValue(byte b, int index) {
return byteToBitArray(b)[index];
}
/**
* 根据布尔数组表示的二进制构造一个新的字节.
* @param values 布尔数组,其中true表示为1,false表示为0.
* @return 构造的新字节.
*/
public static byte buildNewByte(boolean[] values) {
byte b = 0;
for (int i = 0; i < 8; i++) {
if (values[i]) {
b |= BUILD_BYTE_TABLE[i];
}
}
return b;
}
/**
* 将指定字节中的某个bit位替换成指定的值,true代表1,false代表0.
* @param b 需要被替换的字节.
* @param index 位的序号,从0开始.超过7将抛出越界异常.
* @param newValue 新的值.
* @return 替换好某个位值的新字节.
*/
public static byte changeByteBitValue(byte b, int index, boolean newValue) {
boolean[] bitValues = byteToBitArray(b);
bitValues[index] = newValue;
return buildNewByte(bitValues);
}
/**
* 将指定的IP地址转换成字节表示方式.
* IP数组的每一个数字都不能大于255,否则将抛出IllegalArgumentException异常.
*
* @param ipNums IP地址数组.
* @return IP地址字节表示方式.
*/
public static byte[] ipAddressBytes(String address) {
if (address == null || address.length() < 0 || address.length() > 15) {
throw new IllegalArgumentException("Invalid IP address.");
}
final int ipSize = 4;//最大IP位数
final char ipSpace = '.';//IP数字的分隔符
int[] ipNums = new int[ipSize];
StringBuilder number = new StringBuilder();//当前操作的数字
StringBuilder buff = new StringBuilder(address);
int point = 0;//当前操作的数字下标,最大到3.
char currentChar;
for (int i = 0; i < buff.length(); i++) {
currentChar = buff.charAt(i);
if (ipSpace == currentChar) {
//当前位置等于最大于序号后,还有字符没有处理表示这是一个错误的IP.
if (point == ipSize - 1 && buff.length() - (i + 1) > 0) {
throw new IllegalArgumentException("Invalid IP address.");
}
ipNums[point++] = Integer.parseInt(number.toString());
number.delete(0, number.length());
} else {
number.append(currentChar);
}
}
ipNums[point] = Integer.parseInt(number.toString());
byte[] ipBuff = new byte[ipSize];
int pointNum = 0;
for (int i = 0; i < 4; i++) {
pointNum = Math.abs(ipNums[i]);
if (pointNum > 255) {
throw new IllegalArgumentException("Invalid IP address.");
}
ipBuff[i] = (byte) (pointNum & 0xff);
}
return ipBuff;
}
}