简单的一个轮子MVC

本文介绍了一个简单的 J2EE MVC 架构中的路由和 IOC 容器实现方法。通过类扫描和注解,实现了路径与控制类的映射,并介绍了如何在初始化时构建路由表。

这里是一个简单的J2EE MVC实现例子数据库部分没有写,算是个玩具。

  1. 路由的简单实现

    这里把路由抽象出来 路径、请求类型(GET、POST)、路径的事例对象、以及请求对应的执行方法

public class Route {

	/**
	 * 路径
	 */
	private String path;
	
	/**
	 * 执行方法
	 */
	private String method;

	/**
	 * 方法类型
	 */
	private String type;
	
	/**
	 * action控制类
	 */
	private Object action;
}

在项目初始化的时候用一个Filter来拦截请求,初始化的时候进行类扫描,扫描的部分是有路径注解的类。

这里配置的时候初始化一个Action的路径(这里的ACTION路径扫描没有进行全路径就是获取子文件夹中,

下面简单的IOC注入加了点东西全路径扫描)

/**
	 * 通过一个包路径扫描所有的类
	 * @param path
	 * @return
	 */
   public List<Route> getAllRoutes(String packageDirName){
	   Enumeration<URL> dirs;
	   List<Route> routeList=new ArrayList<Route>();
       try {
    	   packageDirName=packageDirName.replace('.', '/');
           dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
           while (dirs.hasMoreElements()) {
               // 获取下一个元素
               URL url = dirs.nextElement();
               // 得到协议的名称
               String protocol = url.getProtocol();
               // 如果是以文件的形式保存在服务器上
               if ("file".equals(protocol)) {
                   // 获取包的物理路径
                   String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                   // 以文件的方式扫描整个包下的文件 并添加到集合中
                   File[] files=new File(filePath).listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						if(name.endsWith(".class")) {
							return true;
						}
						return false;
					}
                	   
                   }); 
                   for(File f:files) {
                    this.logger.info("扫描文件:"+f.getPath());
//                   if(filePath.endsWith(".class")) {
                    this.logger.info("扫描类路径:"+packageDirName.replace('/', '.')+"."+f.getName().substring(0, f.getName().lastIndexOf('.')));
                	   Class cl=Class.forName(packageDirName.replace('/', '.')+"."+f.getName().substring(0, f.getName().lastIndexOf('.')));
                	   PathAnnotation pa=(PathAnnotation) cl.getAnnotation(PathAnnotation.class);
                	   String routPath="";
                	   String beforePath="";
                	   if(null!=pa) {
                		   routPath=pa.path();
                		   beforePath=routPath;
                	   }
                	   Method[] methods=cl.getMethods();
                	   for(Method m:methods) {
                		   routPath=beforePath;
                		   pa=m.getAnnotation(PathAnnotation.class);
                		   if(null==pa) {
                			   continue;
                		   }
                		   routPath+="/"+pa.path();
                		   Route rt=new Route(routPath,m.getName(),pa.type(),cl.newInstance());
                		   logger.info("加载路由:"+rt.toString());
                		   routeList.add(rt);
                		   }
                	   }
                   }
//                   }
               }
            } 
       }catch (Exception e) {
    	    e.printStackTrace();
	 }
	   return routeList;
   }  

当后台路径初始化后,

获取请求的路径进行匹配

匹配上了执行相应的方法(这里简单的实现保留了之前servlet的调用用到了request,response对象)

这里想到的如何可以避开request,response参数,直接使用普通的类,首先要获取参数的属性,这里通过

获取参数属性和前台对应的数据是一直的(这里指的是属性名字),是否可以直接反射过去执行相应得方

法,后面在尝试

这里是一个

这里的做法是可以编译的时候添加参数-g,但是这样做的别人反编译会存在一个信息泄露的问题
public class Test {

	public static void main(final String[] arguments) throws Exception {  
        Class<?> clazz = Test.class;  
        Method method = clazz.getDeclaredMethod("test", String.class, int.class);  
        System.out.print("test : ");  
        Parameter[] parameters = method.getParameters();  
        for (final Parameter parameter : parameters) {  
                System.out.print(parameter.getName() + ' ');  
        }  
    }  
  
    public static void test(String param1, int param2) {  
        System.out.println(param1 + param2);
    }
}

获取采用注解的方式,参数添加注解
   public void test(@Parameter("param1") String param1,  
            @Parameter("param2") int param2) {  
        System.out.println(param1 + param2);  
    }  

获取采用其他方式

RouteUtil ru=new RouteUtil();
		Route rt=ru.findRoute(request.getServletPath());
		if(null!=rt) {
			System.out.println(rt.toString());
           Object o=rt.getAction();
           try {
			Method m=o.getClass().getDeclaredMethod(rt.getMethod(),HttpServletRequest.class,HttpServletResponse.class);
			if(o.getClass().isInstance(Proxy.class)) {
				m.invoke(o.getClass().newInstance(),request,response);
			}else {
				m.invoke(o,request,response);
			}
  1. IOC这里简单的实现

    这里也扫描所有有注解定义(自动注入的注解)

    首先扫描保存起来,然后遍历注入,这里加了点代码直接遍历了子文件夹

 /**
	 * 通过一个包路径扫描所有的注入类
	 * @param path
	 * @return
	 */
  public Map<String,Object> getAllAop(String packageDirName){
	   Enumeration<URL> dirs;
	   Map<String,Object> aopMap=new HashMap<String,Object>();
      try {
   	   packageDirName=packageDirName.replace('.', '/');
          dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
          while (dirs.hasMoreElements()) {
              // 获取下一个元素
              URL url = dirs.nextElement();
              // 得到协议的名称
              String protocol = url.getProtocol();
              // 如果是以文件的形式保存在服务器上
              if ("file".equals(protocol)) {
                  // 获取包的物理路径
                  String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                  //以文件的方式扫描整个包下的文件 并添加到集合中
                  File[] files=new File(filePath).listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						if(name.endsWith(".class")|| dir.isDirectory()) {
							return true;
						}
						return false;
					}
               	   
                  });
                 
                  for(File f:files) {
                   if(f.isDirectory()) {
                	   aopMap.putAll(this.getAllAop(packageDirName+"."+f.getName()));   
//                       return aopMap;
                   }else {
                   
                   this.logger.info("扫描文件:"+f.getPath());
//                  if(filePath.endsWith(".class")) {
                   this.logger.info("扫描类路径:"+packageDirName.replace('/', '.')+"."+f.getName().substring(0, f.getName().lastIndexOf('.')));
               	   Class cl=Class.forName(packageDirName.replace('/', '.')+"."+f.getName().substring(0, f.getName().lastIndexOf('.')));
               	   AopAnnotation pa=(AopAnnotation) cl.getAnnotation(AopAnnotation.class);
               	   if(null!=pa) {
               		   String className=pa.value();
               		   if(aopMap.containsKey(className)) {
               			   throw new Exception("注入类重复");
               		   }else {
               			   aopMap.put(className, cl.newInstance());
               		   }
               	   }else {
               		   continue;
               	   }
                   }
                  }
//                  }
              }
           } 
      }catch (Exception e) {
   	    e.printStackTrace();
	 }
	   return aopMap;
  }

3.AOP这里的实现

这里通过代理机制来实现,这里使用的是JAVA自带的代理模式,需要接口实现

转载于:https://my.oschina.net/findurl/blog/1791243

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值