/**
* Web工具类
*
* @author co-pengxiao001
*/
public abstract class WebUtils {
private static Log logger = LogFactory.getLog(WebUtils.class);
// -- content-type 常量定义 --//
public static final String TEXT_TYPE = "text/plain";
public static final String JSON_TYPE = "application/json";
public static final String XML_TYPE = "text/xml";
public static final String HTML_TYPE = "text/html";
public static final String JS_TYPE = "text/javascript";
public static final String EXCEL_TYPE = "application/vnd.ms-excel";
public static final String WORD_TYPE = "application/vnd.ms-word;";
// -- header 常量定义 --//
public static final String AUTHENTICATION_HEADER = "Authorization";
public static final String HEADER_ENCODING = "encoding";
public static final String HEADER_NOCACHE = "no-cache";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final boolean DEFAULT_NOCACHE = true;
public static final int PAGE_SIZE = 20;
public static final int PAGE_INDEX_SIZE = 10;
// jackson提供的json转换对象
private static ObjectMapper mapper = new ObjectMapper();
private WebUtils() {
}
/**
* 获取访问者IP
*
* 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
*
* 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割), 如果还不存在则调用Request .getRemoteAddr()。
*
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
} else {
return ip;
}
if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
} else {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(',');
if (index != -1) {
ip = ip.substring(0, index);
}
}
return ip;
}
/**
* 获得当的访问路径
*
* HttpServletRequest.getRequestURL+"?"+HttpServletRequest.getQueryString
*
* @param request
* @return
*/
public static String getLocation(HttpServletRequest request) {
StringBuffer sb = request.getRequestURL();
if (request.getQueryString() != null) {
sb.append("?").append(request.getQueryString());
}
return sb.toString();
}
/**
* 设置让浏览器弹出下载对话框的Header.
*
* @param fileName 下载后的文件名.
*/
public static void setFileDownloadHeader(HttpServletResponse response, String fileName) {
try {
// 中文文件名支持
String encodedfileName = new String(fileName.getBytes(), "ISO8859-1");
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedfileName + "\"");
} catch (UnsupportedEncodingException e) {
}
}
/**
* 设置LastModified Header.
*/
public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedDate) {
response.setDateHeader("Last-Modified", lastModifiedDate);
}
/**
* 设置Etag Header.
*/
public static void setEtag(HttpServletResponse response, String etag) {
response.setHeader("ETag", etag);
}
/**
* 设置过期时间 Header.
*/
public static void setExpiresHeader(HttpServletResponse response, long expiresSeconds) {
// Http 1.0 header
response.setDateHeader("Expires", System.currentTimeMillis() + expiresSeconds * 1000);
// Http 1.1 header
response.setHeader("Cache-Control", "private, max-age=" + expiresSeconds);
}
/**
* 设置客户端无缓存Header.
*/
public static void setNoCacheHeader(HttpServletResponse response) {
// Http 1.0 header
response.setDateHeader("Expires", 0);
response.addHeader("Pragma", "no-cache");
// Http 1.1 header
response.setHeader("Cache-Control", "no-cache");
}
/**
* 设置禁止客户端缓存的Header.
*/
public static void setDisableCacheHeader(HttpServletResponse response) {
// Http 1.0 header
response.setDateHeader("Expires", 1L);
response.addHeader("Pragma", "no-cache");
// Http 1.1 header
response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
}
/**
* 检查浏览器客户端是否支持gzip编码.
*/
public static boolean checkAccetptGzip(HttpServletRequest request) {
// Http1.1 header
String acceptEncoding = request.getHeader("Accept-Encoding");
if (StringUtils.contains(acceptEncoding, "gzip")) {
return true;
} else {
return false;
}
}
/**
* 设置Gzip Header并返回GZIPOutputStream.
*/
public static OutputStream buildGzipOutputStream(HttpServletResponse response) throws IOException {
response.setHeader("Content-Encoding", "gzip");
return new GZIPOutputStream(response.getOutputStream());
}
/**
* 根据浏览器If-Modified-Since Header, 计算文件是否已修改. 如果无修改, checkIfModify返回false ,设置304 not modify status.
*/
public static boolean checkIfModifiedSince(HttpServletRequest request, HttpServletResponse response,
long lastModified) {
long ifModifiedSince = request.getDateHeader("If-Modified-Since");
if ((ifModifiedSince != -1) && (lastModified < ifModifiedSince + 1000)) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return false;
}
return true;
}
/**
* 根据浏览器 If-None-Match Header,计算Etag是否无效.
*
* 如果Etag有效,checkIfNoneMatch返回false, 设置304 not modify status.
*/
public static boolean checkIfNoneMatchEtag(HttpServletRequest request, HttpServletResponse response, String etag) {
String headerValue = request.getHeader("If-None-Match");
if (headerValue != null) {
boolean conditionSatisfied = false;
if (!"*".equals(headerValue)) {
StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ",");
while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
String currentToken = commaTokenizer.nextToken();
if (currentToken.trim().equals(etag)) {
conditionSatisfied = true;
}
}
} else {
conditionSatisfied = true;
}
if (conditionSatisfied) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader("ETag", etag);
return false;
}
}
return true;
}
/**
* 获取QueryString的参数,并使用URLDecoder以UTF-8格式转码。
*
* @param request web请求
* @param name 参数名称
* @return 参数值
*/
public static String getQueryParam(HttpServletRequest request, String name) {
return getQueryParam(request, name, "UTF-8");
}
/**
* 获取QueryString的参数,并使用URLDecoder以指定的编码格式转码。
*
* @param request web请求
* @param name 参数名称
* @param encoding 编码方式
* @return 参数值
*/
public static String getQueryParam(HttpServletRequest request, String name, String encoding) {
String s = request.getQueryString();
if (StringUtils.isBlank(s)) {
return null;
}
try {
s = URLDecoder.decode(s, encoding);
} catch (UnsupportedEncodingException e) {
logger.error("encoding " + encoding + " not support.", e);
}
if (StringUtils.isBlank(s)) {
return null;
}
String[] values = parseQueryString(s).get(name);
if (values != null && values.length > 0) {
return values[values.length - 1];
} else {
return null;
}
}
/**
*
* Parses a query string passed from the client to the server and builds a <code>HashTable</code> object with
* key-value pairs. The query string should be in the form of a string packaged by the GET or POST method, that is,
* it should have key-value pairs in the form <i>key=value</i>, with each pair separated from the next by a &
* character.
*
* <p>
* A key can appear more than once in the query string with different values. However, the key appears only once in
* the hashtable, with its value being an array of strings containing the multiple values sent by the query string.
*
* <p>
* The keys and values in the hashtable are stored in their decoded form, so any + characters are converted to
* spaces, and characters sent in hexadecimal notation (like <i>%xx</i>) are converted to ASCII characters.
*
* @param s a string containing the query to be parsed
*
* @return a <code>HashTable</code> object built from the parsed key-value pairs
*
* @exception IllegalArgumentException if the query string is invalid
*
*/
public static Map<String, String[]> parseQueryString(String s) {
String valArray[] = null;
if (s == null) {
throw new IllegalArgumentException();
}
Map<String, String[]> ht = new HashMap<String, String[]>();
StringTokenizer st = new StringTokenizer(s, "&");
while (st.hasMoreTokens()) {
String pair = (String) st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
continue;
}
String key = pair.substring(0, pos);
String val = pair.substring(pos + 1, pair.length());
if (ht.containsKey(key)) {
String oldVals[] = (String[]) ht.get(key);
valArray = new String[oldVals.length + 1];
for (int i = 0; i < oldVals.length; i++)
valArray[i] = oldVals[i];
valArray[oldVals.length] = val;
} else {
valArray = new String[1];
valArray[0] = val;
}
ht.put(key, valArray);
}
return ht;
}
@SuppressWarnings("unchecked")
public static Map<String, String> getRequestMap(HttpServletRequest request, String prefix) {
Map<String, String> map = new HashMap<String, String>();
Enumeration<String> names = request.getParameterNames();
String name;
while (names.hasMoreElements()) {
name = names.nextElement();
if (name.startsWith(prefix)) {
request.getParameterValues(name);
map.put(name.substring(prefix.length()), StringUtils.join(request.getParameterValues(name), ','));
}
}
return map;
}
/**
* 取得带相同前缀的Request Parameters.
*
* 返回的结果的Parameter名已去除前缀.
*/
@SuppressWarnings("rawtypes")
public static Map<String, Object> getParametersStartingWith(ServletRequest request, String prefix) {
AssertUtils.notNull(request, "Request must not be null");
Enumeration paramNames = request.getParameterNames();
Map<String, Object> params = new TreeMap<String, Object>();
if (prefix == null) {
prefix = "";
}
while (paramNames != null && paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
if ("".equals(prefix) || paramName.startsWith(prefix)) {
String unprefixed = paramName.substring(prefix.length());
String[] values = request.getParameterValues(paramName);
if (values == null || values.length == 0) {
// Do nothing, no values found at all.
} else if (values.length > 1) {
params.put(unprefixed, values);
} else {
params.put(unprefixed, values[0]);
}
}
}
return params;
}
/**
* 获取Long型的参数
*/
public static Long getLongParameter(HttpServletRequest request, String parameterName) {
if (StringUtils.isEmpty(parameterName)) {
throw new IllegalArgumentException();
}
String value = request.getParameter(parameterName);
if (StringUtils.isEmpty(value)) {
return null;
}
try {
return new Long(value);
} catch (NumberFormatException e) {
logger.error("Convert " + value + " to Long type failed!", e);
return null;
}
}
/**
* 获取Integer型的参数
*/
public static Integer getIntegerParameter(HttpServletRequest request, String parameterName) {
if (StringUtils.isEmpty(parameterName)) {
throw new IllegalArgumentException();
}
String value = request.getParameter(parameterName);
if (StringUtils.isEmpty(value)) {
return null;
}
try {
return new Integer(value);
} catch (NumberFormatException e) {
logger.error("Convert " + value + " to Integer type failed!", e);
return null;
}
}
/**
* 获取String型的参数
*/
public static String getStringParameter(HttpServletRequest request, String parameterName) {
if (StringUtils.isEmpty(parameterName)) {
throw new IllegalArgumentException();
}
String value = request.getParameter(parameterName);
return value;
}
/**
* 分析并设置contentType与headers.
*/
private static HttpServletResponse initResponseHeader(HttpServletResponse response, final String contentType,
final String... headers) {
// 分析headers参数
String encoding = DEFAULT_ENCODING;
boolean noCache = DEFAULT_NOCACHE;
for (String header : headers) {
String headerName = StringUtils.substringBefore(header, ":");
String headerValue = StringUtils.substringAfter(header, ":");
if (StringUtils.equalsIgnoreCase(headerName, HEADER_ENCODING)) {
encoding = headerValue;
} else if (StringUtils.equalsIgnoreCase(headerName, HEADER_NOCACHE)) {
noCache = Boolean.parseBoolean(headerValue);
} else {
throw new IllegalArgumentException(headerName + "不是一个合法的header类型");
}
}
// 设置headers参数
String fullContentType = contentType + ";charset=" + encoding;
response.setContentType(fullContentType);
if (noCache) {
WebUtils.setDisableCacheHeader(response);
}
return response;
}
/**
* 直接输出内容的简便函数.
*
* eg. render("text/plain", "hello", "encoding:GBK"); render("text/plain", "hello", "no-cache:false");
* render("text/plain", "hello", "encoding:GBK", "no-cache:false");
*
* @param headers 可变的header数组,目前接受的值为"encoding:"或"no-cache:",默认值分别为UTF-8和true.
*/
public static void render(HttpServletResponse response, final String contentType, final String content,
final String... headers) {
response = initResponseHeader(response, contentType, headers);
PrintWriter out = null;
try {
out = response.getWriter();
out.write(content);
out.flush();
} catch (IOException e) {
logger.error("render抛出的异常:", e);
throw new RuntimeException(e.getMessage(), e);
} finally {
if (BlankUtil.isBlank(out)) {
out.close();
}
}
}
/**
* 直接输出文本.
*
* @see #render(String, String, String...)
*/
public static void renderText(HttpServletResponse response, final String text, final String... headers) {
render(response, TEXT_TYPE, text, headers);
}
/**
* 直接输出HTML.
*
* @see #render(String, String, String...)
*/
public static void renderHtml(HttpServletResponse response, final String html, final String... headers) {
render(response, HTML_TYPE, html, headers);
}
/**
* 直接输出XML.
*
* @see #render(String, String, String...)
*/
public static void renderXml(HttpServletResponse response, final String xml, final String... headers) {
render(response, XML_TYPE, xml, headers);
}
/**
* 直接输出JSON.
*
* @param jsonString json字符串.
* @see #render(String, String, String...)
*/
public static void renderJson(HttpServletResponse response, final String jsonString, final String... headers) {
render(response, JSON_TYPE, jsonString, headers);
}
/**
* 直接输出JSON,使用Jackson转换Java对象.
*
* @param data 可以是List<POJO>, POJO[], POJO, 也可以Map名值对.
* @see #render(String, String, String...)
*/
public static void renderJson(HttpServletResponse response, final Object data, final String... headers) {
response = initResponseHeader(response, JSON_TYPE, headers);
try {
mapper.writeValue(response.getWriter(), data);
} catch (IOException e) {
logger.error("renderJson抛出的异常:", e);
throw new IllegalArgumentException(e);
}
}
/**
* 直接输出支持跨域Mashup的JSONP.
*
* @param callbackName callback函数名.
* @param object Java对象,可以是List<POJO>, POJO[], POJO ,也可以Map名值对, 将被转化为json字符串.
*/
public static void renderJsonp(HttpServletResponse response, final String callbackName, final Object object,
final String... headers) {
String jsonString = null;
try {
jsonString = mapper.writeValueAsString(object);
} catch (IOException e) {
logger.error("renderJsonp抛出的异常:", e);
throw new IllegalArgumentException(e);
}
String result = new StringBuilder().append(callbackName).append("(").append(jsonString).append(");").toString();
// 渲染Content-Type为javascript的返回内容,输出结果为javascript语句, 如callback197("{html:'Hello World!!!'}");
render(response, JS_TYPE, result, headers);
}
/**
* 在线打开服务器的绝对路径上的文件,<br>
* 可以在网页中直接显示图片、文本等文件的内容
*
* @param filePath
* @param response
* @throws Exception
*/
public static boolean openFileOnLine(String fpath, HttpServletResponse response) throws IOException {
String filePath = fpath;
BufferedInputStream br = null;
OutputStream out = null;
try {
filePath = URLDecoder.decode(filePath, "GBK").replaceAll("/", "\\\\");
File f = new File(filePath);
if (!f.exists()) {
return false;
}
br = new BufferedInputStream(new FileInputStream(f));
byte[] buf = new byte[1024];
int len = 0;
URL u = new URL("file:///" + filePath);
setDisableCacheHeader(response);
response.setContentType(u.openConnection().getContentType());
response.setHeader("Content-Disposition", "inline; filename=" + f.getName());
out = response.getOutputStream();
while ((len = br.read(buf)) > 0) {
out.write(buf, 0, len);
}
return true;
} catch (Exception e) {
logger.error("在线打开文件失败", e);
throw new RuntimeException("在线打开文件失败");
} finally {
if (br != null) {
br.close();
br = null;
}
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 在线打开服务器的相对路径上的文件,<br>
* 可以在网页中直接显示图片、文本等文件的内容
*
* @param file
* @param response
* @throws Exception
*/
public static boolean openFileOnLine(File file, HttpServletResponse response) throws IOException {
BufferedInputStream br = null;
OutputStream out = null;
try {
// file = new File(URLDecoder.decode(file.getAbsolutePath(), "GBK").replaceAll("/", "\\\\"));
file = new File(URLDecoder.decode(file.getAbsolutePath(), "GBK"));
if (!file.exists()) {
return false;
}
br = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[1024];
int len = 0;
setDisableCacheHeader(response);
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "inline; filename=" + file.getName());
out = response.getOutputStream();
while ((len = br.read(buf)) > 0) {
out.write(buf, 0, len);
}
return true;
} catch (Exception e) {
logger.error("在线打开文件失败", e);
throw new RuntimeException("在线打开文件失败");
} finally {
if (br != null) {
br.close();
br = null;
}
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 方法名:httpDownLoad<br>
* 功能描述:HTTP方式下载文件
*
* @param filePath 文件在服务器上绝对路径
* @param response 响应对象
* @param showFileName 下载对话框所显示的文件名
*/
public static boolean httpDownLoad(String fpath, HttpServletResponse response, String showFileName)
throws IOException {
String filePath = fpath;
InputStream br = null;
OutputStream out = null;
try {
if (StringUtils.isEmpty(filePath)) {
response.sendError(404, "File not found!");
return false;
}
// filePath = URLDecoder.decode(filePath, "GBK").replaceAll("/", "\\\\");
File f = new File(filePath);
if (!f.exists()) {
response.sendError(404, "File not found!");
return false;
}
String fileName = f.getName();
if (StringUtils.isNotEmpty(showFileName)) {
fileName = new String(showFileName.getBytes(), "iso-8859-1");
}
br = new BufferedInputStream(new FileInputStream(f));
byte[] buf = new byte[1024];
int len = 0;
setDisableCacheHeader(response);
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
out = response.getOutputStream();
while ((len = br.read(buf)) > 0) {
out.write(buf, 0, len);
}
return true;
} catch (Exception e) {
logger.error("Http方式下载文件异常", e);
throw new RuntimeException("Http方式下载文件异常", e);
} finally {
if (br != null) {
br.close();
br = null;
}
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 给url地址增加时间戳,骗过浏览器,不读取缓存
*
* @param url 原来的地址
* @return 新的url
*/
public static String convertURL(String url) {
StringBuffer newUrl = new StringBuffer(url);
// 获取时间戳
long timstamp = System.currentTimeMillis();
// 将时间戳信息拼接到url上
if (url.indexOf("?") >= 0) {
newUrl.append("&jtst=").append(timstamp);
} else {
newUrl.append("?jtst=").append(timstamp);
}
return newUrl.toString();
}
}
|