30、最简单的mvc框架tiny,增加Aop

Stella981
• 阅读 657

最简单的mvc框架tiny,增加Aop功能。

增加Aop接口,使用是实现即可。

然后设置路由(访问的action)和aop的绑定信息,类似如下:

下面的意思是把路由"/TinyTest/hello/"和TestAop.class做绑定,这样执行类TinyTestAction的hello方法时,就会自动执行TestAop的before和after方法。

下面的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

package tiny;

import java.util.Map;

public interface Aop {
    void before(Map<String,String> args);
    void after(Map<String,String> args);
}

BindingAop.java

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

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

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");
    }
}

测试执行结果截图:

30、最简单的mvc框架tiny,增加Aop

30、最简单的mvc框架tiny,增加Aop

总结

我们用最少的类实现了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天时间,做的比较粗糙,欢迎大家指导一下。提高下我自己。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
CPU推理性能提高数十倍,旷视天元计算图、MatMul优化深度解读
  机器之心发布  机器之心编辑部  !(http://dingyue.ws.126.net/2020/0806/6a6e4896j00qemtzy001ad000p000aop.jpg)本文针对旷视天元深度学习框架在推理优化过程中所涉及的计算图优化与MatMul优化进行深度解读。  背景及引言  在深度学
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这