自定义MVC框架优化
自定义MVC框架
这篇文章主要讲,通过XML对自定义mvc框架进行增强,代码会进行优化!!!
自定义MVC框架优化
步骤:
-
1、将Action的信息配置到xml(反射实例化)
-
2、通过结果码控制页面的跳转
-
3、将一组相关的操作放到一个Action中(反射调用方法)
-
4、利用ModelDriver接口对Java对象进行赋值(反射读写方法)
-
5、使得框架的配置文件可变
注意:Action多例模式,因为Action的属性要用来接收参数!!!
重要代码如下:
(大部分的注释我都已经写的很详细了,诸位看代码就能看懂 。)
主控制器:
package com.dj.framework;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
/**
* 主控制器
* @author 86182
*
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ConfigModel configModel = null;
public void init() {
try {
//将原有的读取框架的默认配置文件 转变成 可配置路径的配置文件
String xmlPath = this.getInitParameter("xmlPath");
if(xmlPath == null || "".equals(xmlPath)) {
configModel = ConfigModelFactory.build();
}else {
configModel = ConfigModelFactory.build(xmlPath);
}
//主控制器有哪些子控制器由configModel决定
configModel = ConfigModelFactory.build();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
init();
String url = req.getRequestURI();//路径
url = url.substring(url.lastIndexOf("/"),url.lastIndexOf("."));
//通过 path 拿到 type
ActionModel actionModel = configModel.pop(url);
//如果没有配置子控制器
if(actionModel == null) {
throw new RuntimeException("没有配置对应的子控制器 Action");
}
/**
* 将Action的信息配置到xml(反射实例化)
*
* 原来子控制器的来源是map集合,如此,子控制器就被写死在map容器中,代码不灵活
* 现将子控制器以配置的方式存在config.xml中,即通过改变config.xml中的内容给中央控制器添加子控制器
*/
try {
Action action = (Action)Class.forName(actionModel.getType()).newInstance();//反射实例化
/**
* 调用模型驱动接口,获取所要操作的实体类,然后将jsp传递过来的参数封装到实体类中
*/
if(action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;//CalAction向上提升为ModelDriven
Object model = modelDriven.getModel();//要操作的实体类
/*//String-属性 String[]-属性值
Map<String, String[]> map = req.getParameterMap();
for (Map.Entry<String, String[]> entry : map.entrySet()) {//遍历
//可以获取到类对应的属性、属性值
}*/ //底层源码
//设置属性、属性值 将所有的参数自动封装到实体类T中
BeanUtils.populate(model, req.getParameterMap());
}
/**
* 通过结果码控制页面跳转
*
* 每个子控制器都要对结果进行处理(重定向/转发),代码重复量较大
* 针对这一现象,将其交给配置文件处理。
*/
//调用增强版的子控制器处理业务逻辑
String code = action.execut(req, resp); //要跳转的路径
ForwardModel forwardModel = actionModel.pop(code);
//如果没有配置子控制器
if(forwardModel == null) {
throw new RuntimeException("没有配置对应的子控制器Action的处理方式forwardModel");
}
String jspPath = forwardModel.getPath();
if(forwardModel.isRedirect()) {
resp.sendRedirect(req.getContextPath()+jspPath);//重定向
}else {
req.getRequestDispatcher(jspPath).forward(req, resp);//转发
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
子控制器:
package com.dj.framework;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器
* 专门用来处理业务逻辑
* @author 86182
*
*/
public interface Action {
String execut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
}
增强版的子控制器:
package com.dj.framework;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 之前的Action只能处理一个实体类的一个业务
*
* 这个是增强版的子控制器,凡是这个实体类的操作,对应的方法都可以写在当前增强版的子控制器
* @author 86182
*
*/
public class ActionSupport implements Action{
@Override
public final String execut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String methodName = req.getParameter("methodName");
String code = null;
try {
Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);//打开访问权限
method.invoke(this, req, resp);
//具体调用了自己所写子控制器中的方法来处理浏览器的请求
code = (String)method.invoke(this, req, resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return code;
}
}
CalAction 写方法
package com.dj.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dj.entity.Cal;
import com.dj.framework.ActionSupport;
import com.dj.framework.ModelDriven;
public class CalAction extends ActionSupport implements ModelDriven<Cal>{
private Cal cal = new Cal();
//加:
public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1()) + Integer.valueOf(cal.getNum2()));
return "calRes";
}
//减:
public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1()) - Integer.valueOf(cal.getNum2()));
return "calRes";
}
//乘:
public String multiply(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1()) * Integer.valueOf(cal.getNum2()));
return "calRes";
}
//除:
public String divide(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("res", Integer.valueOf(cal.getNum1()) / Integer.valueOf(cal.getNum2()));
return "calRes";
}
@Override
public Cal getModel() {
return cal;
}
}
模型驱动接口:
package com.dj.framework;
/**
* 模型驱动接口
*
* 用来处理jsp页面传递过来的参数,将所有参数自动封装到实体类T中
*
* @author 86182
*
* @param <T>
*/
public interface ModelDriven<T> {
T getModel();
}
解读XML
package com.dj.framework;
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ConfigModelFactory {
public static ConfigModel build() throws Exception {
return build("config.xml");
}
//为了方便 我将configModel 为 1节点 actionModel 为2节点 forwardModel 为3节点
public static ConfigModel build(String xmlPath) throws Exception {
ConfigModel configModel = new ConfigModel(); //一个大的1节点
InputStream in = ConfigModelFactory.class.getResourceAsStream(xmlPath); //获取config.xml文件的读取流
SAXReader sax = new SAXReader();//用到了dom4j解析方法
Document doc = sax.read(in);//解析
ActionModel actionModel = null; //实例化2节点
ForwardModel forwardModel = null; //实列化3节点
List<Element> actionNodes = doc.selectNodes("/config/action"); //找到在1节点下的2节点
for (Element actionNode : actionNodes) { //便利
actionModel = new ActionModel(); //如果有的话就创建一个
actionModel.setPath(actionNode.attributeValue("path")); //给2节点里的属性path赋值
actionModel.setType(actionNode.attributeValue("type")); //给2节点里的属性type赋值
List<Element> forwardNodes = actionNode.selectNodes("forward"); //查找2节点下有多少个3节点
for (Element forwardNode : forwardNodes) {
forwardModel = new ForwardModel(); //如果有的话就创建一个
forwardModel.setName(forwardNode.attributeValue("name")); //给3节点里的属性name赋值
forwardModel.setPath(forwardNode.attributeValue("path")); //给3节点里的属性path赋值
forwardModel.setRedirect(!"false".equals(forwardNode.attributeValue("redirect"))); //给3节点里的属性redirect赋值
actionModel.push(forwardModel); //加入到action属性中
}
configModel.push(actionModel);//加入到集合属性中
}
return configModel;
}
public static void main(String[] args) throws Exception {
ConfigModel configModel = build();
ActionModel actionModel = configModel.pop("/add");
System.out.println("type的值"+actionModel.getType());
ForwardModel forwardModel = actionModel.pop("calres");
System.out.println(forwardModel.getPath() +" "+forwardModel.isRedirect());
}
}
web文件配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>pre_02</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.dj.framework.DispatcherServlet</servlet-class>
<!-- <init-param>
<param-name>xmlPath</param-name>
<param-value>/config.xml</param-value>
</init-param> -->
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
有些类我在自定义MVC框架(一)中有写到,在这里就不罗嗦了,大家有需要的可以参考: