jfinal自定义ActionHandler实现。

自动以ActionHandler实现,多多指教

内部CPI调用(感谢波总指导,省去反射代码)

import com.jfinal.aop.Invocation;
import com.jfinal.core.*;
import com.jfinal.log.Log;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

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

public class MyActionHandler extends ActionHandler {

    private static final Log log = Log.getLog(ActionHandler.class);

    /**
     * handle
     * 1: Action action = actionMapping.getAction(target)
     * 2: new Invocation(...).invoke()
     * 3: render(...)
     */
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        if (target.indexOf('.') != -1) {
            return;
        }

        isHandled[0] = true;
        String[] urlPara = {null};
        Action action = actionMapping.getAction(target, urlPara);

        if (action == null) {
            if (log.isWarnEnabled()) {
                String qs = request.getQueryString();
                log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));
            }
            renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render();
            return;
        }

        Controller controller = null;

        try {
            controller = controllerFactory.getController(action.getControllerClass());

            if (injectDependency) {
                com.jfinal.aop.Aop.inject(controller);
            }
            CPI._init_(controller, action, request, response, urlPara[0]);

            new Invocation(action, controller).invoke();

            Render render = controller.getRender();
            if (render instanceof ForwardActionRender) {
                String actionUrl = ((ForwardActionRender) render).getActionUrl();
                if (target.equals(actionUrl)) {
                    throw new RuntimeException("The forward action url is the same as before.");
                } else {
                    handle(actionUrl, request, response, isHandled);
                }
                return;
            }

            if (render == null) {
                render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName());
            }
            render.setContext(request, response, action.getViewPath()).render();
        } catch (RenderException e) {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(qs == null ? target : target + "?" + qs, e);
            }
        } catch (ActionException e) {
            handleActionException(target, request, response, action, e);
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(qs == null ? target : target + "?" + qs, e);
            }
            renderManager.getRenderFactory().getErrorRender(500).setContext(request, response, action.getViewPath()).render();
        } finally {
            if (controller != null) {
                CPI._clear_(controller);
            }
        }
    }

    /**
     * 抽取出该方法是为了缩短 handle 方法中的代码量,确保获得 JIT 优化,
     * 方法长度超过 8000 个字节码时,将不会被 JIT 编译成二进制码
     * <p>
     * 通过开启 java 的 -XX:+PrintCompilation 启动参数得知,handle(...)
     * 方法(73 行代码)已被 JIT 优化,优化后的字节码长度为 593 个字节,相当于
     * 每行代码产生 8.123 个字节
     */
    private void handleActionException(String target, HttpServletRequest request, HttpServletResponse response, Action action, ActionException e) {
        int errorCode = e.getErrorCode();
        String msg = null;
        if (errorCode == 404) {
            msg = "404 Not Found: ";
        } else if (errorCode == 400) {
            msg = "400 Bad Request: ";
        } else if (errorCode == 401) {
            msg = "401 Unauthorized: ";
        } else if (errorCode == 403) {
            msg = "403 Forbidden: ";
        }

        if (msg != null) {
            if (log.isWarnEnabled()) {
                String qs = request.getQueryString();
                msg = msg + (qs == null ? target : target + "?" + qs);
                if (e.getMessage() != null) {
                    msg = msg + "\n" + e.getMessage();
                }
                log.warn(msg);
            }
        } else {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(errorCode + " Error: " + (qs == null ? target : target + "?" + qs), e);
            }
        }

        e.getErrorRender().setContext(request, response, action.getViewPath()).render();
    }
}

反射调用

import com.jfinal.aop.Invocation;
import com.jfinal.core.*;
import com.jfinal.log.Log;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyActionHandler extends ActionHandler {

    private static final Log log = Log.getLog(ActionHandler.class);

    /**
     * handle
     * 1: Action action = actionMapping.getAction(target)
     * 2: new Invocation(...).invoke()
     * 3: render(...)
     */
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        if (target.indexOf('.') != -1) {
            return;
        }

        isHandled[0] = true;
        String[] urlPara = {null};
        Action action = actionMapping.getAction(target, urlPara);

        if (action == null) {
            if (log.isWarnEnabled()) {
                String qs = request.getQueryString();
                log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs));
            }
            renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render();
            return;
        }

        Class<Controller> controllerClass = Controller.class;

        Controller controller = null;

        Method init_ = null;

        try {
            init_ = controllerClass.getDeclaredMethod("_init_", Action.class, HttpServletRequest.class, HttpServletResponse.class, String.class);
            init_.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        Method clear_ = null;
        try {
            clear_ = controllerClass.getDeclaredMethod("_clear_");
            clear_.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            // Controller controller = action.getControllerClass().newInstance();
            controller = controllerFactory.getController(action.getControllerClass());

            if (injectDependency) {
                com.jfinal.aop.Aop.inject(controller);
            }
            init_.invoke(controller, action, request, response, urlPara[0]);

            new Invocation(action, controller).invoke();

            Render render = controller.getRender();
            if (render instanceof ForwardActionRender) {
                String actionUrl = ((ForwardActionRender) render).getActionUrl();
                if (target.equals(actionUrl)) {
                    throw new RuntimeException("The forward action url is the same as before.");
                } else {
                    handle(actionUrl, request, response, isHandled);
                }
                return;
            }

            if (render == null) {
                render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName());
            }
            render.setContext(request, response, action.getViewPath()).render();
        } catch (RenderException e) {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(qs == null ? target : target + "?" + qs, e);
            }
        } catch (ActionException e) {
            handleActionException(target, request, response, action, e);
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(qs == null ? target : target + "?" + qs, e);
            }
            renderManager.getRenderFactory().getErrorRender(500).setContext(request, response, action.getViewPath()).render();
        } finally {
            if (controller != null) {
                try {
                    clear_.invoke(controller);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 抽取出该方法是为了缩短 handle 方法中的代码量,确保获得 JIT 优化,
     * 方法长度超过 8000 个字节码时,将不会被 JIT 编译成二进制码
     * <p>
     * 通过开启 java 的 -XX:+PrintCompilation 启动参数得知,handle(...)
     * 方法(73 行代码)已被 JIT 优化,优化后的字节码长度为 593 个字节,相当于
     * 每行代码产生 8.123 个字节
     */
    private void handleActionException(String target, HttpServletRequest request, HttpServletResponse response, Action action, ActionException e) {
        int errorCode = e.getErrorCode();
        String msg = null;
        if (errorCode == 404) {
            msg = "404 Not Found: ";
        } else if (errorCode == 400) {
            msg = "400 Bad Request: ";
        } else if (errorCode == 401) {
            msg = "401 Unauthorized: ";
        } else if (errorCode == 403) {
            msg = "403 Forbidden: ";
        }

        if (msg != null) {
            if (log.isWarnEnabled()) {
                String qs = request.getQueryString();
                msg = msg + (qs == null ? target : target + "?" + qs);
                if (e.getMessage() != null) {
                    msg = msg + "\n" + e.getMessage();
                }
                log.warn(msg);
            }
        } else {
            if (log.isErrorEnabled()) {
                String qs = request.getQueryString();
                log.error(errorCode + " Error: " + (qs == null ? target : target + "?" + qs), e);
            }
        }

        e.getErrorRender().setContext(request, response, action.getViewPath()).render();
    }
}

最后配置一下

image.png

评论区

JFinal

2018-12-26 17:24

这么快就出来分享了,超赞

有两个改进建议,对于 _init_() _clear_() 的调用,jfinal 早就准备好了工具类:
CPI._init_(....);
CPI._clear_();

省去反射调用, 性能会更好

zhangshiqiang

2018-12-26 17:34

@JFinal 没注意到这个工具类 我调整下

q76267454

2018-12-26 17:38

都是大神

himans

2018-12-26 17:43

@zhangshiqiang 请教这个handler的作用……

JFinal

2018-12-26 17:44

@zhangshiqiang @q76267454 这类隐藏功能,在 jfinal 中到处都是。 多看看源码,能玩出很多创新来

zhangshiqiang

2018-12-26 17:52

@JFinal 好的 在撸一遍代码

JFinal

2018-12-26 17:55

@zhangshiqiang CPI 这个改进证明分享的同时自己也能受益

zhangshiqiang

2018-12-26 18:01

@himans 可以自由定制 处理请求的 ActionHandler 。可以自由发挥

过河

2018-12-27 10:40

昨天才发现有Handler这个东西,不过还没研究明白,收藏

zhangshiqiang

2018-12-27 11:26

@过河 全局请求拦截。责任链设计模式。

过河

2018-12-27 13:16

@zhangshiqiang 嗯呢 正在百度这个

小马奔腾

2019-01-31 11:43

actionMapping 空指针异常