自定义MVC框架优化

本文详述了如何通过XML配置优化自定义MVC框架,包括Action的反射实例化,结果码控制页面跳转,Action方法聚合,ModelDriver接口用于Java对象赋值,以及使配置文件动态可变。强调Action采用多例模式以接收参数。
摘要由CSDN通过智能技术生成

自定义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框架(一)中有写到,在这里就不罗嗦了,大家有需要的可以参考:

自定义MVC框架(一)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值