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", "
"); } } /** * 一个客户端转向的方便工具方法.可以选择使用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 MapAGENT_PATTERNS = new HashMap (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; } }