歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> JFinal - Handler 處理流程

JFinal - Handler 處理流程

日期:2017/3/1 9:11:56   编辑:Linux編程

Handler 處理流程

doFilter - Handler 鏈中每個 handler.handle(...)

容器初始化時訪問 web.xml 配置的 JFinalFilter.doFilter。沿著 Handler 鏈,每個 handler 調用 handle 方法進行處理,然後交給下一個 handler。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    
    // 獲取 request、response,設置編碼
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;
    request.setCharacterEncoding(encoding);
    
    // 初始化的時候可以看出 contextPathLength 為 0 或者為 項目名稱的長度
    // 比如 target = webapp/xx/yy/zz,則截取後的 target = /xx/yy/zz
    String target = request.getRequestURI();
    if (contextPathLength != 0)
        target = target.substring(contextPathLength);
    
    // 在調用了 ActionHandler的 handle 方法之後,isHandled[0] 才會被置為 true。
    boolean[] isHandled = {false};
    try {
        // 重頭戲,handler 鏈首到鏈尾 ActionHandler 依次進行處理
        handler.handle(target, request, response, isHandled);
    }
    catch (Exception e) {
        if (log.isErrorEnabled()) {
            String qs = request.getQueryString();
            log.error(qs == null ? target : target + "?" + qs, e);
        }
    }
    
    // 若最後 isHandled[0] = false,會執行下一個 Filter。
    if (isHandled[0] == false)
        chain.doFilter(request, response);
} 

JFinal 初始化過程中可以 add JFinal 庫中的Handler 或自定義的 Handler。

例如:ContextPathHandler,JFinal 自身擴展的 Handler。

訪問項目時就會走過 handler 方法設置 contextPath。這樣在前端就可以通過 ${CONTEXT_PATH} 得到項目根路徑。

public class ContextPathHandler extends Handler {
    
    private String contextPathName;
    
    public ContextPathHandler() {
        contextPathName = "CONTEXT_PATH";
    }
    
    public ContextPathHandler(String contextPathName) {
        if (StrKit.isBlank(contextPathName))
            throw new IllegalArgumentException("contextPathName can not be blank.");
        this.contextPathName = contextPathName;
    }
    
    public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
        request.setAttribute(contextPathName, request.getContextPath());
        System.out.println("哈哈哈");
        next.handle(target, request, response, isHandled);
    }
} 

FakeStaticHandler,也是 JFinal 自身擴展的 Handler。new FakeStaticHandler 時可定義後綴,訪問路徑 target 必須是以這個後綴結尾才可以進行下去。

public class FakeStaticHandler extends Handler {private String viewPostfix;

public FakeStaticHandler() {
viewPostfix= ".html";
}

public FakeStaticHandler(String viewPostfix) {
if (StrKit.isBlank(viewPostfix))
throw new IllegalArgumentException("viewPostfix can not be blank.");
this.viewPostfix = viewPostfix;
}

public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
if ("/".equals(target)) {
next.handle(target, request, response, isHandled);
return;
}

if (target.indexOf('.') == -1) {
HandlerKit.renderError404(request, response, isHandled);
return ;
}

int index = target.lastIndexOf(viewPostfix);
if (index != -1)
target= target.substring(0, index);
next.handle(target, request, response, isHandled);
}
}

到達 Handler 鏈尾 ActionHandler 處理

訪問交給 Handler 鏈尾 ActionHandler,調用 handle 方法進行處理:根據訪問路徑 target 得到 Action,由 Action 得到 Controller。接著 new Invocation(action, controller).invoke() 進入責任鏈,反射機制調用 Controller 的方法處理(此方法可根據 Action 得到)。

public final void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
if (target.indexOf('.') != -1) {
return ;
}

isHandled[0] = true;
String[] urlPara= {null};

// actionMapping 根據 target 得到對應的 action
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));
}
renderFactory.getErrorRender(404).setContext(request, response).render();
return ;
}

