继续上一篇的内容
本篇讲述MVC框架的初始化工作
我们可以在我们的核心控制器ActionCore里面的init方法进行初始化
之前说过我们用的是注解实现的而不是用xml,所以我们先新建一个注解
@Retention指定的是注解的声明周期,RUNTIME 意思是在运行时
@Target 表示注解定义在哪,而METHOD则代表方法
其中两个属性代表使用注解的时候的参数都是可选的 但有默认值"",使用如下
相信用过spring mvc 的人看到这里都会比较熟悉,就是当有add这个请求来到的时候会调用这个方法
而method="post" 表示只接收post请求
建好注解之后我们要进行初始化的第一步:
就是扫描所以的类,扫描来干嘛呢? 当然是扫描来映射成一个map集合
你想想我们有好多方法
@NfAction("/add") public void add(){ } @NfAction("/save") public void save(){ } @NfAction("/delete") public void delete(){ }
我们扫描一遍,映射成map集合,就像
"/add":add()
"/save":save()
"/delete":delete()
这样当有一个add请求来的时候就很简单的获取到这个方法啦,
当然我们要记录的不止是这个方法,还有请求方式呢,
要有调用这方法要用到对象,
还有......
既然那么多东西要用到,当然就把他们封装成一个对象啦
我们就叫MyActionMapping
然后提供对应的get/set方法
说到这里,一般写框架都会用到反射,如果不会的朋友,可以先去学学
我们看到其中一个属性paras,就是代表着参数,这里会是我们遇到的第一个难题
学过反射的都知道,我们通过反射应该获取参数是Parameter,可是为什么我要自己写一个Para呢?
因为 Parameter不能获取到参数名,我们映射参数需要用到参数名,所以大家先建一个实体类
而获取参数名我们编写个Util获取需要导入javassist-3.15.0-GA.jar 这个包
具体代码如下
//获取参数名 public static String[] getParaNames(Method m) throws NotFoundException { // 实例化类型池 ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(new ClassClassPath(m.getDeclaringClass())); CtClass ctClass = classPool.get(m.getDeclaringClass().getName()); // 获取方法 CtMethod method = ctClass.getDeclaredMethod(m.getName()); // 判断是否为静态方法 int staticIndex = Modifier.isStatic(method.getModifiers()) ? 0 : 1; // 获取方法的参数 //在得到方法后,返回代表这个方法的文件 MethodInfo methodInfo = method.getMethodInfo(); CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute)codeAttribute.getAttribute(LocalVariableAttribute.tag); String[] names = new String[method.getParameterTypes().length]; for (int i = 0; i < method.getParameterTypes().length; i++) { names[i] = localVariableAttribute.variableName(staticIndex + i); } return names; }
绕了那么远,总体来说就是建立两个实体类,和获取参数名
回到我们的扫描 映射成map
我们扫描所有的class文件
public class ScanUtil { public List<String> scan(String url){ List<String> list = new ArrayList<String>(); //遍历这个文件夹下面的所有文件 list = ergodic(url); //把路径换成类名 return subString(list,url); } //递归遍历文件夹 private List<String> ergodic(String url){ List<String> list = new ArrayList<String>(); File file = new File(url); if(file.isFile()){ if(file.getName().matches(".*\\.class")){ list.add(file.getAbsolutePath()); } }else{ File[] files = file.listFiles(); for (File f : files) { if(f.isFile()){ if(f.getName().matches(".*\\.class")){ list.add(f.getAbsolutePath()); } }else{ List<String> temp = ergodic(url+File.separator+f.getName()); for (String t : temp) { list.add(t); } } } } return list; } //截取字符串 private List<String> subString(List<String> list,String u) { u = u.substring(1); u= u.replace("/","\\"); List<String> paths = new ArrayList<String>(); for (String str : list) { String url = str.replace(".class",""); //换斜杠 String newUrl = url.replace(u,""); String newStr = newUrl.replace("\\","."); paths.add(newStr); } return paths; } }
扫描完然后调用一个方法annotetionMapping
通过反射生成对象获取里面的方法,属性等 封装成Maaping,判断有没有我们的注解,有就放到map集合,就那么简单
private Map<String,MyActionMapping> annotetionMapping(List<String> list){ Map<String,MyActionMapping> map = new HashMap<String,MyActionMapping>(); //遍历这些类 for (String str : list) { Class<?> clazz = null; try { clazz = Class.forName(str); } catch (ClassNotFoundException e) { e.printStackTrace(); } //获取遍历这些类的方法有没有NfAction注解 Method[] meths = clazz.getMethods(); for (Method method : meths) { NfAction myAction = method.getAnnotation(NfAction.class); //如果有NfAction注解 if(myAction != null){ String val = myAction.value(); MyActionMapping mapping = new MyActionMapping(); mapping.setAnnotation(myAction); //获取这个类 mapping.setClazz(clazz); //获取这个类属性 mapping.setFields(clazz.getFields()); //获取这个方法 mapping.setMethod(method); //获取这个方法的参数和参数名 List<Para> paras = new ArrayList<Para>(); String[] names = null; try { names = ParameterUtil.getParaNames(method); } catch (NotFoundException e) { e.printStackTrace(); } Parameter[] ps = method.getParameters(); for(int i=0;i<ps.length;i++){ Para p = new Para(); p.setName(names[i]); p.setPara(ps[i]); paras.add(p); } mapping.setParas(paras); map.put(val,mapping); } } } return map; }
最后把这个封装的结果放到我们Actioncore的成员变量里 Map<String,MyActionMapping> mappingMap;
初始化就OK啦,之后有请求来从这个map里获取就OK啦
讲的有些凌乱,不懂的话多看几遍,因为写框架本来就不是容易的事,这只是刚刚开始
我也写了几个月,下一篇,就会讲解如何处理请求和映射表单提交的参数