一步一步编写自己的Web MVC框架——属性自动获取和传递

这篇文章将进行属性的获取与返回的开发。

在Servlet中,属性是通过request中的parameterMap获取的。通过  request.getParameter("name名称") 取得,还不知道获取的类型。

在Struts2中,是用过类的字段获取,或者模型驱动获取自定义的实体类。

在Spring MVC中,我们是通过方法参数的名称去实现的。


在我这次的开发中,我打算使用类似Spring MVC的方式。(由于java 中 的方法的参数的名称是无法获取到的,要从文件中的名称获取或者其它方式,在 编译之前就拿到,这样让新手很难理解)所以,我使用了注解的方式去获取。

https://github.com/yyfyyf1994/MyWebFrame

首先,在html中写一个表单

<form action="/user/add.do" method="post">
    用户ID:<input type="text" name="userId">
    <br>用户名:<input type="text" name="userName">
    <br>备注信息:<input type="text" name="note">
    <br><input type="submit" value="提交">
</form>


然后,我们需要一个处理此post请求的Action

@MyAction("/user")
public class UserAction {
    private static List<User> users = new ArrayList<User>();

    static {
        for (long i = 0; i < 8; i++) {
            users.add(new User(i, "用户" + i));
        }
    }

    @MyAction("/list")
    public Model userList() {
        Model model = new Model();
        model.addAttribute("users", users);
        model.setReturnPath("user/list");
        return model;
    }

    @MyAction("/add")
    public Model userAdd(@MyParam("user") User user, @MyParam("note") String note) {
        Model model = new Model();
        model.addAttribute("message", "增加用户成功!");
        users.add(user);
        System.out.println("note:"+note);
        model.addAttribute("users", users);
        model.setReturnPath("user/list");
        return model;
    }
}