try {
// 由 action 得到對應的 Controller
Controller controller = action.getControllerClass().newInstance();

// Controller 初始化
controller.init(request, response, urlPara[0]);

if (devMode) {
if (ActionReporter.isReportAfterInvocation(request)) {
new Invocation(action, controller).invoke();
ActionReporter.report(controller, action);
}else {
ActionReporter.report(controller, action);
new Invocation(action, controller).invoke();
}
}
else {
// 調用 Controller 相應的處理方法
new Invocation(action, controller).invoke();
}

// 獲取對應的 Render,如果是一個 ActionRender,就再交給 handler 處理;如果 Render == null會按照默認Render處理;
Render render = controller.getRender();
if (render instanceof ActionRender) {
String actionUrl= ((ActionRender)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= renderFactory.getDefaultRender(action.getViewPath() + action.getMethodName());

// 調用 Render 實現類講數據寫入頁面
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) {
int errorCode = e.getErrorCode();
if (errorCode == 404 && log.isWarnEnabled()) {
String qs= request.getQueryString();
log.warn("404 Not Found: " + (qs == null ? target : target + "?" + qs));
}
else if (errorCode == 401 && log.isWarnEnabled()) {
String qs= request.getQueryString();
log.warn("401 Unauthorized: " + (qs == null ? target : target + "?" + qs));
}
else if (errorCode == 403 && log.isWarnEnabled()) {
String qs= request.getQueryString();
log.warn("403 Forbidden: " + (qs == null ? target : target + "?" + qs));
}
else if (log.isErrorEnabled()) {
String qs= request.getQueryString();
log.error(qs== null ? target : target + "?" + qs, e);
}
e.getErrorRender().setContext(request, response, action.getViewPath()).render();
}
catch (Throwable t) {
if (log.isErrorEnabled()) {
String qs= request.getQueryString();
log.error(qs== null ? target : target + "?" + qs, t);
}
renderFactory.getErrorRender(500).setContext(request, response, action.getViewPath()).render();
}
}View Cod

下面看看攔截器鏈如何處理

public class Invocation {

private Action action;
private static final Object[] NULL_ARGS = new Object[0]; // Prevent new Object[0] by jvm for paras of action invocation.

boolean useInjectTarget;
private Object target;
private Method method;
private Object[] args;
private MethodProxy methodProxy;
private Interceptor[] inters;
private Object returnValue = null;

private int index = 0;

// InvocationWrapper need this constructor
protected Invocation() {
this.action = null;
}

public Invocation(Action action, Controller controller) {
this.action = action;
this.inters = action.getInterceptors();
this.target = controller;
this.args = NULL_ARGS;
}

public Invocation(Object target, Method method, Object[] args, MethodProxy methodProxy, Interceptor[] inters) {
this.action = null;
this.target = target;
this.method = method;
this.args = args;
this.methodProxy = methodProxy;
this.inters = inters;
}

public void invoke() {
if (index < inters.length) {
inters[index++].intercept(this);
}
else if (index++ == inters.length) { // index++ ensure invoke action only one time
try {
// Invoke the action
if (action != null) {
returnValue= action.getMethod().invoke(target, args);
}
// Invoke the method
else {
// if (!Modifier.isAbstract(method.getModifiers()))
// returnValue = methodProxy.invokeSuper(target, args);
if (useInjectTarget)
returnValue= methodProxy.invoke(target, args);
else
returnValue= methodProxy.invokeSuper(target, args);
}
}
catch (InvocationTargetException e) {
Throwable t= e.getTargetException();
throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e);
}
catch (RuntimeException e) {
throw e;
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
}

// ... many sets and gets
}

public class AInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}

public class BInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}

public class BInterceptor implements Interceptor  {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking ");
        inv.invoke();
        System.out.println("After invoking ");
    }
}

new Invocation(action, controller).invoke(),由 action 得到攔截器數組,如果數組為空,就可以利用反射機制進入 Controller 的方法進行處理的了;

如果攔截器數組不為空,就會遇到攔截器1 的攔截 - inters[0].intercept(this),數組下標 +1,攔截器1 繼續調用這個 Invocation 實例的 invoke() 方法,並且會在前後加上一些目的性操作;

若下標未越界,接著會遇到攔截器2 的攔截 - inters[1].intercept(this),數組下標 +1,攔截器2 繼續調用這個 Invocation 實例的 invoke() 方法,並且會在前面加上一些目的性操作;

如此繼續直到下標越界,接著反射機制進入 Controller 的方法進行處理。

render(...)

接著上面 ActionHandler.handle 繼續,在 Controller 方法處理的最後,往往要調用 render 方法來實例化 render 變量。例如,我自定義的一個 IndexController,在最後一步調用 render("next.html")。

public class IndexController extends Controller {
    public void index() {
        // ...
        render("next.html");
    }
} 

用到父類 Controller 的 render 方法,通過 renderFactory.getRender 得到 render 實例。

