日志记录到redis展现形式

1.基于注解的方式实现日志记录,扫描对应的方法实现日志记录

@inherited
@retention(retentionpolicy.runtime)
@target({elementtype.method})
public @interface bussinesslog {
 
    /**
     * 业务的名称,例如:"修改菜单"
     */
    string value() default "";
 
    /**
     * 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
     */
    string key() default "id";
 
    /**
     * 业务类型
     */
    string type() default "0";
 
    /**
     * 字典(用于查找key的中文名称和字段的中文名称)
     */
    class<? extends abstractdictmap> dict() default systemdict.class; 
}

2.扫描的方法,基于注解实现方法扫描并且记录日志

3.基于@aspect注解,实现日志扫描,并且记录日志

import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.signature;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.aspectj.lang.reflect.methodsignature;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component; 
import java.lang.reflect.method;
import java.util.map;
 
/**
 * 日志记录
 *
 */
@aspect
@component
public class logaop { 
    private logger log = loggerfactory.getlogger(this.getclass()); 
    @pointcut(value = "@annotation(com.stylefeng.guns.core.common.annotion.bussinesslog)")
    public void cutservice() {
    }
 
    @around("cutservice()")
    public object recordsyslog(proceedingjoinpoint point) throws throwable {
 
        //先执行业务
        object result = point.proceed();
 
        try {
            handle(point);
        } catch (exception e) {
            log.error("日志记录出错!", e);
        } 
        return result;
    }
 
    private void handle(proceedingjoinpoint point) throws exception {
 
        //获取拦截的方法名
        signature sig = point.getsignature();
        methodsignature msig = null;
        if (!(sig instanceof methodsignature)) {
            throw new illegalargumentexception("该注解只能用于方法");
        }
        msig = (methodsignature) sig;
        object target = point.gettarget();
        method currentmethod = target.getclass().getmethod(msig.getname(), msig.getparametertypes());
        string methodname = currentmethod.getname();
 
        //如果当前用户未登录,不做日志
        shirouser user = shirokit.getuser();
        if (null == user) {
            return;
        }
 
        //获取拦截方法的参数
        string classname = point.gettarget().getclass().getname();
        object[] params = point.getargs();
 
        //获取操作名称
        bussinesslog annotation = currentmethod.getannotation(bussinesslog.class);
        string bussinessname = annotation.value();
        string key = annotation.key();
        class dictclass = annotation.dict();
 
        stringbuilder sb = new stringbuilder();
        for (object param : params) {
            sb.append(param);
            sb.append(" & ");
        }
 
        //如果涉及到修改,比对变化
        string msg;
        if (bussinessname.contains("修改") || bussinessname.contains("编辑")) {
            object obj1 = logobjectholder.me().get();
            map<string, string> obj2 = httpcontext.getrequestparameters();
            msg = contrast.contrastobj(dictclass, key, obj1, obj2);
        } else {
            map<string, string> parameters = httpcontext.getrequestparameters();
            abstractdictmap dictmap = (abstractdictmap) dictclass.newinstance();
            msg = contrast.parsemutikey(dictmap, key, parameters);
        }
        log.info("[记录日志][result:{}]",user.getid()+bussinessname+classname+methodname+msg.tostring());
        logmanager.me().executelog(logtaskfactory.bussinesslog(user.getid(), bussinessname, classname, methodname, msg));
    }
}

4.比较两个对象的工具类