,如果直接在网页中调试开发,比较蛮烦。我们直接模拟一个request的parameterMap,并往里面填好参数。下面是测试实现过程

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class clazz = UserAction.class;
        Object object = clazz.newInstance();

        Method method = clazz.getMethod("userAdd", User.class, String.class);

        Annotation[][] annotations = method.getParameterAnnotations();
        Class<?>[] classes = method.getParameterTypes();

        Map<String, String[]> reqMap = new HashMap<String, String[]>();
        reqMap.put("userId", new String[]{"123"});
        reqMap.put("userName", new String[]{"用户1"});
        reqMap.put("note", new String[]{"这是备注信息"});


        Object[] prarms = new Object[classes.length];

        for (int i = 0; i < classes.length; i++) {
            //获取方法上参数的注解
            MyParam myParam = (MyParam) annotations[i][0];
            Class<?> clz = classes[i];
//            System.out.println(clz + " " + myParam.value());
            Object cob = null;
            //如果是基本类型
            if (ConvertFactory.isJavaClass(clz)) {
                for (String s : reqMap.keySet()) {
                    //找到对应的参数
                    if (myParam.value().equals(s)) {
                        try {
                            cob = ConvertFactory.convert(clz, reqMap.get(s)[0]);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    //填充数据
                    prarms[i] = cob;
                }
            } else if (clz == List.class) {
                //如果是集合类
            } else {
                //如果是自定义实体
                Object paramObject = clz.newInstance();
                LoadUtil.getMyObject(reqMap, clz, paramObject);
                prarms[i] = paramObject;
            }


        }


        method.invoke(object, prarms);
    }

LoadUtil.java

package myframe.commons;

import myframe.annotation.MyParam;
import myframe.convert.ConvertFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * Created by yuyufeng on 2017/5/18.
 */
public class LoadUtil {
    /**
     * 参数装载
     * @param reqMap
     * @param method
     * @param prarms
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static void loadParams(Map<String, String[]> reqMap, Method method, Object[] prarms) throws InstantiationException, IllegalAccessException {
        Class<?>[] classes = method.getParameterTypes();
        Annotation[][] annotations = method.getParameterAnnotations();
        for (int i = 0; i < classes.length; i++) {
            //获取方法上参数的注解
            MyParam myParam = (MyParam) annotations[i][0];
            Class<?> clz = classes[i];
//            System.out.println(clz + " " + myParam.value());
            Object cob = null;
            //如果是基本类型
            if (ConvertFactory.isJavaClass(clz)) {
                for (String s : reqMap.keySet()) {
                    //找到对应的参数
                    if (myParam.value().equals(s)) {
                        try {
                            cob = ConvertFactory.convert(clz, reqMap.get(s)[0]);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    //填充数据
                    prarms[i] = cob;
                }
            } else if (clz == List.class) {
                //如果是集合类
            } else {
                //如果是自定义实体
                Object paramObject = clz.newInstance();
                getMyObject(reqMap, clz, paramObject);
                prarms[i] = paramObject;
            }


        }
    }
    //自定义对象装载
    public static void getMyObject(Map<String, String[]> reqMap, Class<?> clz, Object paramObject) {
        List<Method> methods = GetterSetterUtil.setter(clz);
        for (Method method1 : methods) {
            Class<?> method1PrarmType = method1.getParameterTypes()[0];
            String pName = GetterSetterUtil.getPropertyName(method1);
            for (String s : reqMap.keySet()) {
                //判断对象里面有getParam方法
                if (pName.equals(s)) {
                    //对象里面的参数也是基本类型。如果自定义对象里面还有自定义对象,则此处需要做递归处理
                    if (ConvertFactory.isJavaClass(method1PrarmType)) {
                        try {
                            method1.invoke(paramObject, ConvertFactory.convert(method1PrarmType, reqMap.get(s)[0]));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

我们在方法里面添加上打印信息,以确定执行过该方法,并且成功传递了参数

 @MyAction("/add")
    public Model userAdd(@MyParam("user") User user, @MyParam("note") String note) {
        Model model = new Model();
        model.addAttribute("message", "增加用户成功!");
        users.add(user);
        System.out.println("note:"+note);
        System.out.println("user:"+user);
        model.addAttribute("users", users);
        model.setReturnPath("user/list");
        return model;
    }

执行之后,控制台信息:


Connected to the target VM, address: '127.0.0.1:64455', transport: 'socket'
note:这是备注信息
user:User{userId=123, userName='用户1'}
Disconnected from the target VM, address: '127.0.0.1:64455', transport: 'socket'

Process finished with exit code 0

可以看到,我们的方法已经执行了。并且。参数也成功传递了。


然后,我们需要将参数传递给页面,我也构造了一个Model类,去传递(类似Spring MVC),这样就方便很多

package myframe.bean;

import myframe.enums.ReturnTypeEnum;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by yuyufeng on 2017/5/17.
 */
public class Model {
    private ReturnTypeEnum returnType = ReturnTypeEnum.forward; //响应类型
    private String returnPath; //返回路径

    private Map<String, Object> map = new HashMap<String, Object>();

    public void addAttribute(String var1, Object var2) {
        map.put(var1, var2);
    }

    public Map<String, Object> getModelMap() {
        return map;
    }

    public ReturnTypeEnum getReturnType() {
        return returnType;
    }

    public void setReturnType(ReturnTypeEnum returnType) {
        this.returnType = returnType;
    }

    public String getReturnPath() {
        return returnPath;
    }

    public void setReturnPath(String returnPath) {
        this.returnPath = returnPath;
    }
}


在Servlet入口类中,这么返回:

//判断返回的类型,然后执行不同的动作
            if (returnType == Model.class) {
                Model modelResult = (Model) result;
                path = modelResult.getReturnPath();
                //重定向
                if (modelResult.getReturnType() == ReturnTypeEnum.redirect) {
                    System.out.println("执行重定向完毕,跳转路径" + path);
                    resp.sendRedirect(path);
                }
                //设置属性
                for (String s : modelResult.getModelMap().keySet()) {
                    req.setAttribute(s, modelResult.getModelMap().get(s));
                }
            } else if (returnType == String.class) {
                path = (String) result;
            }


        System.out.println("执行完毕,跳转路径" + "/WEB-INF/jsp/" + path + ".jsp");  ///WEB-INF/jsp/这些暂时写死,到时候可以到配置中获取
        req.getRequestDispatcher("/WEB-INF/jsp/" + path + ".jsp").forward(req, resp);

这样我们的参数就可以成功传递到request的attribute里面了

 


现在在整理一下入口Servlet中的doGet()

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        //获取要执行的动作
        String uri = req.getRequestURI();
        String actionName = uri.substring(0, uri.indexOf(".do"));
        System.out.println("访问ActionMethod:" + actionName);
        //do
        String path = "";
        ActionBean actionBean = MyFrameInit.getActionBean(actionName);
        Object result;
        try {
            Class<?> returnType = actionBean.getMethod().getReturnType();

            //执行方法的参数填充
            Map<String, String[]> reqMap = req.getParameterMap();

            Object[] prarms = new Object[actionBean.getMethod().getParameterTypes().length];
            //参数装载
            LoadUtil.loadParams(reqMap, actionBean.getMethod(), prarms);

            result = actionBean.getMethod().invoke(MyFrameInit.getObject(actionBean.getClazz()), prarms);


            //判断返回的类型,然后执行不同的动作
            if (returnType == Model.class) {
                Model modelResult = (Model) result;
                path = modelResult.getReturnPath();
                //重定向
                if (modelResult.getReturnType() == ReturnTypeEnum.redirect) {
                    System.out.println("执行重定向完毕,跳转路径" + path);
                    resp.sendRedirect(path);
                }
                //设置属性
                for (String s : modelResult.getModelMap().keySet()) {
                    req.setAttribute(s, modelResult.getModelMap().get(s));
                }
            } else if (returnType == String.class) {
                path = (String) result;
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }


        System.out.println("执行完毕,跳转路径" + "/WEB-INF/jsp/" + path + ".jsp");  ///WEB-INF/jsp/这些暂时写死,到时候可以到配置中获取
        req.getRequestDispatcher("/WEB-INF/jsp/" + path + ".jsp").forward(req, resp);
    }

建立的测试Action 

package action;

import entity.User;
import myframe.annotation.MyAction;
import myframe.annotation.MyParam;
import myframe.bean.Model;
import myframe.commons.GetterSetterUtil;
import myframe.commons.LoadUtil;
import myframe.convert.ConvertFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by yuyufeng on 2017/5/17.
 */
@MyAction("/user")
public class UserAction {
    private static List<User> users = new ArrayList<User>();

    static {
        for (long i = 0; i < 8; i++) {
            users.add(new User(i, "用户" + i));
        }
    }

    @MyAction("/list")
    public Model userList() {
        Model model = new Model();
        model.addAttribute("users", users);
        model.setReturnPath("user/list");
        return model;
    }

    @MyAction("/add")
    public Model userAdd(@MyParam("user") User user, @MyParam("note") String note) {
        Model model = new Model();
        model.addAttribute("message", "增加用户成功!");
        users.add(user);
        System.out.println("note:"+note);
        System.out.println("user:"+user);
        model.addAttribute("users", users);
        model.setReturnPath("user/list");
        return model;
    }


    


}

部署启动tomcat

输入http://127.0.0.1:8080/user/list.do

MyFrameInit.init==================初始化完毕
访问ActionMethod:/user/list
执行完毕,跳转路径/WEB-INF/jsp/user/list.jsp


输入信息增加一个用户,点击提交

访问ActionMethod:/user/add
note:备注~
user:User{userId=123, userName='测试用户'}
执行完毕,跳转路径/WEB-INF/jsp/user/list.jsp



这样,MyFrame框架的属性自动获取和传递功能基本已经编写完毕



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值