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":"/"}大致就这样,我们有自己的深度业务,比如异常时候会自己发送钉钉运维群消息,就在处理的位置就可以了
福利图就不放了,睡觉。。。困了,有参考就点个赞呗