自定义MVC(一)

一、MVC

mvc是什么
Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。
    通常模型对象负责在数据库中存取数据。
View(视图):是应用程序中处理数据显示的部分。
    通常视图是依据模型数据创建的。
Controller(控制器):是应用程序中处理用户交互的部分。
    通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
注1:不能跨层调用
注2:只能出现由上而下的调用

三层架构和MVC的区别
三层架构是一个经典的分层思想,将开发模式分为三层,每个人专注自己擅长模块即可
MVC是一种设计模式,其目的是让html和业务逻辑分开
MVC的优缺点:
优点:分层,结构清晰,耦合性低,大型项目代码的复用性得到极大的提高,开发人员分工明确,提高了开发的效率,维护方便,降低了维护成本。

缺点:简单的小型项目,使用MVC设计反而会降低开发效率,层和层虽然相互分离,但是之间关联性太强,没有做到独立的重用。

接下来我们来讲解自定义mvc,我们以一张图来理解我们的自定义mvc

二、自定义MVC框架工作原理图

在这里插入图片描述
我们以一个案例来讲解整个过程:
加减乘除运算案例:
1)中央控制器
作用: 接受请求,通过寻找处理请求的对应的子控制器 。
思路: 用来获取发送请求的路径名,并截取。然后交给其他子控制器。

package com.dengrenli.framework;
/**
 * 
 * 中央控制器
 * 作用:接受请求,通过寻找处理请求的对应的子控制器
 *
 */
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dengrenli.web.AddCalAction;
import com.dengrenli.web.DelCalAction;

public class DispatcherServlet extends HttpServlet {

	
	private static final long serialVersionUID = 3392701943410984788L;
	//定义一个集合
	private Map<String, Action> actionMap=new HashMap<>();
	
	//定义一个init方法
	public void init() {
		actionMap.put("/addCal", new AddCalAction());//放了一个子控制器
		actionMap.put("/delCal", new DelCalAction());
		
	}
	
	
	@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(".")); //截取
	    Action action = actionMap.get(url); //返回 Action
	    action.execute(req, resp);
	}

}

(2)子控制器接口
作用: 用来直接处理浏览器发送过来的请求
思路: 用来定义方法。

package com.dengrenli.framework;


import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 子控制器
 * 作用:用来直接处理浏览器发送过来的请求
 * @author Admin
 *
 */
public interface Action {

 String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ;
	
}

(3)实体类

package com.dengrenli.entity;

public class Cal {

	private  int num1;
	private  int num2;
	public int getNum1() {
		return num1;
	}
	public void setNum1(int num1) {
		this.num1 = num1;
	}
	public int getNum2() {
		return num2;
	}
	public void setNum2(int num2) {
		this.num2 = num2;
	}
	public Cal(int num1, int num2) {
		
		this.num1 = num1;
		this.num2 = num2;
	}
	public Cal() {
	
	}


	
}

(4)AddCalAction它实现Action接口
我们这里就写一个加法运算:

package com.dengrenli.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dengrenli.entity.Cal;
import com.dengrenli.framework.Action;

public class AddCalAction implements Action {

	@Override
	public String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String num1=req.getParameter("num1");
		String num2=req.getParameter("num2");
		Cal cal=new Cal(Integer.valueOf(num1),Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() + cal.getNum2());
		req.getRequestDispatcher("res.jsp").forward(req, resp);//跳页面
		return null;

	}

	
}

(5)配置xml文件
它只要配置中央控制器,

<?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>T226_mvc</display-name>
  <servlet>
 <servlet-name>dispatcherServlet</servlet-name>
 <servlet-class>com.dengrenli.framework.DispatcherServlet</servlet-class>
 </servlet>

 <servlet-mapping>
 <servlet-name>dispatcherServlet</servlet-name>
 <url-pattern>*.action</url-pattern>
 </servlet-mapping>
</web-app>

(6)jsp页面调用
代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	function doSub(num) {
		if(num==1){
			calForm.action="${pageContext.request.contextPath}/addCal.action";
		}else if(num==2){
			calForm.action="${pageContext.request.contextPath}/delCal.action";
		}
		calForm.submit();
	}
</script>


</head>
<body>

