自定义MVC(一)
既然我们想要运用一个模式,我们就得先去了解一下。
什么是MVC?
MVC:Model(模型) - View(视图) - Controller(控制器)的缩写。
是一种软件设计典范(模式),用一种业务逻辑、数据、界面显示分离的方法组织代码。
我们来了解一下他的
两种模式
Model1模式:JSP+JDBC 代码重用性低,维护差,可读性差。
Model2模式:MVC 核心思想:各司其职,提高代码的重用,提高维护性和可读性
MVC模式的优缺点
它把业务处理和Jsp页面分开了。而以前的Jsp页面是把所有的代码都写在Jsp页面中,那样不利于维护
MVC模式的目的就是实现Web系统的职能分工。
1. MVC模式的好处:
1.各施其职,互不干涉
在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。
2.有利于开发中的分工
在MVC模式中,由于按层把系统分开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。
3.有利于组件的重用
分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视图层也可做成通用的操作界面。
2. MVC模式的不足
MVC的不足体现在以下几个方面:
(1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
(2)视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。
(3)视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
(4) 目前,一般高级的界面工具或构造器不支持MVC模式。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。
3. 自定义MVC工作原理图 如下
主控制动态调用子控制器调用完成具体的业务逻辑
举例:
(火车、控制台、车轨)
请求、主控制器、子控制器
火车进站,火车控制室来决定火车是否能够进站,火车的信号发送,发送什么信号,
是由铁轨上是否有车来决定,就是要进站的火车需要进入的铁轨上是没车的
接下来就让我们了解一下以自定义MVC来写一个简单的计算器吧:
实体类:里面含有两个参数
public class Cal {
private String num1;//参数一
private String num2;//参数二
public String getNum1() {
return num1;
}
public void setNum1(String num1) {
this.num1 = num1;
}
public String getNum2() {
return num2;
}
public void setNum2(String num2) {
this.num2 = num2;
}
public Cal(String num1, String num2) {
super();
this.num1 = num1;
this.num2 = num2;
}
public Cal() {
super();
}
//主控制器
/**
* 中央控制器
*
*/
public class DispathcherServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
//一一对应的关系
private Map<String, Action> actionMap=new HashMap<>();
//初始化的方法
public void init() {
actionMap.put("/addCal",new AddCalAction());
actionMap.put("/delCal",new DelCalAction2());
actionMap.put("/cheCal",new CheCalAction());
actionMap.put("/chuCal",new ChuCalAction());
}
@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();//获取xxx.action
url=url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
//Action action=new AddCalAction();
//向上转型
//列如
//实现了父类所有的方法
//class Student extend Person;
//Person p=new Student();
//拿到对应的子控制器
Action action = actionMap.get(url);
action.execute(req, resp);
}
/**
* 子控制器
* 专门用来处理业务逻辑层的
*
*/
public interface Action {
void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
}
到子控制器里面写方法,让主控制器只配置一个
加:
public class AddCalAction implements Action {
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取值
String num1=req.getParameter("num1");
String num2=req.getParameter("num2");
//把值存放在req里面
req.setAttribute("res", Integer.valueOf(num1)+Integer.valueOf(num2));
//转发
req.getRequestDispatcher("calRes.jsp").forward(req, resp);
}
//减:
public class AddCalAction implements Action {
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取值
String num1=req.getParameter("num1");
String num2=req.getParameter("num2");
//把值存放在req里面
req.setAttribute("res", Integer.valueOf(num1)-Integer.valueOf(num2));
//转发
req.getRequestDispatcher("calRes.jsp").forward(req, resp);
}
乘:
public class AddCalAction implements Action {
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取值
String num1=req.getParameter("num1");
String num2=req.getParameter("num2");
//把值存放在req里面
req.setAttribute("res", Integer.valueOf(num1)*Integer.valueOf(num2));
//转发
req.getRequestDispatcher("calRes.jsp").forward(req, resp);
}
除:
public class AddCalAction implements Action {
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取值
String num1=req.getParameter("num1");
String num2=req.getParameter("num2");
//把值存放在req里面
req.setAttribute("res", Integer.valueOf(num1)/Integer.valueOf(num2));
//转发
req.getRequestDispatcher("calRes.jsp").forward(req, resp);
}
//接下来我们再写一个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(val) {
if(val==1){
calForm.action="${pageContext.request.contextPath }/addCal.action";
}else if(val==2){
calForm.action="${pageContext.request.contextPath }/delCal.action";
}else if(val==3){
calForm.action="${pageContext.request.contextPath }/cheCal.action";
}
else if(val==4){
calForm.action="${pageContext.request.contextPath }/chuCal.action";
}
calFrom.submit();
}
</script>
</head>
<body>
<form id="calForm" name="calForm" action="${pageContext.request.contextPath }/addCal.action">
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>
//再写一个页面 跳转 让结果传递到这个页面展现出来
<%@ 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>
结果在页面上展示的页面是:
加:
减:
乘:
除:
总结:
主控制器:查看是否有对应的子控制器来处理用户请求,如果有就调用子控制器来处理请求;
没有就报错,就处理不了请求
子控制器:就是处理用户请求用的
相对于我们以前写servlet里每一个都配置Servlet
我们的mvc模式里的中央控制器只配置一次
也省去了转化.重定向和接受页面传过来的值
极大的提高了代码的效率