import java.beans.propertydescriptor;
import java.lang.reflect.field;
import java.lang.reflect.method;
import java.util.date;
import java.util.map;
/**
* 对比两个对象的变化的工具类
*
* @author ...
* @date 2017/3/31 10:36
*/
public class contrast {
//记录每个修改字段的分隔符
public static final string separator = ";;;";
/**
* 比较两个对象,并返回不一致的信息
*
* @author ...
* @date 2017/5/9 19:34
*/
public static string contrastobj(object pojo1, object pojo2) {
string str = "";
try {
class clazz = pojo1.getclass();
field[] fields = pojo1.getclass().getdeclaredfields();
int i = 1;
for (field field : fields) {
if ("serialversionuid".equals(field.getname())) {
continue;
}
propertydescriptor pd = new propertydescriptor(field.getname(), clazz);
method getmethod = pd.getreadmethod();
object o1 = getmethod.invoke(pojo1);
object o2 = getmethod.invoke(pojo2);
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof date) {
o1 = dateutil.getday((date) o1);
}
if (!o1.tostring().equals(o2.tostring())) {
if (i != 1) {
str += separator;
}
str += "字段名称" + field.getname() + ",旧值:" + o1 + ",新值:" + o2;
i++;
}
}
} catch (exception e) {
e.printstacktrace();
}
return str;
}
/**
* 比较两个对象pojo1和pojo2,并输出不一致信息
*
* @author ...
* @date 2017/5/9 19:34
*/
public static string contrastobj(class dictclass, string key, object pojo1, map<string, string> pojo2) throws illegalaccessexception, instantiationexception {
abstractdictmap dictmap = (abstractdictmap) dictclass.newinstance();
string str = parsemutikey(dictmap, key, pojo2) + separator;
try {
class clazz = pojo1.getclass();
field[] fields = pojo1.getclass().getdeclaredfields();
int i = 1;
for (field field : fields) {
if ("serialversionuid".equals(field.getname())) {
continue;
}
propertydescriptor pd = new propertydescriptor(field.getname(), clazz);
method getmethod = pd.getreadmethod();
object o1 = getmethod.invoke(pojo1);
object o2 = pojo2.get(strkit.firstchartolowercase(getmethod.getname().substring(3)));
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof date) {
o1 = dateutil.getday((date) o1);
} else if (o1 instanceof integer) {
o2 = integer.parseint(o2.tostring());
}
if (!o1.tostring().equals(o2.tostring())) {
if (i != 1) {
str += separator;
}
string fieldname = dictmap.get(field.getname());
string fieldwarppermethodname = dictmap.getfieldwarppermethodname(field.getname());
if (fieldwarppermethodname != null) {
object o1warpper = dictfieldwarpperfactory.createfieldwarpper(o1, fieldwarppermethodname);
object o2warpper = dictfieldwarpperfactory.createfieldwarpper(o2, fieldwarppermethodname);
str += "字段名称:" + fieldname + ",旧值:" + o1warpper + ",新值:" + o2warpper;
} else {
str += "字段名称:" + fieldname + ",旧值:" + o1 + ",新值:" + o2;
}
i++;
}
}
} catch (exception e) {
e.printstacktrace();
}
return str;
}
/**
* 比较两个对象pojo1和pojo2,并输出不一致信息
*
* @author ...
* @date 2017/5/9 19:34
*/
public static string contrastobjbyname(class dictclass, string key, object pojo1, map<string, string> pojo2) throws illegalaccessexception, instantiationexception {
abstractdictmap dictmap = (abstractdictmap) dictclass.newinstance();
string str = parsemutikey(dictmap, key, pojo2) + separator;
try {
class clazz = pojo1.getclass();
field[] fields = pojo1.getclass().getdeclaredfields();
int i = 1;
for (field field : fields) {
if ("serialversionuid".equals(field.getname())) {
continue;
}
string prefix = "get";
int prefixlength = 3;
if (field.gettype().getname().equals("java.lang.boolean")) {
prefix = "is";
prefixlength = 2;
}
method getmethod = null;
try {
getmethod = clazz.getdeclaredmethod(prefix + strkit.firstchartouppercase(field.getname()));
} catch (nosuchmethodexception e) {
system.err.println("this classname:" + clazz.getname() + " is not methodname: " + e.getmessage());
continue;
}
object o1 = getmethod.invoke(pojo1);
object o2 = pojo2.get(strkit.firstchartolowercase(getmethod.getname().substring(prefixlength)));
if (o1 == null || o2 == null) {
continue;
}
if (o1 instanceof date) {
o1 = dateutil.getday((date) o1);
} else if (o1 instanceof integer) {
o2 = integer.parseint(o2.tostring());
}
if (!o1.tostring().equals(o2.tostring())) {
if (i != 1) {
str += separator;
}
string fieldname = dictmap.get(field.getname());
string fieldwarppermethodname = dictmap.getfieldwarppermethodname(field.getname());
if (fieldwarppermethodname != null) {
object o1warpper = dictfieldwarpperfactory.createfieldwarpper(o1, fieldwarppermethodname);
object o2warpper = dictfieldwarpperfactory.createfieldwarpper(o2, fieldwarppermethodname);
str += "字段名称:" + fieldname + ",旧值:" + o1warpper + ",新值:" + o2warpper;
} else {
str += "字段名称:" + fieldname + ",旧值:" + o1 + ",新值:" + o2;
}
i++;
}
}
} catch (exception e) {
e.printstacktrace();
}
return str;
}
/**
* 解析多个key(逗号隔开的)
*
* @author ...
* @date 2017/5/16 22:19
*/
public static string parsemutikey(abstractdictmap dictmap, string key, map<string, string> requests) {
stringbuilder sb = new stringbuilder();
if (key.indexof(",") != -1) {
string[] keys = key.split(",");
for (string item : keys) {
string fieldwarppermethodname = dictmap.getfieldwarppermethodname(item);
string value = requests.get(item);
if (fieldwarppermethodname != null) {
object valuewarpper = dictfieldwarpperfactory.createfieldwarpper(value, fieldwarppermethodname);
sb.append(dictmap.get(item) + "=" + valuewarpper + ",");
} else {
sb.append(dictmap.get(item) + "=" + value + ",");
}
}
return strkit.removesuffix(sb.tostring(), ",");
} else {
string fieldwarppermethodname = dictmap.getfieldwarppermethodname(key);
string value = requests.get(key);
if (fieldwarppermethodname != null) {
object valuewarpper = dictfieldwarpperfactory.createfieldwarpper(value, fieldwarppermethodname);
sb.append(dictmap.get(key) + "=" + valuewarpper);
} else {
sb.append(dictmap.get(key) + "=" + value);
}
return sb.tostring();
}
} 
}

5.根据输入方法获取数据字典的数据

import java.lang.reflect.method;  
public class dictfieldwarpperfactory {  
public static object createfieldwarpper(object parameter, string methodname) {
iconstantfactory constantfactory = constantfactory.me();
try {
method method = iconstantfactory.class.getmethod(methodname, parameter.getclass());
return method.invoke(constantfactory, parameter);
} catch (exception e) {
try {
method method = iconstantfactory.class.getmethod(methodname, integer.class);
return method.invoke(constantfactory, integer.parseint(parameter.tostring()));
} catch (exception e1) {
throw new runtimeexception("bizexceptionenum.error_wrapper_field");
}
}
} 
}

6.对应获取数据字典的方法

public interface iconstantfactory { 
/**
* 获取状态
*/
string getwordstatus(integer data_status); 
}
import com.qihoinfo.dev.log.util.springcontextholder;
import org.anyline.service.anylineservice;
import org.springframework.context.annotation.dependson;
import org.springframework.stereotype.component;  
@component
@dependson("springcontextholder")
public class constantfactory implements iconstantfactory { 
private anylineservice anylineservice = springcontextholder.getbean(anylineservice.class); 
public static iconstantfactory me() {
return springcontextholder.getbean("constantfactory");
}
@override
public string getwordstatus(integer data_status) {
if ("1".equals(data_status.tostring())) {
return "启用";
} else {
return "停用";
}
} 
}

7.spring根据方法名获取对应容器中的对象

import org.springframework.beans.beansexception;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.stereotype.component; 
/**
* spring的applicationcontext的持有者,可以用静态方法的方式获取spring容器中的bean
*/
@component
public class springcontextholder implements applicationcontextaware {  
private static applicationcontext applicationcontext; 
@override
public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
springcontextholder.applicationcontext = applicationcontext;
}
public static applicationcontext getapplicationcontext() {
assertapplicationcontext();
return applicationcontext;
}
@suppresswarnings("unchecked")
public static <t> t getbean(string beanname) {
assertapplicationcontext();
return (t) applicationcontext.getbean(beanname);
}
public static <t> t getbean(class<t> requiredtype) {
assertapplicationcontext();
return applicationcontext.getbean(requiredtype);
}
private static void assertapplicationcontext() {
if (springcontextholder.applicationcontext == null) {
throw new runtimeexception("applicaitoncontext属性为null,请检查是否注入了springcontextholder!");
}
} 
}

8.字符串工具类

/**
* 字符串工具类
*/
public class strkit {   
/**
* 首字母变小写
*/
public static string firstchartolowercase(string str) {
char firstchar = str.charat(0);
if (firstchar >= 'a' && firstchar <= 'z') {
char[] arr = str.tochararray();
arr[0] += ('a' - 'a');
return new string(arr);
}
return str;
}
/**
* 首字母变大写
*/
public static string firstchartouppercase(string str) {
char firstchar = str.charat(0);
if (firstchar >= 'a' && firstchar <= 'z') {
char[] arr = str.tochararray();
arr[0] -= ('a' - 'a');
return new string(arr);
}
return str;
}
/**
* 去掉指定后缀
*/
public static string removesuffix(string str, string suffix) {
if (isempty(str) || isempty(suffix)) {
return str;
}
if (str.endswith(suffix)) {
return str.substring(0, str.length() - suffix.length());
}
return str;
}
/**
* 字符串是否为空,空的定义如下 1、为null <br>
* 2、为""<br>
*/
public static boolean isempty(string str) {
return str == null || str.length() == 0;
}
}
import java.io.ioexception;
import java.io.printwriter;
import java.io.stringwriter;  
public class toolutil {
public static final int salt_length = 6;
public toolutil() {
}
public static string getexceptionmsg(throwable e) {
stringwriter sw = new stringwriter();
try {
e.printstacktrace(new printwriter(sw));
} finally {
try {
sw.close();
} catch (ioexception var8) {
var8.printstacktrace();
}
} 
return sw.getbuffer().tostring().replaceall("\\$", "t");
}
}

9.获取数据字典的类

import java.util.hashmap;  
public abstract class abstractdictmap { 
protected hashmap<string, string> dictory = new hashmap<>();
protected hashmap<string, string> fieldwarpperdictory = new hashmap<>(); 
public abstractdictmap() {
put("id", "主键id");
init();
initbewrapped();
}
public abstract void init(); 
protected abstract void initbewrapped(); 
public string get(string key) {
return this.dictory.get(key);
}
public void put(string key, string value) {
this.dictory.put(key, value);
}
public string getfieldwarppermethodname(string key) {
return this.fieldwarpperdictory.get(key);
}
public void putfieldwrappermethodname(string key, string methodname) {
this.fieldwarpperdictory.put(key, methodname);
}
}
public class systemdict extends abstractdictmap { 
@override
public void init() {
}
@override
protected void initbewrapped() {
}
}
public class wordmap extends abstractdictmap { 
@override
public void init() {
put("en", "英文");
put("cn", "中文");
put("short", "简称");
put("remark", "备注");
put("data_status", "状态");
}
@override
protected void initbewrapped() {
putfieldwrappermethodname("data_status","getwordstatus");
} 
}

10.获取缓存对象的bean

import org.springframework.context.annotation.scope;
import org.springframework.stereotype.component;
import org.springframework.web.context.webapplicationcontext; 
import java.io.serializable;  
@component
@scope(scopename = webapplicationcontext.scope_session)
public class logobjectholder implements serializable{ 
private object object = null; 
public void set(object obj) {
this.object = obj;
}
public object get() {
return object;
}
public static logobjectholder me(){
logobjectholder bean = springcontextholder.getbean(logobjectholder.class);
return bean;
} 
}

11.运行时异常的获取

@controlleradvice
public class globalexceptionhandler extends basicmemberjsoncontroller { 
private logger log = loggerfactory.getlogger(this.getclass()); 
@exceptionhandler(runtimeexception.class)
@responsestatus(httpstatus.internal_server_error)
@responsebody
public string notfount(runtimeexception e) {
string username = curmanage().get("username").tostring();
logmanager.me().executelog(logtaskfactory.exceptionlog(username, e));
log.error("运行时异常:", e);
return fail();
}
}

12.使用线程池创建操作日志

import java.util.date;  
public class logfactory {  
/**
* 创建操作日志
*/
public static datarow createoperationlog(logtype logtype, string username, string bussinessname, string clazzname, string methodname, string msg, logsucceed succeed) {
datarow operationlog = new datarow();
operationlog.put("log_type", logtype.getmessage());
operationlog.put("user_name", username);
operationlog.put("log_name", bussinessname);
operationlog.put("class_name", clazzname);
operationlog.put("method", methodname);
operationlog.put("create_time", new date());
operationlog.put("succeed", succeed.getmessage());
if (msg.length() > 800) {
msg = msg.substring(0, 800);
operationlog.put("message", msg);
} else {
operationlog.put("message", msg);
}
return operationlog;
}
}
import java.util.timertask;
import java.util.concurrent.scheduledthreadpoolexecutor;
import java.util.concurrent.timeunit; 
public class logmanager { 
//日志记录操作延时
private final int operate_delay_time = 10;
//异步操作记录日志的线程池
private scheduledthreadpoolexecutor executor = new scheduledthreadpoolexecutor(10); 
private logmanager() {
}
public static logmanager logmanager = new logmanager(); 
public static logmanager me() {
return logmanager;
}
public void executelog(timertask task) {
executor.schedule(task, operate_delay_time, timeunit.milliseconds);
} 
}
public enum logsucceed { 
success("成功"),
fail("失败");
string message; 
logsucceed(string message) {
this.message = message;
}
public string getmessage() {
return message;
}
public void setmessage(string message) {
this.message = message;
} 
}
import com.qihoinfo.dev.log.annotation.redisdb;
import com.qihoinfo.dev.log.util.toolutil;
import org.anyline.entity.datarow;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.context.annotation.dependson;
import org.springframework.data.redis.core.stringredistemplate;
import org.springframework.stereotype.component; 
import java.util.timertask; 
@component
@dependson("springcontextholder")
public class logtaskfactory {
private static logger logger = loggerfactory.getlogger(logmanager.class); 
private static stringredistemplate redistemplate = redisdb.getmapper(stringredistemplate.class);
public static timertask bussinesslog(final string username, final string bussinessname, final string clazzname, final string methodname, final string msg) {
return new timertask() {
@override
public void run() {
datarow operationlog = logfactory.createoperationlog(
logtype.bussiness, username, bussinessname, clazzname, methodname, msg, logsucceed.success);
try {
redistemplate.opsforlist().rightpush("sys_operation_log", operationlog.getjson());
} catch (exception e) {
logger.error("创建业务日志异常!", e);
}
}
};
}
public static timertask exceptionlog(final string username, final exception exception) {
return new timertask() {
@override
public void run() {
string msg = toolutil.getexceptionmsg(exception);
datarow operationlog = logfactory.createoperationlog(
logtype.exception, username, "", null, null, msg, logsucceed.fail);
try {
redistemplate.opsforlist().rightpush("sys_operation_log", operationlog.getjson());
} catch (exception e) {
logger.error("创建异常日志异常!", e);
}
}
};
} 
}
public enum logtype {
exception("异常日志"),
bussiness("业务日志");
string message; 
logtype(string message) {
this.message = message;
}
public string getmessage() {
return message;
}
public void setmessage(string message) {
this.message = message;
} 
}

13.将日志记录到redis数据库

package com.qihoinfo.dev.log.annotation;  
import com.qihoinfo.dev.log.util.springcontextholder;
import org.springframework.data.redis.core.stringredistemplate; 
public class redisdb<t> {  
private class<t> clazz; 
private stringredistemplate basemapper; 
private redisdb(class clazz) {
this.clazz = clazz;
this.basemapper = (stringredistemplate) springcontextholder.getbean(clazz);
} 
public static <t> redisdb<t> create(class<t> clazz) {
return new redisdb<t>(clazz);
} 
public stringredistemplate getmapper() {
return this.basemapper;
} 
public static <t> t getmapper(class<t> clazz) {
return springcontextholder.getbean(clazz);
}  
}
import org.springframework.web.context.request.requestcontextholder;
import org.springframework.web.context.request.servletrequestattributes; 
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import java.util.enumeration;
import java.util.hashmap;
import java.util.map;
/**
* @description:
* @auther: wj
* @date: 2019/5/28 13:56
*/
public class httpcontext {
public httpcontext() {
}
public static string getip() {
httpservletrequest request = getrequest();
return request == null ? "127.0.0.1" : request.getremotehost();
}
public static httpservletrequest getrequest() {
servletrequestattributes requestattributes = (servletrequestattributes) requestcontextholder.getrequestattributes();
return requestattributes == null ? null : requestattributes.getrequest();
}
public static httpservletresponse getresponse() {
servletrequestattributes requestattributes = (servletrequestattributes) requestcontextholder.getrequestattributes();
return requestattributes == null ? null : requestattributes.getresponse();
}
public static map<string, string> getrequestparameters() {
hashmap<string, string> values = new hashmap();
httpservletrequest request = getrequest();
if (request == null) {
return values;
} else {
enumeration enums = request.getparameternames();
while (enums.hasmoreelements()) {
string paramname = (string) enums.nextelement();
string paramvalue = request.getparameter(paramname);
values.put(paramname, paramvalue);
}
return values;
}
}
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。