最簡單的mvc框架tiny,增長Aop功能。 css
增長Aop接口,使用是實現便可。 java
而後設置路由(訪問的action)和aop的綁定信息,相似以下: web
下面的意思是把路由"/TinyTest/hello/"和TestAop.class作綁定,這樣執行類TinyTestAction的hello方法時,就會自動執行TestAop的before和after方法。 mvc
下面的BindingAop 的init方法,須要本身設置。系統啓動時會自動讀取。 框架
public class BindingAop { public static void init(){ BindingUtil.binding("/TinyTest/hello/", new Class[]{TestAop.class}); BindingUtil.binding("/TinyTest/*", new Class[]{TestAop2.class}); } }
Aop.java dom
package tiny; import java.util.Map; public interface Aop { void before(Map<String,String> args); void after(Map<String,String> args); }
BindingAop.java async
package tiny; import web.servlet.async_request_war.TestAop; import web.servlet.async_request_war.TestAop2; public class BindingAop { public static void init(){ //BindingUtil.binding("/TinyTest/hello/", new Class[]{TestAop.class}); //BindingUtil.binding("/TinyTest/*", new Class[]{TestAop2.class}); //本身綁定 } }
BindingUtil.java ide
package tiny; public final class BindingUtil { public static void binding(String route,Class[] cls){ if(Container.aops.get(route) != null){ new Exception(route+" 重複"); }else{ Container.aops.put(route,cls); } } }
修改後的Container.java 測試
package tiny; import static java.lang.System.out; import java.io.File; import java.net.URL; import java.util.HashMap; import java.util.Map; public class Container { private static Map<String,Object> clsMap = new HashMap<String,Object>(); static Map<String,Class[]> aops =new HashMap<String,Class[]>(); private static Map<String,Aop[]> reqAops =new HashMap<String,Aop[]>(); public static void init() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ ClassLoader cld = Thread.currentThread().getContextClassLoader(); URL resource = cld.getResource("/"); File dirs = new File(resource.getFile()); findAction(dirs,""); } private static void findAction(File dirs,String basePack) throws ClassNotFoundException, InstantiationException, IllegalAccessException { File[] childs = dirs.listFiles(); for (int i = 0; i < childs.length; i++) { String packPath =basePack+childs[i].getName()+"."; if (childs[i].isDirectory()) { findAction(childs[i],packPath); } else { String className = childs[i].getName(); if (className.endsWith("Action.class")) { packPath=packPath.replace(".class.", ""); Object o = Class.forName(packPath).newInstance(); String clsName = o.getClass().getSimpleName().substring(0,o.getClass().getSimpleName().lastIndexOf("Action")); if(clsMap.get(clsName) != null){ new IllegalAccessException(clsName+" class 重複"); }else{ clsMap.put(clsName, o); } } } } } public static Aop[] getBeforeBinding(String[] route,String key) throws InstantiationException, IllegalAccessException{ Aop[] reqAop = null; Class[] aops1 = aops.get("/"+route[0]+"/"+route[1]+"/"); Class[] aops2 = aops.get("/"+route[0]+"/*"); Class[] aops3 = aops.get("/*"); int aopNum1 = aops1 !=null?aops1.length:0; int aopNum2 = aops2 != null?aops2.length:0; int aopNum3 = aops3 !=null?aops3.length:0; if(aopNum3+aopNum2+aopNum1 !=0){ Class[] allAop = new Class[aopNum3+aopNum2+aopNum1]; if(aopNum3>0){ System.arraycopy(aops3,0,allAop,0,aops3.length); } if(aopNum2>0){ System.arraycopy(aops2,0,allAop,aopNum3,aops2.length); } if(aopNum1>0){ System.arraycopy(aops1,0,allAop,aopNum2+aopNum3,aops1.length); } reqAop = new Aop[allAop.length]; for(int a=0;a<allAop.length;a++){ reqAop[a] = (Aop)allAop[a].newInstance(); } reqAops.put(key, reqAop); } return reqAop; } public static Aop[] getAfterBinding(String key){ return reqAops.get(key); } public static void clearReqAops(String key){ reqAops.remove(key); } public static Object getCls(String name){ return clsMap.get(name); } }
修稿後的FrontControl.java this
package tiny; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //@WebFilter(urlPatterns = { "/demoAsyncLink" }, asyncSupported = true) @WebFilter(urlPatterns = { "/ty/*" }) public class FrontControl implements Filter{ private AtomicBoolean initialized = new AtomicBoolean(); private ServletContext servletContext; @Override public void init(final FilterConfig config) throws ServletException{ try { if (initialized.compareAndSet(false, true)) { this.servletContext = config.getServletContext(); Container.init(); BindingAop.init(); } } catch (Exception e) { throw new ServletException("FrontControl init failed.", e); } } @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws ServletException, IOException{ HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; ContextUtil.setActionContext(servletContext, req, res); try { String[] routes = valid(req); if(routes == null){ chain.doFilter(request, response); return; } Object o = Container.getCls(routes[0]); if(o == null){ chain.doFilter(request, response); return; } Map<String,String> args = this.converter(req.getParameterMap()); String key = UUID.randomUUID().toString(); this.before(routes,args,key); Object result = o.getClass().getMethod(routes[1],Map.class).invoke(o,args); this.after(args,key); Container.clearReqAops(key); if (result==null){ return; } if (result instanceof Renderer) { Renderer r = (Renderer) result; r.render(this.servletContext, req, res); return; } if (result instanceof String) { String s = (String) result; if (s.startsWith("/")) { request.getRequestDispatcher(s).forward(request, response); return; }else{ response.getWriter().print(result); } } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } private Map<String,String> converter(Map<String,String[]> args){ if(args == null){ return null; } Map<String,String> params = new HashMap<String,String>(); for(String key : args.keySet()){ params.put(key, Arrays.toString(args.get(key)).replaceAll("[\\[\\]\\s,]", "")); } return params; } private String[] valid(HttpServletRequest req){ String uri = req.getRequestURI(); String path = req.getContextPath(); if (path != null){ uri = uri.substring(path.length()); }else{ return null; } String[] routes = uri.substring(uri.indexOf("/ty/")+4).split("/"); if(routes == null || routes.length<2){ return null; } return routes; } //aop before private void before(String[] route,Map<String,String> args,String key) throws InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException{ Aop[] aops = Container.getBeforeBinding(route, key); if(aops != null){ for(int a=0;a<aops.length;a++){ aops[a].getClass().getMethod("before",Map.class).invoke(aops[a],args); } } } //aop after private void after(Map<String,String> args,String key) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException{ Aop[] aops = Container.getAfterBinding(key); if(aops != null){ for(int a=0;a<aops.length;a++){ aops[a].getClass().getMethod("after",Map.class).invoke(aops[a],args); } } } @Override public void destroy() { } }
測試類代碼
TinyTestAction.java
package web.servlet.async_request_war; import java.util.Map; import tiny.ContextUtil; public class TinyTestAction { public void hello(Map<String,String> args){ System.out.println("aa:"+args.get("aa")); System.out.println("訪問時間1:"+System.currentTimeMillis()); //ContextUtil.getContext().getXXX; } }
TestAop.java
package web.servlet.async_request_war; import java.util.Map; import tiny.Aop; public class TestAop implements Aop { @Override public void before(Map<String,String> args){ System.out.println(this.getClass().getName()+".before"); } @Override public void after(Map<String,String> args){ System.out.println(this.getClass().getName()+".after"); } }
TestAop2.java
package web.servlet.async_request_war; import java.util.Map; import tiny.Aop; public class TestAop2 implements Aop { @Override public void before(Map<String,String> args){ System.out.println(this.getClass().getName()+".before"); } @Override public void after(Map<String,String> args){ System.out.println(this.getClass().getName()+".after"); } }
測試執行結果截圖:
總結
咱們用最少的類實現了mvc功能,其實應該叫相似mvc功能的模板,更合適。呵呵。
主要用到的就是filter來攔截用戶請求,而後統一處理。servlet也能夠實現,不過filter有個好處是不用本身處理靜態文件的請求。(eternal框架本身處理了靜態請求如css、js)。
0配置,0註解,之前0配置必須是使用註解的,我們使用了servlet3.0的註解方式配置(tiny自身),這樣使用者,根本就不用配置。
aop的實現,更簡單,就是匹配攔截到的路由和用戶本身綁定的,就比較。而後,執行action前置性before,執行action後,執行after,並傳遞參數。
昨天忘記說了,Renderer渲染器,是能夠攜帶數據的,你們一看就明白了。還有就是得使用jee6,由於用到了servlet3.0。
還有就是要實現一個java調用js的功能,相似dwr的,呵呵,實現這個功能後我們在增長一個js文件,tiny就是全部的文件了。
花了1天時間,作的比較粗糙,歡迎你們指導一下。提升下我本身。