JDK环境变量配置及常用Java工具类指南
一. JDK环境变量配置
1. 位置
配置JDK环境变量第一步:找到入口。在桌面右键点击“我的电脑”(或“此电脑”),选择“属性”,接着进入“高级系统设置”,最后点击“环境变量”按钮。
2. 作用域
环境变量窗口里会看到两个区域:用户变量和系统变量。它们的作用域完全不同——用户变量只对当前登录用户生效,而系统变量则影响整个计算机上的所有用户。
3. 配置内容
接下来就是添加具体的变量了。需要添加以下三个变量,如果变量已经存在,直接在原有值的后面追加即可。注意每一项之间用英文分号隔开。
| 变量名 | 变量值 |
|---|---|
| JA VA_HOME | D:Ja vajdk1.8; |
| PATH | %JA VA_HOME%bin; |
| CLASSPATH | %JA VA_HOME%libtools.jar; |
二. Ja va后台获得客户端IP
获取客户端真实IP是个常见需求,尤其是在使用了反向袋里(比如Nginx)的情况下,简单的 request.getRemoteAddr() 就不够用了。这时候需要从请求头里一层层地找。直接看代码,逻辑很清晰:
import com.alibaba.druid.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ja vax.servlet.http.HttpServletRequest;
/**
* 获取客户端IP地址
*/
public class IPUtils {
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
/**
* 获取客户端IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
return ip;
}
}
三. 无参获取Request和Response
有时候在工具类或非Controller层需要拿到Request对象,但方法签名里没有传参。Spring提供了一个很好用的 RequestContextHolder,可以直接从当前线程绑定中获取。实现如下:
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class HttpContextUtils {
/**
* 获取Request
*/
public static HttpServletRequest getHttpServletRequest() {
if(RequestContextHolder.getRequestAttributes()==null){
return null;
}
return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取Response
*/
public static HttpServletResponse getHttpServletResponse() {
if(RequestContextHolder.getRequestAttributes()==null){
return null;
}
return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
}
}
四. Ja va代码行数统计
想知道项目里写了多少行代码?这个小工具可以帮你统计Ja va文件的代码行数、注释行数和空白行数。需要注意的是,这个类需要放在 src/test/ja va 目录下才能正常工作。核心思路就是递归扫描目录,然后逐行分析。
import ja va.io.BufferedReader;
import ja va.io.File;
import ja va.io.FileNotFoundException;
import ja va.io.FileReader;
import ja va.io.IOException;
import ja va.util.ArrayList;
public class CodeCounter {
static long files = 0;
static long codeLines = 0;
static long commentLines = 0;
static long blankLines = 0;
static ArrayList fileArray = new ArrayList();
public static ArrayList getFile(File f) {
File[] ff = f.listFiles();
for (File child : ff) {
if (child.isDirectory()) {
getFile(child);
} else
fileArray.add(child);
}
return fileArray;
}
private static void count(File f) {
BufferedReader br = null;
boolean flag = false;
try {
br = new BufferedReader(new FileReader(f));
String line = "";
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.matches("^[ ]*$")) {
blankLines++;
} else if (line.startsWith("//")) {
commentLines++;
} else if (line.startsWith("/*") && !line.endsWith("*/")) {
commentLines++;
flag = true;
} else if (line.startsWith("/*") && line.endsWith("*/")) {
commentLines++;
} else if (flag == true) {
commentLines++;
if (line.endsWith("*/")) {
flag = false;
}
} else {
codeLines++;
}
}
files++;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
br = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
String file = CodeCounter.class.getResource("/").getFile();
String path = file.replace("target/test-classes", "src");
ArrayList al = getFile(new File(path));
for (File f : al) {
if (f.getName().matches(".*.ja va$")){
count(f);
System.out.println(f);
}
}
System.out.println("统计文件:" + files);
System.out.println("代码行数:" + codeLines);
System.out.println("注释行数:" + commentLines);
System.out.println("空白行数:" + blankLines);
}
}
五. 判断设备类型(PC, 手机等), 浏览器类型(IE, Google等)
在Web开发中经常需要根据用户设备返回不同的页面,比如手机端和PC端分别渲染。推荐一个成熟的第三方库 UserAgentUtils,它能从User-Agent中解析出操作系统、浏览器和设备类型。先引入依赖:
1. Ma ven导包如下
eu.bitwalker
UserAgentUtils
1.21
2. 工具类如下
import ja vax.servlet.http.HttpServletRequest;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.DeviceType;
import eu.bitwalker.useragentutils.UserAgent;
public class UserAgentUtils {
public static UserAgent getUserAgent(HttpServletRequest request) {
return UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
}
public static DeviceType getDeviceType(HttpServletRequest request) {
return getUserAgent(request).getOperatingSystem().getDeviceType();
}
public static boolean isComputer(HttpServletRequest request) {
return DeviceType.COMPUTER.equals(getDeviceType(request));
}
public static boolean isMobile(HttpServletRequest request) {
return DeviceType.MOBILE.equals(getDeviceType(request));
}
public static boolean isTablet(HttpServletRequest request) {
return DeviceType.TABLET.equals(getDeviceType(request));
}
public static boolean isMobileOrTablet(HttpServletRequest request){
DeviceType deviceType = getDeviceType(request);
return DeviceType.MOBILE.equals(deviceType) || DeviceType.TABLET.equals(deviceType);
}
public static Browser getBrowser(HttpServletRequest request) {
return getUserAgent(request).getBrowser();
}
public static boolean isLteIE8(HttpServletRequest request) {
Browser browser = getBrowser(request);
return Browser.IE5.equals(browser) || Browser.IE6.equals(browser) || Browser.IE7.equals(browser)
|| Browser.IE8.equals(browser);
}
}
3. 进行拦截并根据需要进行处理
有了判断工具,下一步就是在Spring的拦截器里根据设备类型切换视图。比如手机或平板访问时,自动加上 mobile/ 前缀:
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.apache.commons.lang3.StringUtils;
public class MobileInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
if (UserAgentUtils.isMobileOrTablet(request)
&& !StringUtils.startsWithIgnoreCase(modelAndView.getViewName(), "redirect:")) {
modelAndView.setViewName("mobile/" + modelAndView.getViewName());
}
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
六. 根据日期生成目录
上传文件时,为了避免文件名重复,通常会用日期加时间戳来生成存储路径。下面这个工具类生成形如 2018/07/26/1532572300220 的路径:
import ja va.text.SimpleDateFormat;
import ja va.util.Date;
public class DirectoryUtils {
public static String getDir() {
StringBuilder sb = new StringBuilder("");
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
String path = format.format(date);
long time = new Date().getTime();
sb.append(path).append("/").append(time);
return sb.toString();
}
}
七. 根据附件名获得附件类型
当我们需要根据文件名后缀返回对应的类型(比如图片、文档、视频)时,可以借助 commons-io 的 FilenameUtils 来快速获取扩展名,然后做映射。
1. Ma ven导包
commons-io
commons-io
2.6
2. 工具类
import org.apache.commons.io.FilenameUtils;
public class FileTypeUtils {
public static String getFileType(String fileName) {
if (fileName != null && !"".equals(fileName)) {
String extension = FilenameUtils.getExtension(fileName);
if ("jng".equalsIgnoreCase(extension) || "jpg".equalsIgnoreCase(extension)
|| "png".equalsIgnoreCase(extension) || "gif".equalsIgnoreCase(extension)
|| "jpeg".equalsIgnoreCase(extension) || "bmp".equalsIgnoreCase(extension)) {
return "IMG";
} else if ("txt".equalsIgnoreCase(extension)) {
return "TXT";
} else if ("doc".equalsIgnoreCase(extension) || "docx".equalsIgnoreCase(extension)) {
return "DOC";
} else if ("pdf".equalsIgnoreCase(extension)) {
return "PDF";
} else if ("xls".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension)) {
return "XLS";
} else if ("ppt".equalsIgnoreCase(extension) || "pptx".equalsIgnoreCase(extension)) {
return "PPT";
} else if ("zip".equalsIgnoreCase(extension)) {
return "ZIP";
} else if ("mp3".equalsIgnoreCase(extension)) {
return "MP3";
} else if ("mp4".equalsIgnoreCase(extension) || "flv".equalsIgnoreCase(extension)
|| "a vi".equalsIgnoreCase(extension)) {
return "A VI";
} else if ("HTML".equalsIgnoreCase(extension)) {
return "HTM";
} else if ("VSD".equalsIgnoreCase(extension)) {
return "VSD";
} else {
return "OTHER";
}
}
return "";
}
}
八. 附件上传下载
文件上传下载是每个Web项目几乎都会遇到的功能。下面这个工具类整合了上传和下载两个方法,上传时通过 System.getProperty("webPath") 获取部署根目录(需要在web.xml中配置),下载时支持中文文件名编码。
1. web.xml中需要加入如下代码
webAppRootKey
webPath
2. Ja va代码如下
import ja va.io.File;
import ja va.io.FileInputStream;
import ja va.io.IOException;
import ja va.io.InputStream;
import ja va.io.OutputStream;
import ja va.io.UnsupportedEncodingException;
import ja va.net.URLEncoder;
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
public class FileUtils {
public static String fileUpload(MultipartFile file, String subPath) {
String basePath = System.getProperty("webPath");
String path = basePath.replaceAll("\\\\", "/") + subPath;
String finalPath = path + "/" + file.getOriginalFilename();
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
try {
file.transferTo(new File(finalPath));
} catch (IOException e) {
System.out.println("文件: " + file.getOriginalFilename() + "上传失败!");
e.printStackTrace();
}
return finalPath;
}
public static boolean excelOutTemplate(HttpServletRequest request, HttpServletResponse response,
String filePath, String fileShowName) {
String localPath = request.getServletContext().getRealPath("/");
String finalPath = localPath.endsWith("/") ? (localPath + filePath) : (localPath + "/" + filePath);
File file = new File(finalPath);
if (file.exists()) {
try {
response.addHeader("Content-Disposition",
"attachment;filename=" + URLEncoder.encode(fileShowName, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(finalPath);
out = response.getOutputStream();
int b;
while ((b = in.read()) != -1)
out.write(b);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
System.out.println("服务器文件已经不存在了!");
return false;
}
return true;
}
}
九. 获得UUID
生成唯一标识符最简单的方式就是UUID,去掉横线之后变成32位字符串,很多场景下用来做主键或文件名前缀。
import ja va.util.UUID;
public class IDUtils {
public static String getId() {
String id = UUID.randomUUID().toString();
id = id.replace("-", "");
return id;
}
}
十. 自定义异常类
为了让业务异常和系统异常区分开,通常会定义一个自定义运行时异常。这里封装了 msg 和 code 两个字段,方便在全局异常处理器中统一返回。
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
十一. 字符串首字母大写
有时候需要把字段名从驼峰转成首字母大写,比如生成getter/setter时。下面这个实现通过字符数组偏移量直接操作,效率很高。
public class StringUtils {
public static String captureName(String name) {
char[] cs=name.toCharArray();
cs[0]-=32;
return String.valueOf(cs);
}
}
十二. List乱序与按照汉字拼音排序
做抽奖或随机展示时经常需要打乱List顺序,而汉字拼音排序则适用于按名字首字母分组等场景。注意拼音排序依赖 Collator 的 Locale.CHINA 参数。
import ja va.text.Collator;
import ja va.util.ArrayList;
import ja va.util.Collections;
import ja va.util.Comparator;
import ja va.util.List;
import ja va.util.Random;
public class ListUtils {
public static List randomList(List sourceList) {
if (sourceList == null || sourceList.size() == 0) {
return sourceList;
}
List random = new ArrayList(sourceList.size());
do {
int index = Math.abs(new Random().nextInt(sourceList.size()));
random.add(sourceList.remove(index));
} while (sourceList.size() > 0);
return random;
}
public static List sortList(List sourceList) {
if (sourceList == null || sourceList.size() == 0) {
return sourceList;
}
List sort = new ArrayList(sourceList.size());
sort.addAll(sourceList);
Collections.sort(sort, new Comparator(){
@Override
public int compare(V v0, V v1) {
List list = new ArrayList(2);
list.add(v0.toString());
list.add(v1.toString());
Collections.sort(list, Collator.getInstance(ja va.util.Locale.CHINA));
return list.indexOf(v0.toString()) == 0 ? -1 : 1;
}
});
return sort;
}
}
十三. Redis工具类
基于Spring Data Redis封装了一个通用的缓存操作工具,支持String、List、Set、Map等常用数据结构,同时封装了删除方法。使用时需要先配置好Redis连接。
1. properties配置文件
# redis 配置文件
redis.hostName=127.0.0.1
redis.port=6379
redis.timeout=36000
redis.usePool=true
redis.maxIdle=6
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=3
redis.timeBetweenEvictionRunsMillis=60000
2. Spring添加配置文件
3. Ma ven依赖
org.springframework.data
spring-data-redis
1.6.2.RELEASE
redis.clients
jedis
2.9.0
4. Redis工具类
import ja va.util.Iterator;
import ja va.util.List;
import ja va.util.Map;
import ja va.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class RedisCacheUtil {
@Autowired
@Qualifier("jedisTemplate")
public RedisTemplate
十四. 判断是否是中文
有时候需要检查字符串是否包含中文字符,可以通过Unicode编码范围来判断。下面这个工具类支持中文汉字和中文符号。
public class CharUtils {
public static boolean isChinese(String strName) {
char[] ch = strName.toCharArray();
for (int i = 0; i < ch.length; i++) {
char c = ch[i];
if (isChinese(c)) {
return true;
}
}
return false;
}
private static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
return true;
}
return false;
}
}
十五. 异常拦截处理
全局异常处理器是Spring MVC中非常重要的一环。这里实现了 HandlerExceptionResolver 接口,针对自定义异常、数据库主键重复、Shiro权限不足等分别返回不同的JSON信息,同时记录日志。
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
@Component
public class RRExceptionHandler implements HandlerExceptionResolver {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
R r = new R();
try {
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
if (ex instanceof RRException) {
r.put("code", ((RRException) ex).getCode());
r.put("msg", ((RRException) ex).getMessage());
r.put("tip", ((RRException) ex).getMessage());
}
else if(ex instanceof DuplicateKeyException){
r = R.error("数据库中已存在该记录");
}
else if(ex instanceof AuthorizationException){
r = R.error("没有权限,请联系管理员授权").put("tip", "没有权限,请联系管理员授权").put("content", null);
}
else{
r = R.error();
}
logger.error(ex.getMessage(), ex);
String json = JSON.toJSONString(r);
response.getWriter().print(json);
} catch (Exception e) {
logger.error("RRExceptionHandler 异常处理失败", e);
e.printStackTrace();
}
return new ModelAndView();
}
}
十六. Cookie工具类
Cookie操作虽然简单,但涉及到编码、域名、路径等细节。这个工具类提供了获取、设置、删除Cookie的方法,支持编码和解码,同时考虑了多级域名的情况。
import ja va.io.UnsupportedEncodingException;
import ja va.net.URLDecoder;
import ja va.net.URLEncoder;
import ja vax.servlet.http.Cookie;
import ja vax.servlet.http.HttpServletRequest;
import ja vax.servlet.http.HttpServletResponse;
public class CookieUtils {
public static String getCookieValue(HttpServletRequest request, String cookieName) {
return getCookieValue(request, cookieName, false);
}
public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
if (isDecoder) {
retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
} else {
retValue = cookieList[i].getValue();
}
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue) {
setCookie(request, response, cookieName, cookieValue, -1);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage) {
setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, boolean isEncode) {
setCookie(request, response, cookieName, cookieValue, -1, isEncode);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage, boolean isEncode) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
String cookieValue, int cookieMaxage, String encodeString) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
}
public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName) {
doSetCookie(request, response, cookieName, "", -1, false);
}
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
try {
if (cookieValue == null) {
cookieValue = "";
} else {
cookieValue = URLEncoder.encode(cookieValue, encodeString);
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
private static final String getDomainName(HttpServletRequest request) {
String domainName = null;
String serverName = request.getRequestURL().toString();
if (serverName == null || serverName.equals("")) {
domainName = "";
} else {
final int end = serverName.lastIndexOf("/");
serverName = serverName.substring(0, end);
final String[] domains = serverName.split("\\.");
int len = domains.length;
if (len > 3) {
domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
} else if (len <= 3 && len > 1) {
domainName = "." + domains[len - 2] + "." + domains[len - 1];
} else {
domainName = serverName;
}
}
if (domainName != null && domainName.indexOf(":") > 0) {
String[] ary = domainName.split(":");
domainName = ary[0];
}
return domainName;
}
}
十七. 日期处理
日期格式化、获取某月的所有日期、判断是否同一天、计算相差天数——这些是日常开发中很常见的需求。下面这个工具类封装了这些方法,可以直接使用。
import ja va.text.SimpleDateFormat;
import ja va.util.ArrayList;
import ja va.util.Calendar;
import ja va.util.Date;
import ja va.util.List;
public class DateUtils {
public final static String DATE_PATTERN = "yyyy-MM-dd";
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
public static List getAllDatesOfMonth(Date date) {
List list = new ArrayList();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DATE, 1);
int month = cal.get(Calendar.MONTH);
while (cal.get(Calendar.MONTH) == month) {
list.add(cal.getTime());
cal.add(Calendar.DATE, 1);
}
return list;
}
public static boolean isSameDate(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
boolean isSameYear = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
boolean isSameMonth = isSameYear && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
boolean isSameDate = isSameMonth && cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH);
return isSameDate;
}
public static int getDateSpace(Date date1, Date date2) {
Calendar calst = Calendar.getInstance();
Calendar caled = Calendar.getInstance();
calst.setTime(date1);
caled.setTime(date2);
calst.set(Calendar.HOUR_OF_DAY, 0);
calst.set(Calendar.MINUTE, 0);
calst.set(Calendar.SECOND, 0);
caled.set(Calendar.HOUR_OF_DAY, 0);
caled.set(Calendar.MINUTE, 0);
caled.set(Calendar.SECOND, 0);
return ((int) (caled.getTime().getTime() / 1000) - (int) (calst.getTime().getTime() / 1000)) / 3600 / 24;
}
}
十八. HttpClient工具类(通过Ja va后台进行Http访问)
Ja va后端经常需要调用其他系统的HTTP接口,Apache HttpClient 是经典选择。这里封装了GET、POST请求(支持参数)、文件上传、文件下载以及SSL连接(支持证书导入和信任所有证书两种方式)。
1. Ma ven导包
org.apache.httpcomponents
httpclient
4.3.1
org.apache.httpcomponents
httpcore
4.3.1
org.apache.httpcomponents
httpmime
4.3.1
2. Ja va代码
import ja va.io.File;
import ja va.io.FileInputStream;
import ja va.io.FileOutputStream;
import ja va.io.IOException;
import ja va.io.InputStream;
import ja va.io.UnsupportedEncodingException;
import ja va.security.KeyManagementException;
import ja va.security.KeyStore;
import ja va.security.KeyStoreException;
import ja va.security.NoSuchAlgorithmException;
import ja va.security.cert.CertificateException;
import ja va.security.cert.X509Certificate;
import ja va.util.ArrayList;
import ja va.util.HashMap;
import ja va.util.List;
import ja va.util.Map;
import ja va.util.Set;
import ja vax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EntityUtils;
public class HttpClientUtils {
private static final int SUCCESS = 200;
public static void ssl(String url) {
CloseableHttpClient httpclient = null;
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File("E:tomcat.keystore"));
try {
trustStore.load(instream, "123456".toCharArray());
} catch (CertificateException e) {
e.printStackTrace();
} finally {
try {
instream.close();
} catch (Exception ignore) {
}
}
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext, new String[] { "TLSv1" }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
HttpGet httpget = new HttpGet(url);
System.out.println("executing request" + httpget.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
} finally {
response.close();
}
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} finally {
if (httpclient != null) {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static CloseableHttpClient createSSLClientDefault() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return HttpClients.createDefault();
}
public static void ssl2(String url) {
CloseableHttpClient httpclient = null;
try {
httpclient = createSSLClientDefault();
HttpGet httpget = new HttpGet(url);
System.out.println("executing request" + httpget.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
} finally {
response.close();
}
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpclient != null) {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void closeClientAndResponse(CloseableHttpClient client, CloseableHttpResponse response) {
try {
if (response != null) {
response.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static Map doGet(String url, Map params) {
Map result = new HashMap<>(2);
result.put("code", "200");
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try {
client = HttpClients.createDefault();
URIBuilder uri = new URIBuilder(url);
if (params != null) {
Set> entries = params.entrySet();
for (Map.Entry entry : entries) {
uri.addParameter(entry.getKey(), entry.getValue());
}
}
HttpGet hg = new HttpGet(uri.build());
hg.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
hg.setHeader(new BasicHeader("Accept", "application/json;charset=utf-8"));
response = client.execute(hg);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == SUCCESS) {
String resStr = EntityUtils.toString(response.getEntity(), "utf-8");
result.put("data", resStr);
} else {
result.put("code", statusCode + "");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeClientAndResponse(client, response);
}
return result;
}
public static Map doPost(String url, Map params){
Map result = new HashMap<>(2);
result.put("code", "200");
CloseableHttpClient client = null;
CloseableHttpResponse response = null;
try {
client = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
List formList = new ArrayList<>();
if (params != null) {
Set> entries = params.entrySet();
for (Map.Entry entry : entries) {
formList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
StringEntity entity = new UrlEncodedFormEntity(formList, "utf-8");
post.setEntity(entity);
post.setHeader(new BasicHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
post.setHeader(new BasicHeader("Accept", "application/json;charset=utf-8"));
response = client.execute(post);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == SUCCESS) {
String resStr = EntityUtils.toString(response.getEntity(), "utf-8");
result.put("data", resStr);
} else {
result.put("code", statusCode + "");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeClientAndResponse(client, response);
}
return result;
}
public static void upload(String url) {
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httppost = new HttpPost(url);
FileBody bin = new FileBody(new File("C:UserszhangwenchaoDesktopjinzhongzi.jpg"));
HttpEntity reqEntity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addPart("uploadFile", bin)
.setCharset(CharsetUtils.get("UTF-8"))
.build();
httppost.setEntity(reqEntity);
System.out.println("executing request: " + httppost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
System.out.println("Response content: " + EntityUtils.toString(resEntity));
}
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void download(String url) {
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpGet httpget = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpget);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
InputStream in = resEntity.getContent();
String fileName = url.substring(url.lastIndexOf("/"));
File file = new File("E:" + fileName);
try {
FileOutputStream fout = new FileOutputStream(file);
int l = -1;
byte[] tmp = new byte[1024];
while ((l = in.read(tmp)) != -1) {
fout.write(tmp, 0, l);
}
fout.flush();
fout.close();
} finally {
in.close();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
十九. 分页工具类
分页是后台系统的标配。这个 PageUtils 封装了总记录数、每页大小、总页数、当前页和分页数据,使用起来很直观。
import ja va.io.Serializable;
import ja va.util.List;
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
private int totalCount;
private int pageSize;
private int totalPage;
private int currPage;
private List> list;
public PageUtils(List> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
// getters and setters omitted for brevity
}
二十. SQL查询工具类
在MyBatis中动态拼SQL时,排序字段容易产生SQL注入风险。下面这个工具类包含SQL过滤和查询参数封装,避免直接拼接。
1. SQL过滤
import org.apache.commons.lang.StringUtils;
public class SQLFilter {
public static String sqlInject(String str){
if(StringUtils.isBlank(str)){
return str;
}
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
str = str.toLowerCase();
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};
for(String keyword : keywords){
if(str.contains(keyword)){
throw new RuntimeException("包含非法字符");
}
}
return str;
}
}
2. SQL查询
import ja va.util.LinkedHashMap;
import ja va.util.Map;
public class Q extends LinkedHashMap {
private static final long serialVersionUID = 1L;
private int page;
private int limit;
public Q(Map params){
this.putAll(params);
String sidx = "";
String order = "";
if(params.get("page")!=null) {
this.page = Integer.parseInt(params.get("page").toString());
}
if(params.get("limit")!=null) {
this.limit = Integer.parseInt(params.get("limit").toString());
}
if(params.get("sidx")!=null) {
sidx = params.get("sidx").toString();
}
if(params.get("order")!=null) {
order = params.get("order").toString();
}
this.put("offset", (page - 1) * limit);
this.put("page", page);
this.put("limit", limit);
if(params.get("limit")==null) {
this.put("limit", null);
}
this.put("sidx", SQLFilter.sqlInject(sidx));
this.put("order", SQLFilter.sqlInject(order));
}
public Q() {
this.put("page", page);
this.put("limit", null);
this.put("sidx", "");
this.put("order", "");
}
// getters and setters omitted
}
3. mapper文件中查询列表可以这么写
二十一. Shiro工具类
Apache Shiro 是Ja va常见的权限框架。下面这个工具类封装了获取Session、Subject、当前用户信息、验证码等常见操作。
1. Ma ven导包
org.apache.shiro
shiro-core
1.3.2
org.apache.shiro
shiro-spring
1.3.2
org.apache.shiro
shiro-ehcache
1.3.2
2. 工具类
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
public class ShiroUtils {
public static Session getSession() {
return SecurityUtils.getSubject().getSession();
}
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
public static SysUserEntity getUserEntity() {
return (SysUserEntity)SecurityUtils.getSubject().getPrincipal();
}
public static Long getUserId() {
return getUserEntity().getUserId();
}
public static void setSessionAttribute(Object key, Object value) {
getSession().setAttribute(key, value);
}
public static Object getSessionAttribute(Object key) {
return getSession().getAttribute(key);
}
public static boolean isLogin() {
return SecurityUtils.getSubject().getPrincipal() != null;
}
public static void logout() {
SecurityUtils.getSubject().logout();
}
public static String getKaptcha(String key) {
String kaptcha = getSessionAttribute(key).toString();
getSession().removeAttribute(key);
return kaptcha;
}
}
二十二. SpringContext工具类
有时候我们需要在非Spring管理的类中获取Bean,实现 ApplicationContextAware 接口是最常用的方式。工具类如下:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static T getBean(String name, Class requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
二十三. Properties载入工具类
读取properties配置文件时,这个工具类可以指定多个文件,并支持UTF-8编码,避免中文乱码。
1. 工具类如下
import ja va.io.IOException;
import ja va.io.InputStreamReader;
import ja va.util.Properties;
public class PropertiesLoader {
private final Properties properties;
public PropertiesLoader(String... resourcePaths) {
properties = loadProperties(resourcePaths);
}
private Properties loadProperties(String[] resourcePaths) {
Properties props = new Properties();
for (String location : resourcePaths) {
InputStreamReader is = null;
try {
is = new InputStreamReader(
PropertiesLoader.class.getClassLoader().getResourceAsStream(location), "UTF-8");
props.load(is);
} catch (Exception e) {
} finally {
try {
is.close();
} catch (IOException e) {
}
}
}
return props;
}
public String getConfig(String key) {
if (properties.containsKey(key)) {
return properties.getProperty(key);
}
return "";
}
public int getIntConfig(String key) {
return Integer.parseInt(getConfig(key));
}
}
2. 使用
public static PropertiesLoader loader = new PropertiesLoader("config/config.properties");
public void test() {
String content = loader.getConfig("content");
}
二十四. Ja va执行Bat命令(或其他命令)
有时候需要从Ja va调用外部脚本(比如批处理)。下面这个工具类通过 ProcessBuilder 执行bat文件,并通过判断输出中的特定标记来确认执行结果。
import ja va.io.BufferedReader;
import ja va.io.IOException;
import ja va.io.InputStreamReader;
import ja va.nio.charset.StandardCharsets;
public class BatUtils {
public static boolean doBat(String batPath, String... args) {
boolean result = false;
String[] command;
if (args == null || args.length == 0) {
command = new String[]{batPath};
} else {
command = new String[args.length + 1];
command[0] = batPath;
System.arraycopy(args, 0, command, 1, args.length);
}
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
try {
Process process = processBuilder.start();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
if (line.contains("Bat Finished! ")) {
line = bufferedReader.readLine();
System.out.println(line);
if (line.contains("Bat Success! ")) {
result = true;
} else if (line.contains("Bat Fail! ")){
// result remains false
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
二十五. 不使用Request获得Web项目的全路径
在非Web环境下(比如工具类中)获取class文件的绝对路径,可以用 getResource("").getFile()。注意返回的路径前后都带有斜杠。
String path = Test.class.getResource("").getFile();
假如Test.class类文件在blog项目的 com/paulandcode/utils 目录下,则上面的path值为:
/D:/Tomcat/webapps/blog/WEB-INF/classes/com/paulandcode/utils/
二十六. 下划线与驼峰相互转换
数据库字段通常采用下划线命名(如 user_name),而Ja va实体类则使用驼峰(如 userName)。这个工具类支持数组和Map的键转换。
import ja va.util.HashMap;
import ja va.util.Map;
public class HumpUtils {
private static final char UNDERLINE = '_';
public static String[] arrUnderlineToHump(String[] arr) {
if (arr == null) return null;
String[] newArr = new String[arr.length];
for (int i = 0; i < arr.length; i++) {
newArr[i] = toHump(arr[i]);
}
return newArr;
}
public static String[] arrHumpToUnderline(String[] arr) {
if (arr == null) return null;
String[] newArr = new String[arr.length];
for (int i = 0; i < arr.length; i++) {
newArr[i] = toUnderline(arr[i]);
}
return newArr;
}
public static Map mapKeyUnderlineToHump(Map map) {
if (map == null) return null;
Map newMap = new HashMap<>(map.size());
for (Map.Entry entry : map.entrySet()) {
newMap.put(toHump(entry.getKey()), entry.getValue());
}
return newMap;
}
public static Map mapKeyHumpToUnderline(Map map) {
if (map == null) return null;
Map newMap = new HashMap<>(map.size());
for (Map.Entry entry : map.entrySet()) {
newMap.put(toUnderline(entry.getKey()), entry.getValue());
}
return newMap;
}
public static String toHump(String colName) {
if (colName == null) return null;
StringBuilder sb = new
