自定义MVC框架原理和使用

1.什么是mvc?

       MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,它是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码。

2.自定义mvc核心思想

答:“各司其职”;

3. 三层架构和MVC的区别

       三层架构是一个经典的分层思想,将开发模式分为三层,每个人专注自己擅长模块即可,MVC是一种设计模式,其目的是让html和业务逻辑分开。

4.mvc结构

术语 对应关系
M 实体域模型(名词)entity,过程域模型(动词:因为是可变的)dao/biz
V jsp/ios/android
C servlet/action

5.Model1和Model2的区别

       我们在学习自定义MVC框架的时候常常会听到Model1 、Model2和MVC。那么什么是Model1 什么是Model2什么又是MVC呢?

什么是Model1?

model1:jsp+jdbc
答:Model1就是一种纯jsp开发技术,将业务逻辑代码和视图渲染代码杂糅在一起

什么是Model2?

model2:mvc
答:Model2是在Model1的基础上,将业务逻辑的代码分离开来,单独形成一个Servlet,Model2也是基于MVC开发。

6.注意事项

注1:不能跨层调用
注2:只能出现由上而下的调用:View -> Controller -> Model

7.优缺点

优点:

       耦合性低

       重用性高

       生命周期成本低

       可维护性高

       部署快

缺点:

       1.增加系统结构和实现的复杂性

对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

       2.一般高级的界面工具或构造器不支持模式

改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,会造成MVC使用的困难。

8.自定义mvc框架工作原理图

在这里插入图片描述
举个栗子:

       比如说一个老板他开饭店,刚开始为了节约成本,他一个人做事,从早上起床买菜、洗菜、切菜,切完之后有客人来了、还要招呼客人,客人还要点单点完单之后又要去炒菜,这一系列下来都是他一个人做的,客人吃完之后他还要洗碗,前期当他店小的时候用户量小的情况下他一个人是可以做的到的。
        但是当他后期生意越来越好,想扩展规模越来越大的时候,他一个人就做不了这些事情了。
       此时只能请人分配各个岗位,老板就做管理,管理员工。(各司其职)

使用Model2这种开发的好处:

       比如说淘宝它有电脑版、网站版、还有手机版、但是它们只需要修改v层就可以了,如果是Model1的话那就只能各写一套了,那样很麻烦。

细讲原理图:

  1. ActionServlet:中央控制层
  2. 子控制器Action中央控制器就是老板用来做管理的,子控制器就是各个员工,具体做事的那个人就叫子控制器。
    注意:子控制器必须获取资格证才能上岗做事,这个资格证相当于Action
    它里面有一个execute方法(处理具体逻辑)
  3. 图解:
    基于下面案例:
    在这里插入图片描述

9.案例运用(加减乘除)

建模的配置文件:

基于此配置文件进行流程的转发和重定向、实例化等。
在这里插入图片描述
1.对事物进行oop思想创建实体

package com.liyingdong.entity;

import java.io.Serializable;
/**
 * 实体类
 * @author 李瀛东
 *
 * 2020年6月3日
 */
public class CalBean implements  Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 5426954915625069605L;
	
	private int num1;
	private int num2;
	
	public CalBean() {}

	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;
	}
	
	
	
}

2.定义一个子控制器声明抽象方法execute(相当于资格证)


public abstract class Action {

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

3声明一个模型实体的接口


public interface ModelDriver <K> {
  
	public K getModel();
	
}

4.写一个方法分发的类它继承于Action同时是子控制器的父类对子控制器实现数据向下抽取

  1. execute具体处理业务的方法根据req请求拿到客户端要执行的方法名
  2. 通过反射进行对子控制器的动态调用方法
  3. 拿到子控制器的结果码返回到中央控制器进行下一步处理
package com.liyingdong.framework;

import java.io.IOException;
import java.lang.reflect.Method;

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

public class DispatcherAction  extends  Action{

	@Override
	public String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			//反射调用方法
			String methodName = req.getParameter("methodName");
			//拿到类对象
			Class c=this.getClass();
			//获取方法对象
			Method method= c.getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
			//执行子控制器的方法拿到结果码并返回
			String code=(String)method.invoke(this,req,resp);
			return code;
		} catch (Exception e) {
			// TODO: handle exception
			throw  new RuntimeException(e);
		}
		
	}

}

5.中央控制器

  1. 获取请求的路径:*.action
  2. 得到* : 子控制器对应的路径
  3. 根据*获取子控制器
  4. 得到子控制器的完整类名
  5. 根据完整类名拿到子控制器
  6. 通过反射赋值
  7. 把请求委托给子控制器
  8. 根据结果码进行流程的转发和从定项
package com.liyingdong.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;

public class ActionServlet extends HttpServlet {
	/**
	 * 实现序列化
	 */
	private static final long serialVersionUID = 1L;

	private ConfigModel configModel = null;

	/**
	 * 读取xml进行建模 这个过程放在初始方法里面不管请求多少次(建模过程只有一次)
	 */
	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		try {
			configModel = ConfigModelFactory.createConfigModelFactory("/mvc.xml");
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub

		// 1获取请求路径
		String servletPath = req.getServletPath();
		// 2获得*:子控制器对应的路径
		String actionPath = servletPath.substring(0, servletPath.indexOf(".action"));
		// 3.根据*获取子控制器 得到子控制器
		ActionModel actionModel = configModel.get(actionPath);
		// 4.得到type相当于得到完整类名
		String type = actionModel.getType();
		// 5.根据完整类名拿到子控制器
		Action action = getAction(type);
		// 6.通过反射赋值
		doModelDriver(action, req);
		// 7.把请求委托给子控制器执行获取结果码
		String code = action.execute(req, resp);
		// 8.根据结果码进行流程的转发和重定向
		forwardByCode(code, actionModel, req, resp);

	}