<form name="calForm" action="" method="post">
    num1:<input type="text" name="num1"><br>
    num2:<input type="text" name="num2"><br>
    <button onclick="doSub(1)">+</button>
    <button onclick="doSub(2)">-</button>
      <button onclick="doSub(3)">*</button>
       <button onclick="doSub(4)">/</button> 
</form>

</body>
</html>

(7)jsp结果页面:
之所以我们要这个页面就是,我们两个数相加之后按提交我们要跳转到这个页面,呈现运算结果:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
结果:${res}
</body>
</html>

接下来我们来一起看一下结果:
我们这里运行了加法运算:
结果如图所示:
在这里插入图片描述
在这里插入图片描述
总结:
主控制器:查看是否有对应的子控制器来处理用户请求,如果就调用子控制器来处理请求,没有就报错,就处理不了请求

子控制器:就是处理用户请求用的

按以上的实例来看,它的操作还是太繁琐了,所以我们必须对它的性能进行加强

通过XML对自定义mvc框架进行增强

我们先来确定我们的增强的核心思想,如图所示:
在这里插入图片描述
com.dengrenli.framework里面的类我们就把它当做我们的框架代码,里面的类都不能改动,为了满足客户需求,我们应该改动的就只有其他包下的类
1、将Action的信息配置到xml(反射实例化)
解决了在框架代码中去改动,以完成客户需求,这个是不合理的,所以我们不能在框架代码里面改动
mvc.xml
代码如下:

<?xml version="1.0" encoding="UTF-8"?>
	<!--
		config标签:可以包含0~N个action标签
	-->
<config>
	<!--
		action标签:可以饱含0~N个forward标签
		path:以/开头的字符串,并且值必须唯一 非空
		type:字符串,非空
	-->
	
	
	 <action path="/addCal" type="com.dengrenli.web.AddCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action>
	<action path="/delCal" type="com.dengrenli.web.DelCalAction">
		<forward name="res" path="/res.jsp" />
	</action>
	<action path="/xxCal" type="com.dengrenli.web.XxCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action>
	<action path="/cfCal" type="com.dengrenli.web.CfCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action> 
	
		
	
</config>

这里用到了我们的xml建模的知识,不了解的可以看一下我的博客xml建模
我们对mvc.xml进行建模:
ConfigModelFactory.java
代码如下:

package com.dengrenli.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 {
	private ConfigModelFactory() {

	}

	private static ConfigModel configModel = null;

	public static ConfigModel newInstance() throws Exception {
		return newInstance("mvc.xml");
	}

	/**
	 * 工厂模式创建config建模对象
	 * 
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public static ConfigModel newInstance(String path) throws Exception {
		if (null != configModel) {
			return configModel;
		}

		ConfigModel configModel = new ConfigModel();
		InputStream is = ConfigModelFactory.class.getResourceAsStream(path);
		SAXReader saxReader = new SAXReader();
		Document doc = saxReader.read(is);
		List<Element> actionEleList = doc.selectNodes("/config/action");
		ActionModel actionModel = null;
		ForwardModel forwardModel = null;
		for (Element actionEle : actionEleList) {
			 actionModel = new ActionModel();
			actionModel.setPath(actionEle.attributeValue("path"));
			actionModel.setType(actionEle.attributeValue("type"));
			List<Element> forwordEleList = actionEle.selectNodes("forward");
			for (Element forwordEle : forwordEleList) {
				forwardModel = new ForwardModel();
				forwardModel.setName(forwordEle.attributeValue("name"));
				forwardModel.setPath(forwordEle.attributeValue("path"));
				forwardModel.setRedirect(forwordEle.attributeValue("redirect"));
				actionModel.put(forwardModel);
			}

			configModel.put(actionModel);
		}

		return configModel;
	}
	
	public static void main(String[] args) {
		try {
			ConfigModel configModel = ConfigModelFactory.newInstance();
			ActionModel actionModel = configModel.get("/loginAction");
			ForwardModel forwardModel = actionModel.get("failed");
			System.out.println(actionModel.getType());
			System.out.println(forwardModel.getPath());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

DispatcherServlet.java
代码如下:

package com.dengrenli.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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 Administrator
 *
 */
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 5483874334171819754L;

//	private Map<String, Action> actionMap = new HashMap<>();
//	
	private ConfigModel configModel;
	
	public void init() {
//		actionMap.put("/addCal", new AddCalAction());
//		actionMap.put("/delCal", new DelCalAction());
		try {
			String xmlPath = this.getInitParameter("xmlPath");
			if(xmlPath == null || "".equals(xmlPath)) {
				configModel = ConfigModelFactory.newInstance();
			}else {
				configModel = ConfigModelFactory.newInstance(xmlPath);
			}
			
		} 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();
//		/web_mvc_addCal.action
//		/addCal
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
		ActionModel actionModel = configModel.get(url);
		if(actionModel == null) {
			throw new RuntimeException("你没有配置action标签,找不到对应的自控制器来处理浏览器发送出来的请求 !!!!");
		}
		
			try {
//				Action action = (Action) Class.forName("com.caoguangli.web.AddCalAction").newInstance();
//				Action action = (Action) AddCalAction();
				Action action = (Action) Class.forName(actionModel.getType()).newInstance();
				
//				action就是com.dengrenli.web.CalAction
				if(action instanceof ModelDrivern) {
					ModelDrivern modelDrivern = (ModelDrivern) action;
//					此时的model所有属性值是null
					Object model = modelDrivern.getModel();
					BeanUtils.populate(model, req.getParameterMap());
//					可以将req.getParameterMap()的值通过反射的方式将其塞进model实例
					
//					BeanUtils.populate方法的原理
//					Map<String, String[]> paMap = req.getParameterMap();
//					Set<Entry<String, String[]>> entrySet = paMap.entrySet();
//					Class<? extends Object> cls = model.getClass();
//					for (Entry<String, String[]> entry : entrySet) {
//						Field field = cls.getDeclaredField(entry.getKey());
//						field.setAccessible(true);
//						field.set(model, entry.getValue());
//					}
				}
				String code = action.execute(req, resp);
				
				ForwardModel forwardModel = actionModel.get(code);	
				if(forwardModel != null) {
					String jspPath = forwardModel.getPath();
					if("false".equals(forwardModel.getRedirect())) {
//						做转发的处理
						req.getRequestDispatcher(jspPath).forward(req, resp);
					}else {
						resp.sendRedirect(req.getContextPath()+jspPath);
					}
				}
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		
//		Action action = actionMap.get(url);
//		try {
			action.execute(req, resp);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
           
	}
}

2 、通过结果码(forwardModel.getRedirect())控制页面的跳转
代码如下:

DispatcherServlet.java
代码如下:

package com.dengrenli.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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 Administrator
 *
 */
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 5483874334171819754L;

//	private Map<String, Action> actionMap = new HashMap<>();
//	
	private ConfigModel configModel;
	
	public void init() {
//		actionMap.put("/addCal", new AddCalAction());
//		actionMap.put("/delCal", new DelCalAction());
		try {
			String xmlPath = this.getInitParameter("xmlPath");
			if(xmlPath == null || "".equals(xmlPath)) {
				configModel = ConfigModelFactory.newInstance();
			}else {
				configModel = ConfigModelFactory.newInstance(xmlPath);
			}
			
		} 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();
//		/web_mvc_addCal.action
//		/addCal
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
		ActionModel actionModel = configModel.get(url);
		if(actionModel == null) {
			throw new RuntimeException("你没有配置action标签,找不到对应的自控制器来处理浏览器发送出来的请求 !!!!");
		}
		
			try {
//				Action action = (Action) Class.forName("com.caoguangli.web.AddCalAction").newInstance();
//				Action action = (Action) AddCalAction();
				Action action = (Action) Class.forName(actionModel.getType()).newInstance();
				
//				action就是com.dengrenli.web.CalAction
				if(action instanceof ModelDrivern) {
					ModelDrivern modelDrivern = (ModelDrivern) action;
//					此时的model所有属性值是null
					Object model = modelDrivern.getModel();
					BeanUtils.populate(model, req.getParameterMap());
//					可以将req.getParameterMap()的值通过反射的方式将其塞进model实例
					
//					BeanUtils.populate方法的原理
//					Map<String, String[]> paMap = req.getParameterMap();
//					Set<Entry<String, String[]>> entrySet = paMap.entrySet();
//					Class<? extends Object> cls = model.getClass();
//					for (Entry<String, String[]> entry : entrySet) {
//						Field field = cls.getDeclaredField(entry.getKey());
//						field.setAccessible(true);
//						field.set(model, entry.getValue());
//					}
				}
				String code = action.execute(req, resp);
				
				ForwardModel forwardModel = actionModel.get(code);	
				if(forwardModel != null) {
					String jspPath = forwardModel.getPath();
					if("false".equals(forwardModel.getRedirect())) {
//						做转发的处理
						req.getRequestDispatcher(jspPath).forward(req, resp);
					}else {
						resp.sendRedirect(req.getContextPath()+jspPath);
					}
				}
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		
//		Action action = actionMap.get(url);
//		try {
			action.execute(req, resp);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
           
	}
}

3 、将一组相关的操作放到一个Action中(反射调用方法)
提供一组与execute方法的参数、返回值相同的方法,只有方法名不一样
mvc.xml
代码如下:

<?xml version="1.0" encoding="UTF-8"?>
	<!--
		config标签:可以包含0~N个action标签
	-->
<config>
	<!--
		action标签:可以饱含0~N个forward标签
		path:以/开头的字符串,并且值必须唯一 非空
		type:字符串,非空
	-->
	
	
	<!-- <action path="/addCal" type="com.dengrenli.web.AddCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action>
	<action path="/delCal" type="com.dengrenli.web.DelCalAction">
		<forward name="res" path="/res.jsp" />
	</action>
	<action path="/xxCal" type="com.dengrenli.web.XxCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action>
	<action path="/cfCal" type="com.dengrenli.web.CfCalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action> -->
	
		
	<action path="/cal" type="com.dengrenli.web.CalAction">
		<forward name="res" path="/res.jsp" redirect="false" />
	</action>
</config>

CalAction.java
代码如下:

package com.dengrenli.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dengrenli.entity.Cal;
import com.dengrenli.framework.ActionSupport;
import com.dengrenli.framework.ModelDrivern;


public class CalAction extends ActionSupport implements ModelDrivern<Cal>{

	private Cal cal = new Cal();
	public String add(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() + cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String del(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() - cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String cf(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() / cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String xx(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() * cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}

	@Override
	public Cal getModel() {
		
		return cal;
	}
}

ActionSupport.java
代码如下:

package com.dengrenli.framework;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 增强版的子控制器
 *   原来是子控制器只能一个用户请求
 *   有时候,用户请求是多个,但是都是操作同一张表,那么原有的子控制器代码编写繁琐
 *   增强版的作用是将一组相关的操作放到一个Action
 * @author Administrator
 *
 */
public class ActionSupport implements Action {

	@Override
	public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		add/del
		String methodName = req.getParameter("methodName");
        String code = null;
//		class  CalAction extends ActionSupport
//		this 在这里指的的是CalAction它的一个类实例
		Method method = this.getClass().getDeclaredMethod(methodName ,HttpServletRequest.class,HttpServletResponse.class);
		method.setAccessible(true);
		code = (String)method.invoke(this, req,resp);
		return code;
	}

}

DispatcherServlet.java
代码如下:

package com.dengrenli.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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 Administrator
 *
 */
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 5483874334171819754L;

//	private Map<String, Action> actionMap = new HashMap<>();
//	
	private ConfigModel configModel;
	
	public void init() {
//		actionMap.put("/addCal", new AddCalAction());
//		actionMap.put("/delCal", new DelCalAction());
		try {
			String xmlPath = this.getInitParameter("xmlPath");
			if(xmlPath == null || "".equals(xmlPath)) {
				configModel = ConfigModelFactory.newInstance();
			}else {
				configModel = ConfigModelFactory.newInstance(xmlPath);
			}
			
		} 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();
//		/web_mvc_addCal.action
//		/addCal
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
		ActionModel actionModel = configModel.get(url);
		if(actionModel == null) {
			throw new RuntimeException("你没有配置action标签,找不到对应的自控制器来处理浏览器发送出来的请求 !!!!");
		}
		
			try {
//				Action action = (Action) Class.forName("com.caoguangli.web.AddCalAction").newInstance();
//				Action action = (Action) AddCalAction();
				Action action = (Action) Class.forName(actionModel.getType()).newInstance();
				
//				action就是com.dengrenli.web.CalAction
				if(action instanceof ModelDrivern) {
					ModelDrivern modelDrivern = (ModelDrivern) action;
//					此时的model所有属性值是null
					Object model = modelDrivern.getModel();
					BeanUtils.populate(model, req.getParameterMap());
//					可以将req.getParameterMap()的值通过反射的方式将其塞进model实例
					
//					BeanUtils.populate方法的原理
//					Map<String, String[]> paMap = req.getParameterMap();
//					Set<Entry<String, String[]>> entrySet = paMap.entrySet();
//					Class<? extends Object> cls = model.getClass();
//					for (Entry<String, String[]> entry : entrySet) {
//						Field field = cls.getDeclaredField(entry.getKey());
//						field.setAccessible(true);
//						field.set(model, entry.getValue());
//					}
				}
				String code = action.execute(req, resp);
				
				ForwardModel forwardModel = actionModel.get(code);	
				if(forwardModel != null) {
					String jspPath = forwardModel.getPath();
					if("false".equals(forwardModel.getRedirect())) {
//						做转发的处理
						req.getRequestDispatcher(jspPath).forward(req, resp);
					}else {
						resp.sendRedirect(req.getContextPath()+jspPath);
					}
				}
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		
//		Action action = actionMap.get(url);
//		try {
			action.execute(req, resp);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
           
	}
}

4 、利用ModelDriver接口对Java对象进行赋值(反射读写属性)
BeanUtils.populate(calBean, parameterMap);
ModelDriver接口返回的对象不能为空

ModelDrivern.java
代码如下:

package com.dengrenli.framework;

/**
 * 模型驱动接口
 *   作用 是将jsp所有传递过来的参数以及参数值都自动封装到浏览器所要操作的实体类中
 * @author Administrator
 *
 */
public interface ModelDrivern<T> {

	T getModel();
}

CalAction.java
代码如下:

package com.dengrenli.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dengrenli.entity.Cal;
import com.dengrenli.framework.ActionSupport;
import com.dengrenli.framework.ModelDrivern;


public class CalAction extends ActionSupport implements ModelDrivern<Cal>{

	private Cal cal = new Cal();
	public String add(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() + cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String del(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() - cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String cf(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() / cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}
	
	public String xx(HttpServletRequest req, HttpServletResponse resp) throws Exception, Exception {
//		String num1 = req.getParameter("num1");
//		String num2 = req.getParameter("num2");
//		Cal cal = new Cal(Integer.valueOf(num1), Integer.valueOf(num2));
		req.setAttribute("res", cal.getNum1() * cal.getNum2());
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "res";
	}

	@Override
	public Cal getModel() {
		
		return cal;
	}
}

DispatcherServlet.java
代码如下:

package com.dengrenli.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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 Administrator
 *
 */
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 5483874334171819754L;

//	private Map<String, Action> actionMap = new HashMap<>();
//	
	private ConfigModel configModel;
	
	public void init() {
//		actionMap.put("/addCal", new AddCalAction());
//		actionMap.put("/delCal", new DelCalAction());
		try {
			String xmlPath = this.getInitParameter("xmlPath");
			if(xmlPath == null || "".equals(xmlPath)) {
				configModel = ConfigModelFactory.newInstance();
			}else {
				configModel = ConfigModelFactory.newInstance(xmlPath);
			}
			
		} 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();
//		/web_mvc_addCal.action
//		/addCal
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
		ActionModel actionModel = configModel.get(url);
		if(actionModel == null) {
			throw new RuntimeException("你没有配置action标签,找不到对应的自控制器来处理浏览器发送出来的请求 !!!!");
		}
		
			try {
//				Action action = (Action) Class.forName("com.caoguangli.web.AddCalAction").newInstance();
//				Action action = (Action) AddCalAction();
				Action action = (Action) Class.forName(actionModel.getType()).newInstance();
				
//				action就是com.dengrenli.web.CalAction
				if(action instanceof ModelDrivern) {
					ModelDrivern modelDrivern = (ModelDrivern) action;
//					此时的model所有属性值是null
					Object model = modelDrivern.getModel();
					BeanUtils.populate(model, req.getParameterMap());
//					可以将req.getParameterMap()的值通过反射的方式将其塞进model实例
					
//					BeanUtils.populate方法的原理
//					Map<String, String[]> paMap = req.getParameterMap();
//					Set<Entry<String, String[]>> entrySet = paMap.entrySet();
//					Class<? extends Object> cls = model.getClass();
//					for (Entry<String, String[]> entry : entrySet) {
//						Field field = cls.getDeclaredField(entry.getKey());
//						field.setAccessible(true);
//						field.set(model, entry.getValue());
//					}
				}
				String code = action.execute(req, resp);
				
				ForwardModel forwardModel = actionModel.get(code);	
				if(forwardModel != null) {
					String jspPath = forwardModel.getPath();
					if("false".equals(forwardModel.getRedirect())) {
//						做转发的处理
						req.getRequestDispatcher(jspPath).forward(req, resp);
					}else {
						resp.sendRedirect(req.getContextPath()+jspPath);
					}
				}
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		
//		Action action = actionMap.get(url);
//		try {
			action.execute(req, resp);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
           
	}
}

5、使得框架的配置文件可变
因为com.dengrenli.framework里面的类不能改动,那我们想改它的.xml文件的话,我们就要用到以下方法:
web.xml
如图所示:
在这里插入图片描述
在这里插入图片描述
这样可以获取到其他路径下的.xml文件
DispatcherServlet.java
代码如下:

package com.dengrenli.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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 Administrator
 *
 */
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 5483874334171819754L;

//	private Map<String, Action> actionMap = new HashMap<>();
//	
	private ConfigModel configModel;
	
	public void init() {
//		actionMap.put("/addCal", new AddCalAction());
//		actionMap.put("/delCal", new DelCalAction());
		try {
			String xmlPath = this.getInitParameter("xmlPath");
			if(xmlPath == null || "".equals(xmlPath)) {
				configModel = ConfigModelFactory.newInstance();
			}else {
				configModel = ConfigModelFactory.newInstance(xmlPath);
			}
			
		} 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();
//		/web_mvc_addCal.action
//		/addCal
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
		ActionModel actionModel = configModel.get(url);
		if(actionModel == null) {
			throw new RuntimeException("你没有配置action标签,找不到对应的自控制器来处理浏览器发送出来的请求 !!!!");
		}
		
			try {
//				Action action = (Action) Class.forName("com.caoguangli.web.AddCalAction").newInstance();
//				Action action = (Action) AddCalAction();
				Action action = (Action) Class.forName(actionModel.getType()).newInstance();
				
//				action就是com.dengrenli.web.CalAction
				if(action instanceof ModelDrivern) {
					ModelDrivern modelDrivern = (ModelDrivern) action;
//					此时的model所有属性值是null
					Object model = modelDrivern.getModel();
					BeanUtils.populate(model, req.getParameterMap());
//					可以将req.getParameterMap()的值通过反射的方式将其塞进model实例
					
//					BeanUtils.populate方法的原理
//					Map<String, String[]> paMap = req.getParameterMap();
//					Set<Entry<String, String[]>> entrySet = paMap.entrySet();
//					Class<? extends Object> cls = model.getClass();
//					for (Entry<String, String[]> entry : entrySet) {
//						Field field = cls.getDeclaredField(entry.getKey());
//						field.setAccessible(true);
//						field.set(model, entry.getValue());
//					}
				}
				String code = action.execute(req, resp);
				
				ForwardModel forwardModel = actionModel.get(code);	
				if(forwardModel != null) {
					String jspPath = forwardModel.getPath();
					if("false".equals(forwardModel.getRedirect())) {
//						做转发的处理
						req.getRequestDispatcher(jspPath).forward(req, resp);
					}else {
						resp.sendRedirect(req.getContextPath()+jspPath);
					}
				}
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		
//		Action action = actionMap.get(url);
//		try {
			action.execute(req, resp);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
           
	}
}

最后还有我们的jsp页面
cal.jsp
代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
    function doSub(num) {
		if(num == 1){
			calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=add";
		}else if(num == 2){
			calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=del";
		}else if(num == 3){
			calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=xx";
		}else if(num == 4){
			calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=cf";
		}
		calForm.submit();
	}
</script>
</head>
<body>
  <form name="calForm" action="" method="post">
      num1:<input type="text" name="num1"><br>
      num2:<input type="text" name="num2"><br>
      <button onclick="doSub(1)">+</button>
      <button onclick="doSub(2)">-</button>
      <button onclick="doSub(3)">*</button>
      <button onclick="doSub(4)">/</button>
  </form>
</body>
</html>

res.jsp
代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
结果:${res }
</body>
</html>

运行效果如下:
我们照样运行加法运算:
如图所示:
在这里插入图片描述
结果如图所示:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值