MVC原生实现

JAVAEE实现MVC
java反射机制基础知识 Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods
实现 1. 新建一个DispatcherServlet 并且在类下顶一个

public DispatcherServlet() { actionConfigs.put("question_list.aciton", new ActionConfig("com.gavin.exam.controller.QuestionController","save")); }

2. 将web.xml 中改Servlet的*.action 代表该servlet接收所有以.action结尾的路径。
3. 新建一个Controller 包 并且新建一个XxxxController 定义方法 4. 在common 包下在定义一个classaction.config
package com.gavin.exam.common; public class ActionConfig {private String clsssName; private String methodName; public ActionConfig(String clsssName, String methodName) { this.clsssName = clsssName; this.methodName = methodName; }public String getClsssName() { return clsssName; }public void setClsssName(String clsssName) { this.clsssName = clsssName; }public String getMethodName() { return methodName; }public void setMethodName(String methodName) { this.methodName = methodName; } }

5. 在DispatcherServlet中提取得的地址通过Map查询匹配className 和MethodName。 通过反射机制来达到通过一个servlet来实现整合其他servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); String requestedUri = uri.substring(request.getContextPath().length() + 1); ActionConfig actionConfig = actionConfigs.get(requestedUri); if (actionConfig != null) { String className = actionConfig.getClsssName(); System.out.println(className); try { //定义传入的参数是类型 Class[] param = new Class[2]; param[0] = HttpServletRequest.class; param[1] = HttpServletResponse.class; //根据class名字找到class并且初始化 Class cls = Class.forName(className); Object controller = cls.newInstance(); //获得Reflect的方法,第一个参数是方法名,第二个参数是参数类型 String methodName = actionConfig.getMethodName(); Method method = cls.getMethod(methodName,param); //定义传入的参数 Object[] objects = new Object[2]; objects[0] = request; objects[1] = response; //开始调用方法,第一个参数是调用该方法的对象,第二个 //参数的值 method.invoke(controller, objects); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

这样我们就通过反射机制动态的由访问的路径动态的得到了需要调用来处理的类与方法。
6. controller 中method的实现 首先,讲双H参数传入方法中。
public void showList(HttpServletRequest request, HttpServletResponse response) { System.out.println("showList"); }
之后将servlet中的方法copy到对应方法中,
如果一个servlet 有get 和 post 两个方法,则对应相应的方法放入。
7. 实现所有方法后 DispatcherServlet 中调用get方法
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }

8. MVC优化之controller移走response 在common包中创建一个classModelAndView。代码如下:
package com.gavin.exam.common; public class ModelAndView {private String view; private boolean isRedirect = false; public String getView() { return view; }public void setView(String view) { this.view = view; }public boolean isRedirect() { return isRedirect; }public void setRedirect(boolean isRedirect) { this.isRedirect = isRedirect; } }

将方法中的返回值设为ModelAndView 并将参数HttpServletResponse response 去掉。在DispatcherServlet 中同样也需要去掉参数与参数类型的传入。
同时将method.invoke(controller, objects); 的返回值强制转换:
ModelAndView modelAndView = (ModelAndView)method.invoke(controller, objects);
取得返回数值,根据相应进行sendRedirect orgetRequestDispatcher
String view = modelAndView.getView(); if (modelAndView.isRedirect) { response.sendRedirect(view); } else { request.getRequestDispatcher(view).forward(request, response); }

8. MVC优化之controller移走response 1. 定义暂存session的Map 【MVC原生实现】ModelAndView中再定义一个Map 来暂存session 并设定add和remove方法 提供set
private Map sessions = new HashMap(); public Map getSessions() { return sessions; }public void setSessions(Map sessions) { this.sessions = sessions; }public void addSessionAttribute(String key, Object object) { sessions.put(key, object); }public void removeSessionAttribute(String key){}

2. 定义暂存request.setAttribute andrequest.getParameter的的Map 在ModelAndView中再定义一个Map 来暂存request的参数 并设定add方法。作坊
private Map requests = new HashMap(); public void addRequestAttribute(String key, String value) { requests.put(key, value); }

3.DispatcherServlet 获取暂存在modelAndView中的session
Map fromControllerSession = modelAndView.getSessions(); Set keys = fromControllerSession.keySet(); //get all keys from map for (String key: keys) { session.setAttribute(key, fromControllerSession.get(key)); }

4.DispatcherServlet 获取暂存在modelAndView中的ReuqetsAttr
Map fromControllerRequests = modelAndView.getRequests(); Set keyRequests = fromControllerRequests.keySet(); //get all keys from map for (String key: keyRequests) { request.setAttribute(key, fromControllerRequests.get(key)); }

5. DispatcherServlet 将暂存的session传递到method
Map SessionMap = new HashMap(); Enumeration toSessionkeys = session.getAttributeNames(); while (toSessionkeys.hasMoreElements()) { String toKey = toSessionkeys.nextElement(); SessionMap .put(toKey, session.getAttribute(toKey)); }

6. DispatcherServlet 将Parameter传递到method
Map parameterMap = new HashMap(); Enumeration toReuqestkeys = request.getAttributeNames(); while (toReuqestkeys.hasMoreElements()) { String toKey = toReuqestkeys.nextElement(); parameterMap.put(toKey, request.getParameter(toKey)); }

7. 将SessionMapparameterMap作为参数传入回到其他Method中。
//定义传入参数类型 Class[] param = new Class[2]; param[0] = Map.class; param[1] = Map.class;

//定义传入的参数 Object[] objects = new Object[2]; objects[0] = SessionMap; objects[1] = parameterMap;

9 将method中的参数改为(Map request, Map session)同时返回类型为ModelAndView1 10. DispatcherServlet doGet完整代码 ···
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String uri = request.getRequestURI();
String requestedUri = uri.substring(request.getContextPath().length() + 1);
if (StringUtil.isEmpty(requestedUri)) { requestedUri = Constants.LOGIN_VIEW; } ActionConfig actionConfig = actionConfigs.get(requestedUri); HttpSession session =request.getSession(); if (actionConfig != null) { String className = actionConfig.getClsssName(); try { //定义传入的参数的!类型! Class[] param = new Class[2]; param[0] = Map.class; param[1] = Map.class; Class cls = Class.forName(className); Object controller = cls.newInstance(); String methodName = actionConfig.getMethodName(); Method method = cls.getMethod(methodName, param); //write the session and request and send to method Map SessionMap = new HashMap(); Enumeration toSessionkeys = session.getAttributeNames(); while (toSessionkeys.hasMoreElements()) { String toKey = toSessionkeys.nextElement(); SessionMap.put(toKey, session.getAttribute(toKey)); }Map parameterMap = new HashMap(); Enumeration toReuqestkeys = request.getAttributeNames(); while (toReuqestkeys.hasMoreElements()) { String toKey = toReuqestkeys.nextElement(); parameterMap.put(toKey, request.getParameter(toKey)); }//定义传入的参数 Object[] objects = new Object[2]; objects[0] = SessionMap; objects[1] = parameterMap; ModelAndView modelAndView = (ModelAndView)method.invoke(controller, objects); //get the session and requets from modelAndView Map fromControllerSession = modelAndView.getSessions(); Set keys = fromControllerSession.keySet(); //get all keys from map for (String key: keys) { session.setAttribute(key, fromControllerSession.get(key)); }Map fromControllerRequests = modelAndView.getRequests(); Set keyRequests = fromControllerRequests.keySet(); //get all keys from map for (String key: keyRequests) { request.setAttribute(key, fromControllerRequests.get(key)); }String view = modelAndView.getView(); if (modelAndView.isRedirect) { response.sendRedirect(view); } else { request.getRequestDispatcher(view).forward(request, response); }} catch (Exception e) { e.printStackTrace(); response.sendError(500); } } else { response.sendError(404); } }

···

    推荐阅读