	/**
	 * 根据完整类名进行反射实例化对象进行强转并且返回对象
	 * 
	 * @param type
	 * @return Action
	 */
	private Action getAction(String type) {
		try {
			Class<?> c = Class.forName(type);
			Action action = (Action) c.newInstance();
			return action;
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	/**
	 * 根据子控制器返回的结果码进行跳转
	 * 
	 * @param code
	 * @param actionModel
	 * @param req
	 * @param resp
	 * @throws IOException
	 * @throws ServletException
	 */
	private void forwardByCode(String code, ActionModel actionModel, HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		if (null == code) {// code就是结果码
			return;
		}
		// 根据结果码拿到forwardModel对象
		ForwardModel forwardModel = actionModel.get(code);
		// 拿到forwardModel对象里面重定向的属性判断
		boolean redirect = forwardModel.isRedirect();
		// 拿到跳转路径
		String path = forwardModel.getPath();
		if (redirect) {
			// 如果是true就进行重定向
			resp.sendRedirect(req.getContextPath());
		} else {
			// 否则进行转发
			req.getRequestDispatcher(path).forward(req, resp);
		}
	}

	public void doModelDriver(Action action, HttpServletRequest req) {
		// 如果它实现了ModelDriver接口那就实现强转
		if (action instanceof ModelDriver) {
			// 进行强转
			ModelDriver<?> modelDriver = (ModelDriver<?>) action;
			// 调方法返回一个java对象
			Object obj = modelDriver.getModel();
			// TODO: handle exception
			try {
				// 利用反射赋值的jar进行赋值
				BeanUtils.populate(obj, req.getParameterMap());
			} catch (Exception e) {
				// TODO: handle exception
				throw new RuntimeException();
			}
		}
	}

}

6.子控制器(CalAction)

  1. 继承于DispatcherAction
  2. 实现了ModelDriver接口方便进行反射赋值
  3. 执行方法、返回结果码、保存结果存入作用域进行前端显示
package com.liyingdong.action;

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

import com.liyingdong.entity.CalBean;
import com.liyingdong.framework.DispatcherAction;
import com.liyingdong.framework.ModelDriver;
/**
 * CalAction是子控制器
 * 可以理解为具体做事的那个人,能做事的前提下是有资格证,所有必须继承Action
 * 现在子控制器继承的是DispatcherAction方法分发类,同时方法分发类继承了Action所以是一样的道理
 * 而且实现ModelDriver类是一个oop思想    进行事务进行对象化
 * @author 李瀛东
 * 2020年6月3日
 */
public class CalAction extends DispatcherAction  implements ModelDriver<CalBean>{

	CalBean  c=new CalBean();
	/**
	 * 返回创建好的对象
	 */
	@Override
	public CalBean getModel() {
		// TODO Auto-generated method stub
		return c;
	}

	/**
	 * 加法
	 * @param req
	 * @param resp
	 * @return
	 */
	public String add(HttpServletRequest req, HttpServletResponse  resp) {
		System.out.println("-------------------add-----------------");
		int n=c.getNum1()+c.getNum2();
		req.setAttribute("n",n);
		return "rs";
	}
	/**
	 * 减法
	 * @param req
	 * @param resp
	 * @return
	 */
	public String minus(HttpServletRequest req, HttpServletResponse  resp) {
		System.out.println("-------------------minus-----------------");
		int n=c.getNum1()-c.getNum2();
		req.setAttribute("n",n);
		return "rs";
	}
	/**
	 * 乘法
	 * @param req
	 * @param resp
	 * @return
	 */
	public String mul(HttpServletRequest req, HttpServletResponse  resp) {
		System.out.println("-------------------mul-----------------");
		int n=c.getNum1()*c.getNum2();
		req.setAttribute("n",n);
		return "rs";
	}
	/**
	 * 除法
	 * @param req
	 * @param resp
	 * @return
	 */
	public String div(HttpServletRequest req, HttpServletResponse  resp) {
		System.out.println("-------------------div-----------------");
		int n=c.getNum1()/c.getNum2();
		req.setAttribute("n",n);
		return "rs";
	}
	
}

7.输入界面

<%@ 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>

	<script type="text/javascript">
		function cal(methodName) {
			document.getElementById("methodName").value = methodName;
			document.getElementById("form").submit();
		}
	</script>

	<form id="form" action="CalAction.action" method="post">
		num1: <input type="text" name="num1" /><br /> num2: <input type="text"
			name="num2" /><br /> <input id="methodName" type="hidden"
			name="methodName" value="add" /><br /> <input type="button"
			value="加" onclick="cal('add')" />&nbsp;&nbsp; <input type="button"
			value="减" onclick="cal('minus')" />&nbsp;&nbsp; <input type="button"
			value="乘" onclick="cal('mul')" />&nbsp;&nbsp; <input type="button"
			value="除" onclick="cal('div')" />&nbsp;&nbsp;

	</form>
</body>
</html>

8.结果展示界面

<%@ 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>
 <h1>结果: <input type="text" value="${n}"></h1> 
</body>
</html>

9.输出结果

主界面:
在这里插入图片描述
加:
在这里插入图片描述
减:
在这里插入图片描述
乘:
在这里插入图片描述
除:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45384482/article/details/106528330