文章目录
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的话那就只能各写一套了,那样很麻烦。
细讲原理图:
- ActionServlet:中央控制层
- 子控制器Action中央控制器就是老板用来做管理的,子控制器就是各个员工,具体做事的那个人就叫子控制器。
注意:子控制器必须获取资格证才能上岗做事,这个资格证相当于Action
它里面有一个execute方法(处理具体逻辑) - 图解:
基于下面案例:
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同时是子控制器的父类对子控制器实现数据向下抽取
- execute具体处理业务的方法根据req请求拿到客户端要执行的方法名
- 通过反射进行对子控制器的动态调用方法
- 拿到子控制器的结果码返回到中央控制器进行下一步处理
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.中央控制器
- 获取请求的路径:*.action
- 得到* : 子控制器对应的路径
- 根据*获取子控制器
- 得到子控制器的完整类名
- 根据完整类名拿到子控制器
- 通过反射赋值
- 把请求委托给子控制器
- 根据结果码进行流程的转发和从定项
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)
- 继承于DispatcherAction
- 实现了ModelDriver接口方便进行反射赋值
- 执行方法、返回结果码、保存结果存入作用域进行前端显示
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')" /> <input type="button"
value="减" onclick="cal('minus')" /> <input type="button"
value="乘" onclick="cal('mul')" /> <input type="button"
value="除" onclick="cal('div')" />
</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.输出结果
主界面:
加:
减:
乘:
除: