JFinal使用技巧-全局业务数据共享&自定义操作日志

RT,有朋友私我,说想看一下回复https://jfinal.com/feedback/8089的思路实现代码,最近确实非常忙。。。接了好多项目。。。话 不 多 说 了, 上 石马  ~ 
思路:
复制JF的 Log4jLog,在中间复写自己的业务日志,代码里面都是全局位置Log log = Log.getLog(XXX.class)。
全局变量共享在拦截器configHandler配置的,里面也是通过ThreadLocal存放的。比如登录用户,请求路径target,参数,返回结果等等信息

1建个Handler,业务里面可以随意存取公共数据,方便的很

package cn.yunjiaowu.msg.common.handler.data;

import com.jfinal.handler.Handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 公共数据共享处理器
 */
public class DataHandler extends Handler {
    private static final ThreadLocal<DataPack> TL = new ThreadLocal();
    @Override
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        if (target.indexOf('.') != -1) {
            //如果要拦截处理计算静态资源,此处可放开
            return ;
        }
        DataPack data = new DataPack();
        TL.set(data);
        data.setTarget(target);
        data.setRequest(request);
        data.setResponse(response);
        try {
            next.handle(target, request, response, isHandled);
        }finally {
            TL.remove();
        }
    }

    public static DataPack getDataPack() {
        return TL.get();
    }
}

1.1 Interceptor

package cn.yunjiaowu.msg.common.interceptor;

import cn.yunjiaowu.msg.common.handler.data.DataHandler;
import cn.yunjiaowu.msg.common.handler.data.DataPack;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;

/**
 * 公共数据共享拦截器添加
 */
public class DataInterceptor implements Interceptor {
    @Override
    public void intercept(Invocation inv) {
        DataPack data = DataHandler.getDataPack();
        data.setActionKey(inv.getActionKey());
        //根据自己业务来自定义
        inv.invoke();
    }
}

2数据包装类

package cn.yunjiaowu.msg.common.handler.data;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 共享包装类
 */
public class DataPack {
    private String target;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private String parameter;
    private String actionKey;
    //此处可以扩展自己的业务对象,如登录用户等

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public HttpServletRequest getRequest() {
        return request;
    }

    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }

    public HttpServletResponse getResponse() {
        return response;
    }

    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }

    public String getParameter() {
        return parameter;
    }
    public void setParameter(String parameter) {
        this.parameter = parameter;
    }

    public void setActionKey(String actionKey) {
        this.actionKey = actionKey;
    }
    public String getActionKey() {
        return actionKey;
    }
}

3Log对象

package cn.yunjiaowu.msg.common.log;

import com.jfinal.log.Log;
import com.jfinal.log.LogInfo;
import org.apache.log4j.Level;
import org.apache.log4j.Priority;

public class MyLog extends Log {

    private org.apache.log4j.Logger log;
    private static final String callerFQCN = MyLog.class.getName();

    MyLog(Class<?> clazz) {
        log = org.apache.log4j.Logger.getLogger(clazz);
    }

    MyLog(String name) {
        log = org.apache.log4j.Logger.getLogger(name);
    }

    public static MyLog getLog(Class<?> clazz) {
        return new MyLog(clazz);
    }

    public static MyLog getLog(String name) {
        return new MyLog(name);
    }

    public void handleLog(String callerFQCN, Priority level, String message, Throwable t){
        message = MessageHandle.handle(callerFQCN, level, message, t);
        log.log(callerFQCN, level, message, t);
    }

    public void trace(String message) {
        handleLog(callerFQCN, Level.TRACE, message, null);
    }

    public void trace(String message, Throwable t) {
        handleLog(callerFQCN, Level.TRACE, message, t);
    }

    public void debug(String message) {
        handleLog(callerFQCN, Level.DEBUG, message, null);
    }

    public void debug(String message, Throwable t) {
        handleLog(callerFQCN, Level.DEBUG, message, t);
    }

    public void info(String message) {
        handleLog(callerFQCN, Level.INFO, message, null);
    }

    public void info(String message, Throwable t) {
        handleLog(callerFQCN, Level.INFO, message, t);
    }

    public void warn(String message) {
        handleLog(callerFQCN, Level.WARN, message, null);
    }

    public void warn(String message, Throwable t) {
        handleLog(callerFQCN, Level.WARN, message, t);
    }

    public void error(String message) {
        handleLog(callerFQCN, Level.ERROR, message, null);
    }

    public void error(String message, Throwable t) {
        handleLog(callerFQCN, Level.ERROR, message, t);
    }

    public void fatal(String message) {
        handleLog(callerFQCN, Level.FATAL, message, null);
    }

    public void fatal(String message, Throwable t) {
        handleLog(callerFQCN, Level.FATAL, message, t);
    }

    public boolean isTraceEnabled() {
        return log.isTraceEnabled();
    }

    public boolean isDebugEnabled() {
        return log.isDebugEnabled();
    }

    public boolean isInfoEnabled() {
        return log.isInfoEnabled();
    }

    public boolean isWarnEnabled() {
        return log.isEnabledFor(Level.WARN);
    }

    public boolean isErrorEnabled() {
        return log.isEnabledFor(Level.ERROR);
    }

    public boolean isFatalEnabled() {
        return log.isEnabledFor(Level.FATAL);
    }

    // -------------------------------------------------------

    /*
     * 以下方法与前面的两个 trace 方法必须覆盖父类中的实现,否则日志中的类名为
     * com.jfinal.log.Log 而非所需要的日志发生地点的类名
     */

    public void trace(String format, Object... args) {
        if (isTraceEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                trace(li.message, li.throwable);
            } else {
                trace(String.format(format, args));
            }
        }
    }

    public void debug(String format, Object... args) {
        if (isDebugEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                debug(li.message, li.throwable);
            } else {
                debug(String.format(format, args));
            }
        }
    }

    public void info(String format, Object... args) {
        if (isInfoEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                info(li.message, li.throwable);
            } else {
                info(String.format(format, args));
            }
        }
    }

    public void warn(String format, Object... args) {
        if (isWarnEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                warn(li.message, li.throwable);
            } else {
                warn(String.format(format, args));
            }
        }
    }

    public void error(String format, Object... args) {
        if (isErrorEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                error(li.message, li.throwable);
            } else {
                error(String.format(format, args));
            }
        }
    }

    public void fatal(String format, Object... args) {
        if (isFatalEnabled()) {
            if (endsWithThrowable(args)) {
                LogInfo li = parse(format, args);
                fatal(li.message, li.throwable);
            } else {
                fatal(String.format(format, args));
            }
        }
    }
}

 4ILogFactory

package cn.yunjiaowu.msg.common.log;

import com.jfinal.log.ILogFactory;
import com.jfinal.log.Log;

public class MyLogFactory  implements ILogFactory {

    public Log getLog(Class<?> clazz) {
        return new MyLog(clazz);
    }

    public Log getLog(String name) {
        return new MyLog(name);
    }
}

 5MessageHandle

package cn.yunjiaowu.msg.common.log;

import cn.yunjiaowu.msg.common.handler.data.DataHandler;
import cn.yunjiaowu.msg.common.handler.data.DataPack;
import com.jfinal.kit.Kv;
import org.apache.log4j.Level;
import org.apache.log4j.Priority;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;

/**
 * 日志数据打包处理
 */
public class MessageHandle {
    public static String handle(String callerFQCN, Priority level, String message, Throwable t){
        DataPack data = DataHandler.getDataPack();
        if(data == null){
            return message;
        }
        Kv kv = Kv.by("target", data.getTarget());
        //level可以自主判断需要记录什么样的日志
        //可以在登录拦截器 放入用户信息
        //如 data.get登录人信息
        kv.set("actionKey", data.getActionKey());
        //看自己业务是否需要加入请求参数这里只是一个例子
        kv.set("parameter", getParameter(data));
        if(Level.ERROR.equals(level)){
            //异常日志,把部分代码行数放入日志,后续方便写入数据库,如果是只做日志文件,此处可注释掉
            kv.set("code", getCode(t));
        }
        kv.set("callerFQCN", callerFQCN);
        kv.set("message", message);
        kv.set("level", level.toString());

        //我们业务日志是有入库的,这里就不写了, 根据自己业务来吧
        //System.out.println(kv.toJson());
        return kv.toJson();
    }

    private static int maxOutputLengthOfParaValue = 512;
    private static String getParameter(DataPack data) {
        if (data.getParameter() != null){
            return data.getParameter();
        }
        HttpServletRequest request = data.getRequest();
        Enumeration<String> e = request.getParameterNames();
        if (e.hasMoreElements()) {
            StringBuilder sb = new StringBuilder(128);
            sb.append("Parameter   : ");
            while (e.hasMoreElements()) {
                String name = e.nextElement();
                String[] values = request.getParameterValues(name);
                if (values.length == 1) {
                    sb.append(name).append("=");
                    if (values[0] != null && values[0].length() > maxOutputLengthOfParaValue) {
                        sb.append(values[0].substring(0, maxOutputLengthOfParaValue)).append("...");
                    } else {
                        sb.append(values[0]);
                    }
                }
                else {
                    sb.append(name).append("[]={");
                    for (int i=0; i<values.length; i++) {
                        if (i > 0)
                            sb.append(",");
                        sb.append(values[i]);
                    }
                    sb.append("}");
                }
                sb.append("  ");
            }
            String str = sb.toString();
            data.setParameter(str);
            return str;
        }
        return null;
    }

    private static String getCode(Throwable e) {
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.close();
            String ret = sw.toString();
            ret = ret.substring(0, ret.indexOf("com.jfinal.aop.Invocation.invoke"));
            return ret;
        } catch (Exception e2) {
            return "ErrorInfoFromException";
        }
    }


}

 6配置自己的JFinalConfig

/**
 * 配置常量
 */
public void configConstant(Constants me) {
    //日志
   me.setLogFactory(new MyLogFactory());
}
/**
 * 配置全局拦截器
 */
public void configInterceptor(Interceptors me) {
   me.add(new DataInterceptor());
}
/**
 * 配置处理器
 */
public void configHandler(Handlers me) {
   me.add(new DataHandler());
}

7使用日志

/**
 * IndexController
 */
@Path(value = "/", viewPath = "/")
public class IndexController extends Controller {
   private static final  Log log = Log.getLog(IndexController.class);
   public void index() {
      log.debug("来啦老弟~");
      log.info("来啦老弟~");
      log.warn("来啦老弟~");
      log.error("来啦老弟~");
      log.fatal("来啦老弟~");
      render("/index.html");
   }
}

效果:

2021-04-22 09:37:37
[DEBUG]-[Thread: XNIO-2 task-1]-[cn.yunjiaowu.msg.index.IndexController.index()]: {"callerFQCN":"cn.yunjiaowu.msg.common.log.MyLog","level":"DEBUG","parameter":null,"message":"来啦老弟~","target":"/"}

2021-04-22 09:37:37
[INFO]-[Thread: XNIO-2 task-1]-[cn.yunjiaowu.msg.index.IndexController.index()]: {"callerFQCN":"cn.yunjiaowu.msg.common.log.MyLog","level":"INFO","parameter":null,"message":"来啦老弟~","target":"/"}

2021-04-22 09:37:37
[WARN]-[Thread: XNIO-2 task-1]-[cn.yunjiaowu.msg.index.IndexController.index()]: {"callerFQCN":"cn.yunjiaowu.msg.common.log.MyLog","level":"WARN","parameter":null,"message":"来啦老弟~","target":"/"}

2021-04-22 09:37:37
[ERROR]-[Thread: XNIO-2 task-1]-[cn.yunjiaowu.msg.index.IndexController.index()]: {"code":"ErrorInfoFromException","callerFQCN":"cn.yunjiaowu.msg.common.log.MyLog","level":"ERROR","parameter":null,"message":"来啦老弟~","target":"/"}

2021-04-22 09:37:37
[FATAL]-[Thread: XNIO-2 task-1]-[cn.yunjiaowu.msg.index.IndexController.index()]: {"callerFQCN":"cn.yunjiaowu.msg.common.log.MyLog","level":"FATAL","parameter":null,"message":"来啦老弟~","target":"/"}

大致就这样,我们有自己的深度业务,比如异常时候会自己发送钉钉运维群消息,就在处理的位置就可以了
image.png
福利图就不放了,睡觉。。。困了,有参考就点个赞呗

评论区

vk567

2021-04-23 09:01

学习了

北流家园网

2021-04-23 21:04

收藏

maapple

2021-04-28 14:02

来啦老弟,太亲切了