一步一步编写自己的Web MVC框架——Action中方法的装载

来源:互联网 发布:苹果anywhere软件 编辑:程序博客网 时间:2024/06/06 16:24

我准备用一个@MyActionde 的注解,来配上需要装载进入方法容器的类,自定义在类上写上@MyAction(value="/root"),则代码访问该类需要"/root"根路径,然后在方法上加上@MyAction(value = "/test"),表示执行该方法的路径为,“/root/test”。


package action;import myframe.annotation.MyAction;import myframe.annotation.MyMethod;/** * Created by yuyufeng on 2017/5/5. */@MyAction(value="/root")public class TestAction {    @MyAction(value = "/test")    public String testMyMethod() {        System.out.println("TestAction.testMyMethod");        return "index";    }    @MyAction(value = "/test2")    public String testMyMethod2() {        System.out.println("TestAction.testMyMethod2");        return "test";    }}

在容器map中,设计路径为键,要执行的类方法为值。

注解MyAction

package myframe.annotation;import java.lang.annotation.*;/** * Created by yuyufeng on 2017/5/5. */@Target({ElementType.TYPE, ElementType.METHOD})@Retention(value = RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface MyAction {    String value() default  "";}

Map容器中值为类方法,所以先设计类结构ActionBean如下:

package myframe.bean;import java.lang.reflect.Method;/** * Created by yuyufeng on 2017/5/5. */public class ActionBean {    private Class<?> clazz;    private Method method;    public ActionBean(Class<?> clazz, Method method) {        this.clazz = clazz;        this.method = method;    }    public Class<?> getClazz() {        return clazz;    }    public void setClazz(Class<?> clazz) {        this.clazz = clazz;    }    public Method getMethod() {        return method;    }    public void setMethod(Method method) {        this.method = method;    }}


整理一下思路就是,通过uri去执行一个对象实例中的某个方法。
所以,我们需要两个容器。一个容器装载Action类实例,一个容器装载uri和ActionBean。

因为我们是通过方法调用的,所以只需要一个实例就好,一个Action放如一个实例到容器即可。(这个容器也类似Spring的IOC管理bean)

在反射过程中,我们需要从项目的package中获取带有@MyAction注解的类和方法,我们需要一个类扫描器,

类扫描工具类如下:

ClassUtil.java


我们执行一个junit测试类,去执行扫描执行。

Action实例:

package action;import myframe.annotation.MyAction;/** * Created by yuyufeng on 2017/5/5. */@MyAction(value="/root")public class TestAction {    @MyAction(value = "/test")    public String testMyMethod() {        System.out.println("TestAction.testMyMethod");        return "index";    }    @MyAction(value = "/test2")    public String testMyMethod2() {        System.out.println("TestAction.testMyMethod2");        return "test";    }}

test:

import myframe.annotation.MyAction;import myframe.bean.ActionBean;import myframe.commons.ClassUtil;import org.junit.Test;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Set;/** * Created by yuyufeng on 2017/5/5. */public class TestAnno {    private static Map<String, ActionBean> map = new HashMap<String, ActionBean>();    private static Map<Class<?>, Object> objectMap = new HashMap<Class<?>, Object>();    @Test    public void test() throws IllegalAccessException, InstantiationException {        Set<Class<?>> classes = ClassUtil.getClasses("action");        for (Class<?> aClass : classes) {            System.out.println(aClass);            if (aClass.isAnnotationPresent(MyAction.class)) {                MyAction mac = aClass.getAnnotation(MyAction.class);                String classAnnoValue = mac.value().trim();                objectMap.put(aClass,aClass.newInstance());                for (Method method : aClass.getMethods()) {                    if (method.isAnnotationPresent(MyAction.class)) {                        MyAction mam = method.getAnnotation(MyAction.class);                        String methodAnnoValue = mam.value().trim();                        String actionName = classAnnoValue + methodAnnoValue;                        map.put(actionName,new ActionBean(aClass,method));                    }                }            }        }        ActionBean ab = map.get("/root/test2");        System.out.println(ab);        try {            String result= (String) ab.getMethod().invoke(objectMap.get(ab.getClazz()));            System.out.println(result);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }}


执行结果:

Connected to the target VM, address: '127.0.0.1:59438', transport: 'socket'class action.TestActionmyframe.bean.ActionBean@475530b9TestAction.testMyMethod2testDisconnected from the target VM, address: '127.0.0.1:59438', transport: 'socket'Process finished with exit code 0

到这一步,根据uri反射执行类方法已经初步实现。

这些方法在框架初始化阶段执行装载即可。

建立一个初始化执行类:

package myframe.init;import myframe.annotation.MyAction;import myframe.bean.ActionBean;import myframe.commons.ClassUtil;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Set;/** * Created by yuyufeng on 2017/5/5. */public class MyFrameInit {    private static Map<String, ActionBean> actionMap;    private static Map<Class<?>, Object> objectMap;    public static Object getObject(Class<?> clazz) {        return objectMap.get(clazz);    }    public static ActionBean getActionBean(String key) {        return actionMap.get(key);    }    public static void init() throws IllegalAccessException, InstantiationException {        actionMap = new HashMap<String, ActionBean>();        objectMap = new HashMap<Class<?>, Object>();        Set<Class<?>> classes = ClassUtil.getClasses("action");        for (Class<?> aClass : classes) {            System.out.println(aClass);            if (aClass.isAnnotationPresent(MyAction.class)) {                MyAction mac = aClass.getAnnotation(MyAction.class);                String classAnnoValue = mac.value().trim();                objectMap.put(aClass, aClass.newInstance());                for (Method method : aClass.getMethods()) {                    if (method.isAnnotationPresent(MyAction.class)) {                        MyAction mam = method.getAnnotation(MyAction.class);                        String methodAnnoValue = mam.value().trim();                        String actionName = classAnnoValue + methodAnnoValue;                        actionMap.put(actionName, new ActionBean(aClass, method));                    }                }            }        }        System.out.println("MyFrameInit.init==================初始化完毕");    }}


然后,我们在入口Servlet第一次执行的时候去调用初始化方法:

public class MyFrameServlet extends HttpServlet {    @Override    public void init(ServletConfig config) throws ServletException {        try {            MyFrameInit.init();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        }    }


入口Servlet的doGet完善

@Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //获取要执行的动作        String uri = req.getRequestURI();        String actionName = uri.substring(0, uri.indexOf(".do"));        System.out.println("访问Action:" + actionName);        //do        ActionBean actionBean = MyFrameInit.getActionBean(actionName);        String result = "";        try {            result = (String) actionBean.getMethod().invoke(MyFrameInit.getObject(actionBean.getClazz()));        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }        //return        String fileName = result;        System.out.println("执行完毕,跳转路径"+"/WEB-INF/jsp/" + fileName + ".jsp");        req.getRequestDispatcher("/WEB-INF/jsp/" + fileName + ".jsp").forward(req, resp);    }


配置tomcat,启动

访问http://127.0.0.1:8080/root/test.do

访问http://127.0.0.1:8080/root/test2.do

日志打印:

class action.TestActionMyFrameInit.init==================初始化完毕访问Action:/root/testTestAction.testMyMethod执行完毕,跳转路径/WEB-INF/jsp/index.jsp访问Action:/root/test2TestAction.testMyMethod2执行完毕,跳转路径/WEB-INF/jsp/test.jsp

现在,页面的控制以及服务器方法的执行已经成功了。





 
阅读全文
1 0
原创粉丝点击