Aspect基于spingmvc自定义注解实现操作记录
程序员文章站
2022-06-21 17:06:18
现在做的项目中用到了日志记录功能,整理了一下,发出来,也是做个记录:相关jar包百度云下载 1.自定义注解类 SystemControllerLog.java import java.lang.annotation.ElementType; import java.lang.annotation.R ......
现在做的项目中用到了日志记录功能,整理了一下,发出来,也是做个记录:
1.自定义注解类 SystemControllerLog.java
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义注解 拦截Controller * * @author Administrator * */ @Target({ ElementType.PARAMETER, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface SystemControllerLog { /** * 描述业务操作 例:Xxx管理-执行Xxx操作 * @return */ String description() default ""; }
2.日志处理类 SystemLogAspect.java
import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.NamedThreadLocal; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import com.zw.annotation.SystemControllerLog; import com.zw.aop.SystemLogAspect; import com.zw.model.Logs; import com.zw.model.User; import com.zw.service.LogsService; import com.zw.util.AcquireIp; import com.zw.util.DateUtils; /** * 系统日志切面类 * */ @Aspect @Component public class SystemLogAspect { private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class); private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime"); private static final ThreadLocal<Logs> logThreadLocal = new NamedThreadLocal<Logs>("ThreadLocal log"); private static final ThreadLocal<User> currentUser=new NamedThreadLocal<>("ThreadLocal authUser"); @Resource private HttpServletRequest request; @Resource(name="logsServiceImpl") private LogsService logsService; @Resource private ThreadPoolTaskExecutor threadPoolTaskExecutor; /** * Controller层切点 注解拦截 */ @Pointcut("@annotation(com.ht.annotation.SystemControllerLog)") public void controllerAspect(){} /** * 方法规则拦截 */ @Pointcut("execution(* com.ht.controller.*.*(..))") public void controllerPointerCut(){} /** * 前置通知 用于拦截Controller层记录用户的操作的开始时间 * @param joinPoint 切点 * @throws InterruptedException */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) throws InterruptedException{ Date beginTime=new Date(); beginTimeThreadLocal.set(beginTime); //debug模式下 显式打印开始时间用于调试 if (logger.isDebugEnabled()){ logger.debug("开始计时: {} URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") .format(beginTime), request.getRequestURI()); } //读取session中的用户 HttpSession session = request.getSession(); User authUser = (User) session.getAttribute("user"); currentUser.set(authUser); } /** * 后置通知 用于拦截Controller层记录用户的操作 * @param joinPoint 切点 */ @After("controllerAspect()") public void doAfter(JoinPoint joinPoint) { User User = currentUser.get(); //登入login操作 前置通知时用户未校验 所以session中不存在用户信息 if(User == null){ HttpSession session = request.getSession(); User = (User) session.getAttribute("user"); if(User==null){ return; } } Object [] args = joinPoint.getArgs(); System.out.println(args); String title=""; String type="info"; //日志类型(info:入库,error:错误) String remoteAddr=AcquireIp.getIP(request);//请求的IP String requestUri=request.getRequestURI();//请求的Uri String method=request.getMethod(); //请求的方法类型(post/get) Map<String,String[]> params=request.getParameterMap(); //请求提交的参数 try { title=getControllerMethodDescription2(joinPoint); } catch (Exception e) { e.printStackTrace(); } // debu模式下打印JVM信息。 long beginTime = beginTimeThreadLocal.get().getTime();//得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); //2、结束时间 if (logger.isDebugEnabled()){ Object[] obj = new Object[7]; obj[0] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(endTime); obj[1] = request.getRequestURI(); obj[2] = DateUtils.formatDateTime(endTime - beginTime); obj[3] = Runtime.getRuntime().maxMemory()/1024/1024; obj[4] = Runtime.getRuntime().totalMemory()/1024/1024; obj[5] = Runtime.getRuntime().freeMemory()/1024/1024; obj[6] = (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024; logger.debug("计时结束:{} URI: {} 耗时: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m",obj); } //获取数据 Logs log = new Logs(); log.setTitle(title); log.setType(type); log.setRemoteAddr(remoteAddr); log.setRequestUri(requestUri); log.setMethod(method); log.setMapToParams(params); log.setUserId(String.valueOf(User.getId())); Date operateDate=beginTimeThreadLocal.get(); log.setOperateDate(operateDate); log.setTimeout(DateUtils.formatDateTime(endTime - beginTime)); //1.直接执行保存操作 //this.logService.createSystemLog(log); //2.优化:异步保存日志 //new SaveLogThread(log, logService).start(); //3.再优化:通过线程池来执行日志保存 threadPoolTaskExecutor.execute(new SaveLogThread(log, logsService)); logThreadLocal.set(log); } /** * 异常通知 * @param joinPoint * @param e */ @AfterThrowing(pointcut = "controllerAspect()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { Logs logs = logThreadLocal.get(); if(logs != null){ logs.setType("error"); logs.setException(e.toString()); new UpdateLogThread(logs, logsService).start(); } } /** * 获取注解中对方法的描述信息 用于Controller层注解 * * @param joinPoint 切点 * @return 方法描述 */ public static String getControllerMethodDescription2(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SystemControllerLog controllerLog = method .getAnnotation(SystemControllerLog.class); String discription = controllerLog.description(); return discription; } /** * 保存日志线程 * * @author l * */ private static class SaveLogThread implements Runnable { private Logs logs; private LogsService logsService; public SaveLogThread(Logs logs, LogsService logsService) { this.logs = logs; this.logsService = logsService; } @Override public void run() { logsService.insert(logs); } } /** * 日志更新线程 * * @author l * */ private static class UpdateLogThread extends Thread { private Logs logs; private LogsService logsService; public UpdateLogThread(Logs logs, LogsService logsService) { super(UpdateLogThread.class.getSimpleName()); this.logs = logs; this.logsService = logsService; } @Override public void run() { this.logsService.insert(logs); } } }
3.spring的xml添加
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
启用注解,扫描controller层
<!-- 启动对@AspectJ注解的支持 --> <aop:aspectj-autoproxy/> <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 --> <context:component-scan base-package="com.zw"></context:component-scan>
配置日志
<!-- 配置日志 --> <bean id ="threadPoolTaskExecutor" class ="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" > <property name ="corePoolSize" value ="5" /> <!--核心线程数 --> <property name ="keepAliveSeconds" value ="3000" /> <!-- 某线程空闲超过这个时间,就回收该线程 --> <property name ="maxPoolSize" value ="10" /> <!--最大线程数 --> <property name ="queueCapacity" value ="1000" /> <!-- 队列大小 --> <property name= "rejectedExecutionHandler" > <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 --> <!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 --> <!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <bean class = "java.util.concurrent.ThreadPoolExecutor$DiscardPolicy" /> </property> </bean>
4.Controller中使用自定义注解
5.建立日志实体类,建立logs表(关于mapper,service那些就省略了)
import java.io.Serializable; import java.util.Date; import java.util.Map; import com.zw.util.StringUtils; /** * 用于记录日志的实体类 * */ public class Logs implements Serializable{ private static final long serialVersionUID = 1L; /** * 日志主键 * */ private Integer id; /** * 日志类型 * */ private String type; /** * 日志标题 * */ private String title; /** * 请求ip地址 * */ private String remoteAddr; /** * 访问路径 * */ private String requestUri; /** * 请求方式 * */ private String method; /** * 请求参数 * */ private String params; /** * 异常 * */ private String exception; /** * 日志开始时间 * */ private Date operateDate; /** * 日志结束时间 * */ private String timeout; /** * 用户id * */ private String userId; public Logs() { super(); } public Logs(Integer id, String type, String title, String remoteAddr, String requestUri, String method, String params, String exception, Date operateDate, String timeout, String userId) { super(); this.id = id; this.type = type; this.title = title; this.remoteAddr = remoteAddr; this.requestUri = requestUri; this.method = method; this.params = params; this.exception = exception; this.operateDate = operateDate; this.timeout = timeout; this.userId = userId; } @Override public String toString() { return "Logs [id=" + id + ", type=" + type + ", title=" + title + ", remoteAddr=" + remoteAddr + ", requestUri=" + requestUri + ", method=" + method + ", params=" + params + ", exception=" + exception + ", operateDate=" + operateDate + ", timeout=" + timeout + ", userId=" + userId + "]"; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getType() { return StringUtils.isBlank(type) ? type : type.trim(); } public void setType(String type) { this.type = type; } public String getTitle() { return StringUtils.isBlank(title) ? title : title.trim(); } public void setTitle(String title) { this.title = title; } public String getRemoteAddr() { return StringUtils.isBlank(remoteAddr) ? remoteAddr : remoteAddr.trim(); } public void setRemoteAddr(String remoteAddr) { this.remoteAddr = remoteAddr; } public String getRequestUri() { return StringUtils.isBlank(requestUri) ? requestUri : requestUri.trim(); } public void setRequestUri(String requestUri) { this.requestUri = requestUri; } public String getMethod() { return StringUtils.isBlank(method) ? method : method.trim(); } public void setMethod(String method) { this.method = method; } public String getParams() { return StringUtils.isBlank(params) ? params : params.trim(); } public void setParams(String params) { this.params = params; } /** * 设置请求参数 * @param paramMap */ public void setMapToParams(Map<String, String[]> paramMap) { if (paramMap == null){ return; } StringBuilder params = new StringBuilder(); for (Map.Entry<String, String[]> param : ((Map<String, String[]>)paramMap).entrySet()){ params.append(("".equals(params.toString()) ? "" : "&") + param.getKey() + "="); String paramValue = (param.getValue() != null && param.getValue().length > 0 ? param.getValue()[0] : ""); params.append(StringUtils.abbr(StringUtils.endsWithIgnoreCase(param.getKey(), "password") ? "" : paramValue, 100)); } this.params = params.toString(); } public String getException() { return StringUtils.isBlank(exception) ? exception : exception.trim(); } public void setException(String exception) { this.exception = exception; } public Date getOperateDate() { return operateDate; } public void setOperateDate(Date operateDate) { this.operateDate = operateDate; } public String getTimeout() { return StringUtils.isBlank(timeout) ? timeout : timeout.trim(); } public void setTimeout(String timeout) { this.timeout = timeout; } public String getUserId() { return StringUtils.isBlank(userId) ? userId : userId.trim(); } public void setUserId(String userId) { this.userId = userId; } }
6.最后用到的工具类
AcquireIp.java
View Code
import javax.servlet.http.HttpServletRequest; /** * 获取ip? * */ public class AcquireIp { public static String getIP(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (!checkIP(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (!checkIP(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (!checkIP(ip)) { ip = request.getRemoteAddr(); } return ip; } private static boolean checkIP(String ip) { if (ip == null || ip.length() == 0 || "unkown".equalsIgnoreCase(ip) || ip.split(".").length != 4) { return false; } return true; } }
DateUtils.java
View Code
import java.text.ParseException; import java.util.Date; import org.apache.commons.lang3.time.DateFormatUtils; /** * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类 * @author ThinkGem * @version 2014-4-15 */ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; /** * 得到当前日期字符串 格式(yyyy-MM-dd) */ public static String getDate() { return getDate("yyyy-MM-dd"); } /** * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" */ public static String getDate(String pattern) { return DateFormatUtils.format(new Date(), pattern); } /** * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" */ public static String formatDate(Date date, Object... pattern) { String formatDate = null; if (pattern != null && pattern.length > 0) { formatDate = DateFormatUtils.format(date, pattern[0].toString()); } else { formatDate = DateFormatUtils.format(date, "yyyy-MM-dd"); } return formatDate; } /** * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss) */ public static String formatDateTime(Date date) { return formatDate(date, "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前时间字符串 格式(HH:mm:ss) */ public static String getTime() { return formatDate(new Date(), "HH:mm:ss"); } /** * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss) */ public static String getDateTime() { return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前年份字符串 格式(yyyy) */ public static String getYear() { return formatDate(new Date(), "yyyy"); } /** * 得到当前月份字符串 格式(MM) */ public static String getMonth() { return formatDate(new Date(), "MM"); } /** * 得到当天字符串 格式(dd) */ public static String getDay() { return formatDate(new Date(), "dd"); } /** * 得到当前星期字符串 格式(E)星期几 */ public static String getWeek() { return formatDate(new Date(), "E"); } /** * 日期型字符串转化为日期 格式 * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", * "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", * "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" } */ public static Date parseDate(Object str) { if (str == null){ return null; } try { return parseDate(str.toString(), parsePatterns); } catch (ParseException e) { return null; } } /** * 获取过去的天数 * @param date * @return */ public static long pastDays(Date date) { long t = new Date().getTime()-date.getTime(); return t/(24*60*60*1000); } /** * 获取过去的小时 * @param date * @return */ public static long pastHour(Date date) { long t = new Date().getTime()-date.getTime(); return t/(60*60*1000); } /** * 获取过去的分钟 * @param date * @return */ public static long pastMinutes(Date date) { long t = new Date().getTime()-date.getTime(); return t/(60*1000); } /** * 转换为时间(天,时:分:秒.毫秒) * @param timeMillis * @return */ public static String formatDateTime(long timeMillis){ long day = timeMillis/(24*60*60*1000); long hour = (timeMillis/(60*60*1000)-day*24); long min = ((timeMillis/(60*1000))-day*24*60-hour*60); long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60); long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000); return (day>0?day+",":"")+hour+":"+min+":"+s+"."+sss; } /** * 获取两个日期之间的天数 * * @param before * @param after * @return */ public static double getDistanceOfTwoDate(Date before, Date after) { long beforeTime = before.getTime(); long afterTime = after.getTime(); return (afterTime - beforeTime) / (1000 * 60 * 60 * 24); } /** * @param args * @throws ParseException */ public static void main(String[] args) throws ParseException { // System.out.println(formatDate(parseDate("2010/3/6"))); // System.out.println(getDate("yyyy年MM月dd日 E")); // long time = new Date().getTime()-parseDate("2012-11-19").getTime(); // System.out.println(time/(24*60*60*1000)); } }
StringUtils.java
View Code
import java.io.UnsupportedEncodingException; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringEscapeUtils; /** * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 * @author ThinkGem * @version 2013-05-22 */ public class StringUtils extends org.apache.commons.lang3.StringUtils { private static final char SEPARATOR = '_'; private static final String CHARSET_NAME = "UTF-8"; /** * 转换为字节数组 * @param str * @return */ public static byte[] getBytes(String str){ if (str != null){ try { return str.getBytes(CHARSET_NAME); } catch (UnsupportedEncodingException e) { return null; } }else{ return null; } } /** * 转换为字节数组 * @param str * @return */ public static String toString(byte[] bytes){ try { return new String(bytes, CHARSET_NAME); } catch (UnsupportedEncodingException e) { return EMPTY; } } /** * 是否包含字符串 * @param str 验证字符串 * @param strs 字符串组 * @return 包含返回true */ public static boolean inString(String str, String... strs){ if (str != null){ for (String s : strs){ if (str.equals(trim(s))){ return true; } } } return false; } /** * 替换掉HTML标签方法 */ public static String replaceHtml(String html) { if (isBlank(html)){ return ""; } String regEx = "<.+?>"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(html); String s = m.replaceAll(""); return s; } /** * 替换为手机识别的HTML,去掉样式及属性,保留回车。 * @param html * @return */ public static String replaceMobileHtml(String html){ if (html == null){ return ""; } return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>"); } /** * 替换为手机识别的HTML,去掉样式及属性,保留回车。 * @param txt * @return */ /*public static String toHtml(String txt){ if (txt == null){ return ""; } return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", " "); }*/ /** * 缩略字符串(不区分中英文字符) * @param str 目标字符串 * @param length 截取长度 * @return */ public static String abbr(String str, int length) { if (str == null) { return ""; } try { StringBuilder sb = new StringBuilder(); int currentLength = 0; for (char c : replaceHtml(StringEscapeUtils.unescapeHtml(str)).toCharArray()) { currentLength += String.valueOf(c).getBytes("GBK").length; if (currentLength <= length - 3) { sb.append(c); } else { sb.append("..."); break; } } return sb.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 转换为Double类型 */ public static Double toDouble(Object val){ if (val == null){ return 0D; } try { return Double.valueOf(trim(val.toString())); } catch (Exception e) { return 0D; } } /** * 转换为Float类型 */ public static Float toFloat(Object val){ return toDouble(val).floatValue(); } /** * 转换为Long类型 */ public static Long toLong(Object val){ return toDouble(val).longValue(); } /** * 转换为Integer类型 */ public static Integer toInteger(Object val){ return toLong(val).intValue(); } /** * 获得i18n字符串 */ /* public static String getMessage(String code, Object[] args) { LocaleResolver localLocaleResolver = (LocaleResolver) SpringContextHolder.getBean(LocaleResolver.class); HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); Locale localLocale = localLocaleResolver.resolveLocale(request); return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale); }*/ /** * 获得用户远程地址 */ public static String getRemoteAddr(HttpServletRequest request){ String remoteAddr = request.getHeader("X-Real-IP"); if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("X-Forwarded-For"); }else if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("Proxy-Client-IP"); }else if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("WL-Proxy-Client-IP"); } return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); } /** * 驼峰命名法工具 * @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCamelCase(String s) { if (s == null) { return null; } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } /** * 驼峰命名法工具 * @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCapitalizeCamelCase(String s) { if (s == null) { return null; } s = toCamelCase(s); return s.substring(0, 1).toUpperCase() + s.substring(1); } /** * 驼峰命名法工具 * @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toUnderScoreCase(String s) { if (s == null) { return null; } StringBuilder sb = new StringBuilder(); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); boolean nextUpperCase = true; if (i < (s.length() - 1)) { nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); } if ((i > 0) && Character.isUpperCase(c)) { if (!upperCase || !nextUpperCase) { sb.append(SEPARATOR); } upperCase = true; } else { upperCase = false; } sb.append(Character.toLowerCase(c)); } return sb.toString(); } /** * 驼峰转下划线 (暂不建议使用toUnderScoreCase) * @param camelCaseName * @return */ public static String toUnderscoreName(String camelCaseName) { StringBuilder result = new StringBuilder(); if (camelCaseName != null && camelCaseName.length() > 0) { result.append(camelCaseName.substring(0, 1).toLowerCase()); for (int i = 1; i < camelCaseName.length(); i++) { char ch = camelCaseName.charAt(i); if (Character.isUpperCase(ch)) { result.append("_"); result.append(Character.toLowerCase(ch)); } else { result.append(ch); } } } return result.toString(); } /** * 如果不为空,则设置值 * @param target * @param source */ public static void setValueIfNotBlank(String target, String source) { if (isNotBlank(source)){ target = source; } } /** * 转换为JS获取对象值,生成三目运算返回结果 * @param objectString 对象串 * 例如:row.user.id * 返回:!row?'':!row.user?'':!row.user.id?'':row.user.id */ public static String jsGetVal(String objectString){ StringBuilder result = new StringBuilder(); StringBuilder val = new StringBuilder(); String[] vals = split(objectString, "."); for (int i=0; i<vals.length; i++){ val.append("." + vals[i]); result.append("!"+(val.substring(1))+"?'':"); } result.append(val.substring(1)); return result.toString(); } /** * 转换为utf-8字符串 * @param s * @return */ public static String toUtf8String(String s){ StringBuffer sb = new StringBuffer(); for (int i=0;i<s.length();i++){ char c = s.charAt(i); if (c >= 0 && c <= 255){ sb.append(c); }else{ byte[] b; try { b = Character.toString(c).getBytes("utf-8");} catch (Exception ex) { b = new byte[0]; } for (int j = 0; j < b.length; j++) { int k = b[j]; if (k < 0) k += 256; sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } }
数据库插入效果图:
建议使用了日志记录后,再用定时器定时清理过期日志,以免数据过多