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的<url-pattern>*.action</url-pattern>
代表该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
在ModelAndView
中再定义一个Map
来暂存session 并设定add和remove方法 提供set
private Map<String, Object> sessions = new HashMap<String, Object>();
public Map<String, Object> getSessions() {
return sessions;
}
public void setSessions(Map<String, Object> 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<String, String> requests = new HashMap<String, String>();
public void addRequestAttribute(String key, String value) {
requests.put(key, value);
}
3.DispatcherServlet
获取暂存在modelAndView
中的session
Map<String,Object> fromControllerSession = modelAndView.getSessions();
Set<String> keys = fromControllerSession.keySet(); //get all keys from map
for (String key: keys) {
session.setAttribute(key, fromControllerSession.get(key));
}
4.DispatcherServlet
获取暂存在modelAndView
中的ReuqetsAttr
Map<String,String> fromControllerRequests = modelAndView.getRequests();
Set<String> keyRequests = fromControllerRequests.keySet(); //get all keys from map
for (String key: keyRequests) {
request.setAttribute(key, fromControllerRequests.get(key));
}
5. DispatcherServlet
将暂存的session传递到method
Map<String, Object> SessionMap = new HashMap<String, Object>();
Enumeration<String> toSessionkeys = session.getAttributeNames();
while (toSessionkeys.hasMoreElements()) {
String toKey = toSessionkeys.nextElement();
SessionMap .put(toKey, session.getAttribute(toKey));
}
6. DispatcherServlet
将Parameter传递到method
Map<String, String> parameterMap = new HashMap<String, String>();
Enumeration<String> toReuqestkeys = request.getAttributeNames();
while (toReuqestkeys.hasMoreElements()) {
String toKey = toReuqestkeys.nextElement();
parameterMap.put(toKey, request.getParameter(toKey));
}
7. 将SessionMap
与parameterMap
作为参数传入回到其他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<String, String> request, Map<String, Object> session)
同时返回类型为ModelAndView
1
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<String, Object> SessionMap = new HashMap<String, Object>();
Enumeration<String> toSessionkeys = session.getAttributeNames();
while (toSessionkeys.hasMoreElements()) {
String toKey = toSessionkeys.nextElement();
SessionMap.put(toKey, session.getAttribute(toKey));
}
Map<String, String> parameterMap = new HashMap<String, String>();
Enumeration<String> 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<String,Object> fromControllerSession = modelAndView.getSessions();
Set<String> keys = fromControllerSession.keySet(); //get all keys from map
for (String key: keys) {
session.setAttribute(key, fromControllerSession.get(key));
}
Map<String,Object> fromControllerRequests = modelAndView.getRequests();
Set<String> 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);
}
}
···