大多数框架都是经过注解,反射来实现不少框架功能的,在咱们这个框架中,咱们能够经过注解来标识不一样的层,以及每一个路径所对应的方法。html
参考spring的@Controller和RequestMapping,咱们这个框架也能够自定义这两个注解,首先定义一个控制层注解@MyMontroller,这个注解做用于类,主要做用是标识某个类是否为控制层。java
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyController { String name() default ""; }
以后定义一个方法级注解@MyRequestMapping,这个注解用于做用于方法,主要做用就是标识某个请求路径所对应的处理这个请求的方法。web
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestMapping { String path() default ""; RequestMethod[] method() default {}; }
注解中有两个值,path为请求路径,method为请求方式,这里咱们会定义一个枚举变量RequestMethod来记录通常的请求方式spring
public enum RequestMethod { GET,POST,PUT,DELETE }
最后还定义了一个注解@MyResponseString用于标识方法是返回一个字符串仍是一个页面app
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyResponseString { }
至此Controller层基本的注解大概定义完了,接下来的事情就是在容器初始化的时候经过反射来获取每一个路径以及每一个路径所对应的注解,储存为list类型而后保存到ServletContext中框架
首先定义一个AnnotationUtil类来处理注解,以后再定义一个监听器AnnotationListener用于容器启动时执行AnnotationUtil中对应的方法jsp
public class AnnotationListener implements ServletContextListener{ @Override public void contextInitialized(ServletContextEvent servletContextEvent) { } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { } }
web.xml配置ide
<listener> <listener-class>com.example.listener.AnnotationListener</listener-class> </listener>
这里咱们开始编写AnnotionUtil,先说一下总体的流程:最开始咱们须要定义一个变量stringList,来储存结果集,以后经过反射来读取controller目录下全部的类,最后再扫描这些类获取结果集。this
public class AnnotationUtil { private List<String> stringList; private List<Class> getClassList(String dir, String srcPath) throws ClassNotFoundException { List<Class> classList = new ArrayList<Class>(); String newDir = dir.replace(".","/"); String abSolutePath = srcPath + newDir; //构成完整路径 //file:/E:/dev/testServlet/out/artifacts/testServlet_war_exploded/WEB-INF/classes/src/com/example/myController //去除srcPath 获取到的字符串前缀file:/ String ss = abSolutePath.substring(6, abSolutePath.length()); abSolutePath = ss.replace("/",File.separator); File dirFile = new File(abSolutePath); File[] files = dirFile.listFiles(); Class<?> cla = null; for (File file:files){ //遍历文件夹里面的全部文件遇到文件夹则向下查找 if (file.isDirectory()){ String child = dir + "."+file.getName(); getClassList(child, getSrcPath()); }else { cla = Class.forName(dir+"."+file.getName().split("\\.")[0]); classList.add(cla); } } return classList; } private String getSrcPath(){ String path=""; try { path =Thread.currentThread().getContextClassLoader().getResource("")+""; //获取src路径 } catch (Exception e) { e.printStackTrace(); } return path; } private void setRequestMapping(List<Class> list) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException { for (Class<?> cla:list){ if (cla.getAnnotation(MyController.class)!=null){ //是否有MyController注解 Method[] methods = cla.getMethods(); for (Method method : methods){ if (method.getAnnotation(MyRequestMapping.class)!=null){//判断方法上是否有@MyRequestMapping MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class); if (method.getAnnotation(MyResponseString.class) != null){//判断方法上是否有@MyResponseString stringList.add(annotation.path()+" "+annotation.method()[0].toString()+" "+ SystemConfig.ResponseString+" "+cla.getName()+" "+method.getName()); }else { stringList.add(annotation.path()+" "+annotation.method()[0].toString()+" "+SystemConfig.ResponsePage+" "+cla.getName()+" "+method.getName()); } } } } } } public List<String> getRequestMapping(){ stringList = new ArrayList<String>(); List<Class> list = null; try { list = getClassList("com.example.myController", getSrcPath());//获取com.example.myController目录下全部的类 setRequestMapping(list);//选择符合条件的类,而且把类中全部的路劲,方法储存到list中 } catch (Exception e) { e.printStackTrace(); } return stringList; } }
AnnotionUtil中获取的List<String>里面有请求路径,请求方式,是否返回字符串,路径对应的类名,路径对应的处理方法,以后咱们须要把它存储在ServletContext 中,在以前定义的监听器AnnotationListener 中spa
public class AnnotationListener implements ServletContextListener{ private ServletContext servletContext; @Override public void contextInitialized(ServletContextEvent servletContextEvent) { List<String> list = new AnnotationUtil().getRequestMapping(); this.servletContext = servletContextEvent.getServletContext(); servletContext.setAttribute("annotationList",list); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { } }
以后咱们就能够经过getServletContext().getAttribute("annotationList");来获取路径以及其对应的方法了。
@MyController public class RequestController { @MyResponseString @MyRequestMapping(path = "/zhu/test1",method = RequestMethod.GET) public String testA(HttpServletRequest httpServletRequest){ return "xx"; } @MyRequestMapping(path = "/zhu/test",method = RequestMethod.GET) public String testOne(){ return "index.jsp"; } @MyRequestMapping(path = "/zhu/test",method = RequestMethod.POST) public String testOnea(){ return "cao.html"; } @MyRequestMapping(path = "/zhu/html_test",method = RequestMethod.GET) public String testOneaa(){ return "xxx.html"; } }