访问Controller打印的日志效果如下:
*********************************Request请求***************************************
ClassName : com.xxx.app.xxx.action.xxxx
RequestMethod : createURL()
RequestParams : ["xxx","789"]
RequestType : POST
Description : 创建机器二维码图片URL
serverAddr : http://localhost:8090
RemoteAddr : 0:0:0:0:0:0:0:1
DeviceName : Unknown
BrowserName : Unknown
UserAgent : PostmanRuntime/3.0.9
RequestUri : /retail/xxxx/createURL
Result : {http://www.test.com/?msg=&mno=xxx&deviceid=789&acid=689277759a7c40ec81a8fb74cd5c153a, success=true}
Service抛出异常打印信息如下:
*********************************Service异常***************************************
ClassName : com.xxx.app.retail.service.impl.xxx
Method : com.xxx.app.retail.service.impl.xxxx.goodsSync()
Params : [{"deviceId":"123456789","itemId":"1","pictUrl":"1111","reservePrice":"3","title":"2"};]
Description : 贩卖机商品同步
ExceptionName : java.lang.ArithmeticException
ExceptionMessage : / by zero
步骤如下:
1)创建两个注解,分别用了对Controller和Service实现日志记录
ControllerLogs注解
/**
* @version: V1.0
* @author: fendo
* @className: ControllerLogs
* @packageName: com.xx.commons.web.annotation
* @description: Controller日志记录
* @data: 2018-05-21 15:58
**/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLogs {
/**
* 描述
*/
String description() default "";
}
ServiceLogs注解
/**
* @version: V1.0
* @author: fendo
* @className: ControllerLogs
* @packageName: com.xxxx.commons.web.annotation
* @description: Service日志记录
* @data: 2018-05-21 15:58
**/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceLogs {
/**
* 描述
*/
String description() default "";
}
2)创建切面LogAspect
/**
* projectName: xxxx
* fileName: LogAspect.java
* packageName: com.xxxx.logs.aop
* date: 2018-05-31 10:15
* copyright(c) xxxxxxxx
*/
package com.xxxx.utils.logs.aop;
import com.alibaba.fastjson.JSON;
import com.xxxx.utils.logs.annotation.ControllerLogs;
import com.xxxx.utils.logs.annotation.ServiceLogs;
import com.xxxx.utils.logs.utils.IpUtils;
import com.xxxx.utils.logs.utils.StringUtils;
import com.xxxx.utils.logs.utils.UserAgentUtils;
import eu.bitwalker.useragentutils.UserAgent;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @version: V1.0
* @author: fendo
* @className: LogAspect
* @packageName: com.xxxx.logs.aop
* @description: 日志切点
* @data: 2018-05-31 10:15
**/
@Aspect
@Configuration
public class LogAspect {
/**
* 本地异常日志记录对象
*/
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Service层切点
*/
@Pointcut("@annotation(com.xxxx.utils.logs.annotation.ServiceLogs)")
public void serviceAspect() {
}
/**
* Controller层切点
*/
@Pointcut("@annotation(com.xxxx.utils.logs.annotation.ControllerLogs)")
public void controllerAspect() {
}
/**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//类名
String className = joinPoint.getTarget().getClass().getName();
//请求方法
String method = joinPoint.getSignature().getName() + "()";
//方法参数
String methodParam = JSON.toJSONString(joinPoint.getArgs());
//方法描述
String methodDescription = getControllerMethodDescription(joinPoint);
StringBuilder sb = new StringBuilder(1000);
sb.append("\n");
sb.append("*********************************Request请求***************************************");
sb.append("\n");
sb.append("ClassName : ").append(className).append("\n");
sb.append("RequestMethod : ").append(method).append("\n");
sb.append("RequestParams : ").append(methodParam).append("\n");
sb.append("RequestType : ").append(request.getMethod()).append("\n");
sb.append("Description : ").append(methodDescription).append("\n");
sb.append("serverAddr : ").append(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()).append("\n");
sb.append("RemoteAddr : ").append(IpUtils.getRemoteAddr(request)).append("\n");
UserAgent userAgent = UserAgentUtils.getUserAgent(request);
sb.append("DeviceName : ").append(userAgent.getOperatingSystem().getName()).append("\n");
sb.append("BrowserName : ").append(userAgent.getBrowser().getName()).append("\n");
sb.append("UserAgent : ").append(request.getHeader("User-Agent")).append("\n");
sb.append("RequestUri : ").append(StringUtils.abbr(request.getRequestURI(), 255)).append("\n");
logger.info(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
@AfterReturning(returning = "ret", pointcut = "controllerAspect()")
public void doAfterReturning(Object ret) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//请求方法
String method = StringUtils.abbr(request.getRequestURI(), 255);
StringBuilder sb = new StringBuilder(1000);
// 处理完请求,返回内容
sb.append("\n");
sb.append("Result : ").append(ret);
logger.info(sb.toString());
}
/**
* 异常通知 用于拦截service层记录异常日志
*
* @param joinPoint
* @param ex
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//类名
String className = joinPoint.getTarget().getClass().getName();
//请求方法
String method = (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
//方法参数
String methodParam = Arrays.toString(joinPoint.getArgs());
//方法描述
String methodDescription = getServiceMthodDescription(joinPoint);
//获取用户请求方法的参数并序列化为JSON格式字符串
String params = "";
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
}
}
StringBuilder sb = new StringBuilder(1000);
sb.append("\n");
sb.append("*********************************Service异常***************************************");
sb.append("\n");
sb.append("ClassName : ").append(className).append("\n");
sb.append("Method : ").append(method).append("\n");
sb.append("Params : ").append("[" + params + "]").append("\n");
sb.append("Description : ").append(methodDescription).append("\n");
sb.append("ExceptionName : ").append(ex.getClass().getName()).append("\n");
sb.append("ExceptionMessage : ").append(ex.getMessage()).append("\n");
logger.info(sb.toString());
} catch (Exception e1) {
e1.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于service层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(ServiceLogs.class).description();
break;
}
}
}
return description;
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(ControllerLogs.class).description();
break;
}
}
}
return description;
}
}
3)几个工具类
DateUtils
/**
* projectName: xxxx
* fileName: DateUtils.java
* packageName: utils
* date: 2018-05-30 17:29
* copyright(c) xxxx
*/
package com.xxxx.utils.logs.utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
/**
* @version: V1.0
* @author: fendo
* @className: DateUtils
* @packageName: utils
* @description: 日期工具类
* @data: 2018-05-30 17:29
**/
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-dd HH", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH", "yyyy.MM",
"yyyy年MM月dd日", "yyyy年MM月dd日 HH时mm分ss秒", "yyyy年MM月dd日 HH时mm分", "yyyy年MM月dd日 HH时", "yyyy年MM月",
"yyyy"};
/**
* 得到日期字符串 ,转换格式(yyyy-MM-dd)
*/
public static String formatDate(Date date) {
return formatDate(date, "yyyy-MM-dd");
}
/**
* 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
*/
public static String formatDate(long dateTime, String pattern) {
return formatDate(new Date(dateTime), pattern);
}
/**
* 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
*/
public static String formatDate(Date date, String pattern) {
String formatDate = null;
if (date != null){
if (StringUtils.isBlank(pattern)) {
pattern = "yyyy-MM-dd";
}
formatDate = FastDateFormat.getInstance(pattern).format(date);
}
return formatDate;
}
/**
* 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss)
*/
public static String formatDateTime(Date date) {
return formatDate(date, "yyyy-MM-dd HH:mm:ss");
}
/**
* 得到当前日期字符串 格式(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 FastDateFormat.getInstance(pattern).format(new Date());
}
/**
* 得到当前日期前后多少天,月,年的日期字符串
* @param pattern 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
* @param amont 数量,前为负数,后为正数
* @param type 类型,可参考Calendar的常量(如:Calendar.HOUR、Calendar.MINUTE、Calendar.SECOND)
* @return
*/
public static String getDate(String pattern, int amont, int type) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(type, amont);
return FastDateFormat.getInstance(pattern).format(calendar.getTime());
}
/**
* 得到当前时间字符串 格式(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");
}
/**
* 日期型字符串转化为日期 格式 see to DateUtils#parsePatterns
*/
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 = System.currentTimeMillis()-date.getTime();
return t/(24*60*60*1000);
}
/**
* 获取过去的小时
* @param date
* @return
*/
public static long pastHour(Date date) {
long t = System.currentTimeMillis()-date.getTime();
return t/(60*60*1000);
}
/**
* 获取过去的分钟
* @param date
* @return
*/
public static long pastMinutes(Date date) {
long t = System.currentTimeMillis()-date.getTime();
return t/(60*1000);
}
/**
* 获取两个日期之间的天数
*
* @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 date 日期
* @return 天数
*/
public static int getMonthHasDays(Date date){
String yyyyMM = FastDateFormat.getInstance("yyyyMM").format(date);
String year = yyyyMM.substring(0, 4);
String month = yyyyMM.substring(4, 6);
String day31 = ",01,03,05,07,08,10,12,";
String day30 = "04,06,09,11";
int day = 0;
if (day31.contains(month)) {
day = 31;
} else if (day30.contains(month)) {
day = 30;
} else {
int y = Integer.parseInt(year);
if ((y % 4 == 0 && (y % 100 != 0)) || y % 400 == 0) {
day = 29;
} else {
day = 28;
}
}
return day;
}
/**
* 获取日期是当年的第几周
* @param date
* @return
*/
public static int getWeekOfYear(Date date){
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.WEEK_OF_YEAR);
}
/**
* 获取一天的开始时间(如:2015-11-3 00:00:00.000)
* @param date 日期
* @return
*/
public static Date getOfDayFirst(Date date) {
if (date == null){
return null;
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
/**
* 获取一天的最后时间(如:2015-11-3 23:59:59.999)
* @param date 日期
* @return
*/
public static Date getOfDayLast(Date date) {
if (date == null){
return null;
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar.getTime();
}
/**
* 获取服务器启动时间
* @return
*/
public static Date getServerStartDate(){
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 格式化为日期范围字符串
* @param beginDate 2018-01-01
* @param endDate 2018-01-31
* @return 2018-01-01 ~ 2018-01-31
*/
public static String formatDateBetweenString(Date beginDate, Date endDate){
String begin = DateUtils.formatDate(beginDate);
String end = DateUtils.formatDate(endDate);
if (StringUtils.isNoneBlank(begin, end)){
return begin + " ~ " + end;
}
return null;
}
/**
* 解析日期范围字符串为日期对象
* @param dateString 2018-01-01 ~ 2018-01-31
* @return new Date[]{2018-01-01, 2018-01-31}
*/
public static Date[] parseDateBetweenString(String dateString){
Date beginDate = null; Date endDate = null;
if (StringUtils.isNotBlank(dateString)){
String[] ss = StringUtils.split(dateString, "~");
if (ss != null && ss.length == 2){
String begin = StringUtils.trim(ss[0]);
String end = StringUtils.trim(ss[1]);
if (StringUtils.isNoneBlank(begin, end)){
beginDate = DateUtils.parseDate(begin);
endDate = DateUtils.parseDate(end);
}
}
}
return new Date[]{beginDate, endDate};
}
}
IpUtils类:
/**
* projectName: xxxx
* fileName: IpUtils.java
* packageName: com.xxxx.logs.utils
* date: 2018-05-31 10:48
* copyright(c) xxxx
*/
package com.xxxx.utils.logs.utils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* @version: V1.0
* @author: fendo
* @className: IpUtils
* @packageName: com.xxxx.logs.utils
* @description: IP工具类
* @data: 2018-05-31 10:48
**/
public class IpUtils {
/**
* 获取客户端IP地址
* @param request
* @return
*/
public static String getRemoteAddr(HttpServletRequest request) {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return StringUtils.split(ObjectUtils.toString(ip), ",")[0];
}
}
StringUtils类:
/**
* projectName: xxxx
* fileName: StringUtils.java
* packageName: com.xxxx.logs.utils
* date: 2018-05-31 10:53
* copyright(c) xxxx
*/
package com.xxxx.utils.logs.utils;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
* @version: V1.0
* @author: fendo
* @className: StringUtils
* @packageName: com.xxxx.logs.utils
* @description: 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
* @data: 2018-05-31 10:53
**/
public class StringUtils {
/**
* 替换掉HTML标签方法
*/
public static String stripHtml(String html) {
if (isBlank(html)){
return "";
}
String regEx = "<.+?>";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(html);
String s = m.replaceAll("");
return s;
}
/**
* 缩略字符串(不区分中英文字符)
* @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 : stripHtml(StringEscapeUtils.unescapeHtml4(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 "";
}
}
TimeUtils类:
/**
* projectName: xxxx
* fileName: TimeUtils.java
* packageName: utils
* date: 2018-05-30 17:31
* copyright(c) xxxx
*/
package com.xxxx.utils.logs.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.Arrays;
import java.util.Date;
/**
* @version: V1.0
* @author: fendo
* @className: TimeUtils
* @packageName: utils
* @description: 时间计算工具类
* @data: 2018-05-30 17:31
**/
public class TimeUtils {
/**
* 将时间转换为字符串(xx天,xx时,xx分,xx秒,大于360天显示日期时间)
*/
public static String formatDateAgo(long dateTime) {
StringBuilder sb = new StringBuilder();
if (dateTime < 1000){
sb.append(dateTime).append("毫秒");
}else{
TimeUtils t = new TimeUtils(dateTime);
int day = t.get(TimeUtils.DAY);
int hour = t.get(TimeUtils.HOUR);
int minute = t.get(TimeUtils.MINUTE);
int second = t.get(TimeUtils.SECOND);
if (day > 365){
return DateUtils.formatDate(new Date(dateTime), "yyyy年MM月dd日 HH时mm分ss秒");
}
if (day > 0){
sb.append(day).append("天");
}
if (hour > 0){
sb.append(hour).append("时");
}
if (minute > 0){
sb.append(minute).append("分");
}
if (second > 0){
sb.append(second).append("秒");
}
}
return sb.toString();
}
/**
* 将过去的时间转为为,刚刚,xx秒,xx分钟,xx小时前、xx天前,大于3天的显示日期
*/
public static String formatTimeAgo(String dateTime) {
return formatTimeAgo(DateUtils.parseDate(dateTime));
}
/**
* 将过去的时间转为为,刚刚,xx秒,xx分钟,xx小时前、xx天前,大于3天的显示日期
*/
public static String formatTimeAgo(Date dateTime) {
String interval = null;
// 得出的时间间隔是毫秒
long time = System.currentTimeMillis() - dateTime.getTime();
// 如果时间间隔小于10秒则显示“刚刚”time/10得出的时间间隔的单位是秒
if (time / 1000 < 10 && time / 1000 >= 0) {
interval = "刚刚";
}
// 如果时间间隔大于24小时则显示多少天前
else if (time / 3600000 < 24*4 && time / 3600000 >= 24) {
int d = (int) (time / (3600000*24));// 得出的时间间隔的单位是天
interval = d + "天前";
}
// 如果时间间隔小于24小时则显示多少小时前
else if (time / 3600000 < 24 && time / 3600000 >= 1) {
int h = (int) (time / 3600000);// 得出的时间间隔的单位是小时
interval = h + "小时前";
}
// 如果时间间隔小于60分钟则显示多少分钟前
else if (time / 60000 < 60 && time / 60000 >=1) {
int m = (int) ((time % 3600000) / 60000);// 得出的时间间隔的单位是分钟
interval = m + "分钟前";
}
// 如果时间间隔小于60秒则显示多少秒前
else if (time / 1000 < 60 && time / 1000 >=10) {
int se = (int) ((time % 60000) / 1000);
interval = se + "秒前";
}
// 大于3天的,则显示正常的时间,但是不显示秒
else {
interval = DateUtils.formatDate(dateTime,"yyyy-MM-dd");
}
return interval;
}
/**
* 时间字段常量,表示“秒”
*/
public final static int SECOND = 0;
/**
* 时间字段常量,表示“分”
*/
public final static int MINUTE = 1;
/**
* 时间字段常量,表示“时”
*/
public final static int HOUR = 2;
/**
* 时间字段常量,表示“天”
*/
public final static int DAY = 3;
/**
* 各常量允许的最大值
*/
private final int[] maxFields = { 59, 59, 23, Integer.MAX_VALUE - 1 };
/**
* 各常量允许的最小值
*/
private final int[] minFields = { 0, 0, 0, Integer.MIN_VALUE };
/**
* 默认的字符串格式时间分隔符
*/
private String timeSeparator = ":";
/**
* 时间数据容器
*/
private int[] fields = new int[4];
/**
* 无参构造,将各字段置为 0
*/
public TimeUtils() {
this(0, 0, 0, 0);
}
/**
* 使用时、分构造一个时间
* @param hour 小时
* @param minute 分钟
*/
public TimeUtils(int hour, int minute) {
this(0, hour, minute, 0);
}
/**
* 使用时、分、秒构造一个时间
* @param hour 小时
* @param minute 分钟
* @param second 秒
*/
public TimeUtils(int hour, int minute, int second) {
this(0, hour, minute, second);
}
/**
* 使用一个字符串构造时间<br>
* Time time = new Time("14:22:23");
* @param time 字符串格式的时间,默认采用“:”作为分隔符
*/
public TimeUtils(String time) {
this(time, null);
}
/**
* 使用时间毫秒构建时间
* @param time
*/
public TimeUtils(long time){
this(new Date(time));
}
/**
* 使用日期对象构造时间
* @param date
*/
public TimeUtils(Date date){
this(DateFormatUtils.formatUTC(date, "HH:mm:ss"));
}
/**
* 使用天、时、分、秒构造时间,进行全字符的构造
* @param day 天
* @param hour 时
* @param minute 分
* @param second 秒
*/
public TimeUtils(int day, int hour, int minute, int second) {
initialize(day, hour, minute, second);
}
/**
* 使用一个字符串构造时间,指定分隔符<br>
* Time time = new Time("14-22-23", "-");
* @param time 字符串格式的时间
*/
public TimeUtils(String time, String timeSeparator) {
if(timeSeparator != null) {
setTimeSeparator(timeSeparator);
}
parseTime(time);
}
/**
* 设置时间字段的值
* @param field 时间字段常量
* @param value 时间字段的值
*/
public void set(int field, int value) {
if(value < minFields[field]) {
throw new IllegalArgumentException(value + ", time value must be positive.");
}
fields[field] = value % (maxFields[field] + 1);
// 进行进位计算
int carry = value / (maxFields[field] + 1);
if(carry > 0) {
int upFieldValue = get(field + 1);
set(field + 1, upFieldValue + carry);
}
}
/**
* 获得时间字段的值
* @param field 时间字段常量
* @return 该时间字段的值
*/
public int get(int field) {
if(field < 0 || field > fields.length - 1) {
throw new IllegalArgumentException(field + ", field value is error.");
}
return fields[field];
}
/**
* 将时间进行“加”运算,即加上一个时间
* @param time 需要加的时间
* @return 运算后的时间
*/
public TimeUtils addTime(TimeUtils time) {
TimeUtils result = new TimeUtils();
int up = 0; // 进位标志
for (int i = 0; i < fields.length; i++) {
int sum = fields[i] + time.fields[i] + up;
up = sum / (maxFields[i] + 1);
result.fields[i] = sum % (maxFields[i] + 1);
}
return result;
}
/**
* 将时间进行“减”运算,即减去一个时间
* @param time 需要减的时间
* @return 运算后的时间
*/
public TimeUtils subtractTime(TimeUtils time) {
TimeUtils result = new TimeUtils();
int down = 0; // 退位标志
for (int i = 0, k = fields.length - 1; i < k; i++) {
int difference = fields[i] + down;
if (difference >= time.fields[i]) {
difference -= time.fields[i];
down = 0;
} else {
difference += maxFields[i] + 1 - time.fields[i];
down = -1;
}
result.fields[i] = difference;
}
result.fields[DAY] = fields[DAY] - time.fields[DAY] + down;
return result;
}
/**
* 获得时间字段的分隔符
* @return
*/
public String getTimeSeparator() {
return timeSeparator;
}
/**
* 设置时间字段的分隔符(用于字符串格式的时间)
* @param timeSeparator 分隔符字符串
*/
public void setTimeSeparator(String timeSeparator) {
this.timeSeparator = timeSeparator;
}
private void initialize(int day, int hour, int minute, int second) {
set(DAY, day);
set(HOUR, hour);
set(MINUTE, minute);
set(SECOND, second);
}
private void parseTime(String time) {
if(time == null) {
initialize(0, 0, 0, 0);
return;
}
String t = time;
int field = DAY;
set(field--, 0);
int p = -1;
while((p = t.indexOf(timeSeparator)) > -1) {
parseTimeField(time, t.substring(0, p), field--);
t = t.substring(p + timeSeparator.length());
}
parseTimeField(time, t, field--);
}
private void parseTimeField(String time, String t, int field) {
if(field < SECOND || t.length() < 1) {
parseTimeException(time);
}
char[] chs = t.toCharArray();
int n = 0;
for(int i = 0; i < chs.length; i++) {
if(chs[i] <= ' ') {
continue;
}
if(chs[i] >= '0' && chs[i] <= '9') {
n = n * 10 + chs[i] - '0';
continue;
}
parseTimeException(time);
}
set(field, n);
}
private void parseTimeException(String time) {
throw new IllegalArgumentException(time + ", time format error, HH"
+ this.timeSeparator + "mm" + this.timeSeparator + "ss");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(16);
sb.append(fields[DAY]).append(',').append(' ');
buildString(sb, HOUR).append(timeSeparator);
buildString(sb, MINUTE).append(timeSeparator);
buildString(sb, SECOND);
return sb.toString();
}
private StringBuilder buildString(StringBuilder sb, int field) {
if(fields[field] < 10) {
sb.append('0');
}
return sb.append(fields[field]);
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + Arrays.hashCode(fields);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TimeUtils other = (TimeUtils) obj;
if (!Arrays.equals(fields, other.fields)) {
return false;
}
return true;
}
}
UserAgentUtils类:
/**
* projectName: xxxx
* fileName: UserAgentUtils.java
* packageName: com.xxxx.logs.utils
* date: 2018-05-31 10:49
* copyright(c) xxxx
*/
package com.xxxx.utils.logs.utils;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.DeviceType;
import eu.bitwalker.useragentutils.UserAgent;
import javax.servlet.http.HttpServletRequest;
/**
* @version: V1.0
* @author: fendo
* @className: UserAgentUtils
* @packageName: com.xxxx.logs.utils
* @description: 用户代理
* @data: 2018-05-31 10:49
**/
public class UserAgentUtils {
/**
* 获取用户代理对象
* @param request
* @return
*/
public static UserAgent getUserAgent(HttpServletRequest request){
return UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
}
/**
* 获取设备类型
* @param request
* @return
*/
public static DeviceType getDeviceType(HttpServletRequest request){
return getUserAgent(request).getOperatingSystem().getDeviceType();
}
/**
* 是否是PC
* @param request
* @return
*/
public static boolean isComputer(HttpServletRequest request){
return DeviceType.COMPUTER.equals(getDeviceType(request));
}
/**
* 是否是手机
* @param request
* @return
*/
public static boolean isMobile(HttpServletRequest request){
return DeviceType.MOBILE.equals(getDeviceType(request));
}
/**
* 是否是平板
* @param request
* @return
*/
public static boolean isTablet(HttpServletRequest request){
return DeviceType.TABLET.equals(getDeviceType(request));
}
/**
* 是否是手机和平板
* @param request
* @return
*/
public static boolean isMobileOrTablet(HttpServletRequest request){
DeviceType deviceType = getDeviceType(request);
return DeviceType.MOBILE.equals(deviceType) || DeviceType.TABLET.equals(deviceType);
}
/**
* 获取浏览类型
* @param request
* @return
*/
public static Browser getBrowser(HttpServletRequest request){
return getUserAgent(request).getBrowser();
}
/**
* 是否IE版本是否小于等于IE8
* @param request
* @return
*/
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);
}
}
4)POM.XML文件
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.6.RELEASE</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>provided</scope>
<version>1.8.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
<scope>provided</scope>
</dependency>
</dependencies>
5)使用方式
@PostMapping("/createURL")
@ControllerLogs(description = "创建机器二维码图片URL")
public Map<String,Object> createURL(@NotEmpty(message = "mno is required") String mno,
@NotEmpty(message = "deviceid is required") String deviceid){
return eightStatesService.createURL(mno,deviceid);
}
@Override
@ServiceLogs(description = "商品同步")
public Map<String, Object> goodsSync(GoodsRequestDTO data) {
int a = 0/0;
MachineGoods machineGoods = new MachineGoods();
BeanUtils.copyProperties(data,machineGoods);
machineGoods.setId(Identities.uuid2());
machineGoods.setCt(new Date());
machineGoods.setMt(new Date());
activityTemplate.save(machineGoods);
return ResultFactory.getSuccess();
}
6)调整
后面用着用着发现,打印的日志不是很全,特别是对于GET/POST的From提交,不知道key是什么,只打印了value,所有做如下修改:
public void doBefore(JoinPoint joinPoint) {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//类名
String className = joinPoint.getTarget().getClass().getName();
//请求方法
String method = joinPoint.getSignature().getName() + "()";
//方法参数
String methodParam = JSON.toJSONString(joinPoint.getArgs());
Map<String, String[]> params = request.getParameterMap();
String decode = "";
//针对get请求
if(request.getQueryString()!=null){
try {
decode = URLDecoder.decode(request.getQueryString(),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}else{
//针对post请求
for (String key : params.keySet()) {
String[] values = params.get(key);
for (int i = 0; i < values.length; i++) {
String value = values[i];
decode += key + "=" + value + "&";
}
}
}
//将String根据&转成Map
Map<String, Object> methodParamMap = transStringToMap(decode, "&", "=");
//设置日期格式
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//方法描述
String methodDescription = getControllerMethodDescription(joinPoint);
StringBuilder sb = new StringBuilder(1000);
sb.append("\n");
sb.append("*********************************Request请求***************************************");
sb.append("\n");
sb.append("ClassName : ").append(className).append("\n");
sb.append("RequestMethod : ").append(method).append("\n");
sb.append("ContentType : ").append(("".equals(request.getContentType()) || request.getContentType() == null)?"FROM":request.getContentType()).append("\n");
sb.append("RequestParams : ").append(("".equals(decode) || decode == null)?methodParam:methodParamMap).append("\n");
sb.append("RequestType : ").append(request.getMethod()).append("\n");
sb.append("Description : ").append(methodDescription).append("\n");
sb.append("ServerAddr : ").append(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()).append("\n");
sb.append("RemoteAddr : ").append(IpUtils.getRemoteAddr(request)).append("\n");
UserAgent userAgent = UserAgentUtils.getUserAgent(request);
sb.append("DeviceName : ").append(userAgent.getOperatingSystem().getName()).append("\n");
sb.append("BrowserName : ").append(userAgent.getBrowser().getName()).append("\n");
sb.append("UserAgent : ").append(request.getHeader("User-Agent")).append("\n");
sb.append("RequestUri : ").append(StringUtils.abbr(request.getRequestURI(), 255)).append("\n");
sb.append("**************************");
sb.append(df.format(new Date()));
sb.append("***********************************");
sb.append("\n");
logger.info(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* String 转Map
* @param mapString 待转的String
* @param separator 分割符
* @param pairSeparator 分离器
* @return
*/
public static Map<String, Object> transStringToMap(String mapString, String separator, String pairSeparator) {
Map<String, Object> map = new HashMap<String, Object>();
String[] fSplit = mapString.split(separator);
for (int i = 0; i < fSplit.length; i++) {
if (fSplit[i]==null||fSplit[i].length()==0) {
continue;
}
String[] sSplit = fSplit[i].split(pairSeparator);
String value = fSplit[i].substring(fSplit[i].indexOf('=') + 1, fSplit[i].length());
map.put(sSplit[0], value);
}
return map;
}