大多數框架都是經過註解,反射來實現不少框架功能的,在咱們這個框架中,咱們能夠經過註解來標識不一樣的層,以及每一個路徑所對應的方法。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"; } }