public abstract class Controller {

// ...
// render below ---
private static final RenderFactory renderFactory = RenderFactory.me();

/**
* Hold Render object when invoke renderXxx(...)
*/
private Render render;

public Render getRender() {
return render;
}

/**
* Render with any Render which extends Render
*/
public void render(Render render) {
this.render = render;
}

/**
* Render with view use default type Render configured in JFinalConfig
*/
public void render(String view) {
render= renderFactory.getRender(view);
}

/**
* Render with jsp view
*/
public void renderJsp(String view) {
render= renderFactory.getJspRender(view);
}

/**
* Render with freemarker view
*/
public void renderFreeMarker(String view) {
render= renderFactory.getFreeMarkerRender(view);
}

/**
* Render with velocity view
*/
public void renderVelocity(String view) {
render= renderFactory.getVelocityRender(view);
}

/**
* Render with json
* <p>
* Example:<br>
* renderJson("message", "Save successful");<br>
* renderJson("users", users);<br>
*/
public void renderJson(String key, Object value) {
render= renderFactory.getJsonRender(key, value);
}

/**
* Render with json
*/
public void renderJson() {
render= renderFactory.getJsonRender();
}

/**
* Render with attributes set by setAttr(...) before.
* <p>
* Example: renderJson(new String[]{"blogList", "user"});
*/
public void renderJson(String[] attrs) {
render= renderFactory.getJsonRender(attrs);
}

/**
* Render with json text.
* <p>
* Example: renderJson("{\"message\":\"Please input password!\"}");
*/
public void renderJson(String jsonText) {
render= renderFactory.getJsonRender(jsonText);
}

/**
* Render json with object.
* <p>
* Example: renderJson(new User().set("name", "JFinal").set("age", 18));
*/
public void renderJson(Object object) {
render= object instanceof JsonRender ? (JsonRender)object : renderFactory.getJsonRender(object);
}

/**
* Render with text. The contentType is: "text/plain".
*/
public void renderText(String text) {
render= renderFactory.getTextRender(text);
}

/**
* Render with text and content type.
* <p>
* Example: renderText("&lt;user id='5888'&gt;James&lt;/user&gt;", "application/xml");
*/
public void renderText(String text, String contentType) {
render= renderFactory.getTextRender(text, contentType);
}

/**
* Render with text and ContentType.
* <p>
* Example: renderText("&lt;html&gt;Hello James&lt;/html&gt;", ContentType.HTML);
*/
public void renderText(String text, ContentType contentType) {
render= renderFactory.getTextRender(text, contentType);
}

/**
* Forward to an action
*/
public void forwardAction(String actionUrl) {
render= new ActionRender(actionUrl);
}

/**
* Render with file
*/
public void renderFile(String fileName) {
render= renderFactory.getFileRender(fileName);
}

/**
* Render with file
*/
public void renderFile(File file) {
render= renderFactory.getFileRender(file);
}

/**
* Redirect to url
*/
public void redirect(String url) {
render= renderFactory.getRedirectRender(url);
}

/**
* Redirect to url
*/
public void redirect(String url, boolean withQueryString) {
render= renderFactory.getRedirectRender(url, withQueryString);
}

/**
* Render with view and status use default type Render configured in JFinalConfig
*/
public void render(String view, int status) {
render= renderFactory.getRender(view);
response.setStatus(status);
}

/**
* Render with url and 301 status
*/
public void redirect301(String url) {
render= renderFactory.getRedirect301Render(url);
}

/**
* Render with url and 301 status
*/
public void redirect301(String url, boolean withQueryString) {
render= renderFactory.getRedirect301Render(url, withQueryString);
}

/**
* Render with view and errorCode status
*/
public void renderError(int errorCode, String view) {
throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode, view));
}

/**
* Render with render and errorCode status
*/
public void renderError(int errorCode, Render render) {
throw new ActionException(errorCode, render);
}

/**
* Render with view and errorCode status configured in JFinalConfig
*/
public void renderError(int errorCode) {
throw new ActionException(errorCode, renderFactory.getErrorRender(errorCode));
}

/**
* Render nothing, no response to browser
*/
public void renderNull() {
render= renderFactory.getNullRender();
}

/**
* Render with javascript text. The contentType is: "text/javascript".
*/
public void renderJavascript(String javascriptText) {
render= renderFactory.getJavascriptRender(javascriptText);
}

/**
* Render with html text. The contentType is: "text/html".
*/
public void renderHtml(String htmlText) {
render= renderFactory.getHtmlRender(htmlText);
}

/**
* Render with xml view using freemarker.
*/
public void renderXml(String view) {
render= renderFactory.getXmlRender(view);
}

public void renderCaptcha() {
render= renderFactory.getCaptchaRender();
}
}

根據 Controller 可以看出還能使用 renderJosn、renderText 等多種方法,這裡一筆帶過。

就先寫到這裡吧~~

----- End -----

Jfinal學習之路---Controller使用 http://www.linuxidc.com/Linux/2014-07/104323.htm

JFinal開發8個常見問題 http://www.linuxidc.com/Linux/2015-02/113421.htm

JFinal的詳細介紹:請點這裡
JFinal的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved