说明:本笔记仅是书上的笔记。实验室某个项目学习使用。
单身狗的世界,程序猿的世界,这又是狗又是猿的,我。。。
原文地址
1.1 Web开发中的请求——响应模型:
在Web中,具体步骤如下:
1、Web浏览器(如IE)发送请求,如访问http://sishuk.com。
2、Web服务器(如Tomcat)接收请求,处理请求(比如用户新增,则把用户保存一下),最后产生响应(一般为html)。
3、Web服务器处理完成后,返回内容给web客户端(一般就是我们的浏览器),客户端对接收的内容进行处理(如web浏览器会将接收的html内容进行渲染展示给用户)。
所以,在web中都是Web客户端发起请求,Web服务器接收、处理并产生响应。一般的web服务器不能主动通知Web客户端更新内容。但是HTML5 websocket可以实现服务器主动通知Web客户端。
1.2 标准MVC模型概述
MVC模型:是一种架构型的模式,本身不能引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离。
首先让我们了解下MVC(Model—View—Controller)三元组的概念:
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过一般现在都分离开来:Value Object(数据)和服务层(行为)。也就是模型提供了模型数据查询和模型数据状态更新等功能,包含数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想要看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的数据模型返回给视图,由视图负责进行展示。也就是说控制器做了一个调度员的工作。
在标准的MVC模型中能主动推送视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图),但在Web开发中模型是无法主动退给视图(无法主动更新用户界面),因为在Web开发是请求—响应模式。
1.3 Web MVC概述
模型—视图—控制器概念和标准MVC模型一样,接下来我们看看Web MVC模型架构,如下图。
在Web MVC模式下,模型无法主动推送数据给视图,如果用户想要视图更新,需要再发送一次请求(即请求—响应模式)。
1.4Web端开发发展历程
核心历程:
1.4.1 CGI
CGI:(Common Gateway Interface)公共网关接口,一种在Web服务器端使用的脚本技术,使C或Perl语言编写,用于接收Web用户请求并处理,最后动态产生响应给用户,但每次请求将产生一个进程,重量级。
1.4.2 Servlet
Servlet:一种JavaEE web组件技术,是一种在服务器端执行的组件,用户接收web用户请求并处理,最后动态产生响应给用户。但每次请求只产生一个线程(而且有线程池),轻量级。而且能利用很多的JavaEE技术(如JDBC等)。本质就是在java代码里面输出html流。但表现逻辑、控制逻辑、业务逻辑调用混杂,如以下代码。
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);//为了简单,直接委托给dopost处理
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.逻辑控制:根据请求参数选择要执行的功能方法
*/
String submitFlag = request.getParameter("submitFlag");
if("toLogin".equals(submitFlag)) {
toLogin(request,response);
return ;
} else if("login".equals(submitFlag)) {
login(request,response);
return ;
}
toLogin(request, response);//默认到登录页面
}
private void toLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
String loginPath = request.getContextPath() + "/ServletLogin";
PrintWriter out = response.getWriter();
/*
* 2.表现代码:页面展示直接放在我们的Servlet里面
*/
out.write("<from action='"+loginPath+"' method='post'>");
out.write("<input type='text' name='submitlogin' value='login'/>");
out.write("username:<input type='text' name='username'/>");
out.write("password:<input type='password' name='password'/>");
out.write("<input type='submit' value='login'/>");
out.write("</from>");
}
private void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
//1、收集参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//2、验证并封装参数(重复的步骤)
/*
* 3.调用业务对象(javabean)进行登录,即模型,不仅包含数据,还包含处理行为
*/
UserBean user = new UserBean();
user.setUsername(username);
user.setPassword(password);
if(user.login()) {
response.getWriter().write("login success");
} else {
response.getWriter().write("login fail");
}
}
}
这种方法是绝对不可取的,控制逻辑、表现代码、业务逻辑对象调用混杂在一起,最大的问题值直接在Java代码中输出Html,这样前端开发人员无法进行页面风格的修改和设计,即使修改也很麻烦,因此实际项目中这种做法不可取。
1.4.3 JSP
JSP(Java Server Page):一种在服务器端执行的web组件,是一种运行在标准的HTML页面中嵌入脚本语言(现在只支持Java)的模板页面技术。本质就是在html代码中嵌入Java代码。最终还是会被编译为Servlet,只不过纯Servlet开发页面简单、方便。但是表现逻辑、业务逻辑、控制逻辑调用还是很混杂。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.demo.UserBean"%>
<!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=ISO-8859-1">
<title>登录</title>
</head>
<body>
<%
String submintFlag = request.getParameter("submitFlag");
if ("login".equals(submintFlag)) {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserBean user = new UserBean();
user.setUsername(username);
user.setPassword(password);
if (user.login()) {
out.write("login success");
} else {
out.write("login fail");
}
} else {
%>
<form action="" method="post">
<input type="hidden" name="submitFlag" value="login">
username:<input type="text" name="username"/><br>
password:<input type="password" name="password"/><br>
<input type="submit" value="login">
</form>
<%
}
%>
</body>
</html>
这种做法也是绝对不可取的,控制逻辑、业务逻辑、表现代码对象调用混杂在一起,但比直接在Servlet里面输出html要好一点,前端开发人员可以进行简单的页面风格等的设计与修改(但如果嵌入的Java脚本太多也很难修改),因此这种做法也不可取的。
JSP本质上还是Servlet,最终在运行时会生成一个Servlet,但这使得写html简单点,但是仍然是控制逻辑、业务逻辑、页面代码混杂在一起的。
1.4.4 Model1
Model1:可以认为是JSP的增强版,可以认为是jsp+javabean
特点:使用<jsp:userBean>标准动作,自动将参数封装为javabean组件;还是必须使用java脚本执行逻辑代码。
Model1架构:
Model1架构中, JSP负责控制逻辑、表现逻辑、业务对象(javabean)的调用,只是比纯JSP简化了获取请求参数和封装请求参数。同样是不好的,在项目中应该禁用。
1.4.5 Model2
Model2:在JavaEE世界里,它可以认为就是Web MVC模型
Model2架构其实可以认为就是我们所说的Web MVC模型,只是控制器采用的Servlet、模型采用JavaBean、视图采用JSP,如下图。
从Model2架构可以看出,视图和模型分离了,控制逻辑与展示逻辑分离了
缺点:
控制器:
1、控制逻辑可能比较复杂,每个模块基本需要一个控制器,造成控制逻辑可能很复杂。
2、请求参数到模型的封装可能比较麻烦,如果交给框架来做这件事情,就得到了解放。
3、选择下一个视图,严重也来ServletAPI,这样很难或基本不可能更换视图。
4、给视图传输要展示的模型数据,使用ServletAPI,更换视图技术要一个更换,很麻烦。
模型:
1、此处模型使用JavaBean,可能造成JavaBean组件类很庞大,一般现在项目都是采用三层结构,而不采用JavaBean。
视图:
1、现在被绑定JSP,很难更换视图,比如Velocity、FreeMarker;比如我要支持Excel、PDF视图等。
1.4.6 服务到工作者
服务到工作者:Front Controller + Application Controller + Page Controller + Context。即前段控制器+应用控制器+页面控制器+上下文,也是Web MVC,只是职责更加明确,如下图:
职责:
Front Controller:前端控制器,负责为表现层提供统一访问点,从而避免Model2中出现的重复的控制逻辑;并且可以为多个请求提供公用的逻辑,将选择视图和具体功能处理分离。
Application Controller:应用控制器,前端控制器分离选择具体视图和具体的功能处理之后,需要有人来管理,应用控制器就是用来选择具体视图技术(视图的管理)和具体功能处理(页面控制器/命令对象/动作管理),一种策略设计模式的应用,可以很容易的切换视图/页面控制器,互不产生影响。
Page Controller:页面控制器/动作/处理器:功能处理代码、收集参数、封装参数到模型,转调业务对象处理模型,返回逻辑视图交给前端控制器(和具体视图解耦),由前端控制器委托给应用控制器选择具体的视图来展示,可以是命令设计模式的实现。页面控制器也被称为处理器或动作。
Context:上下文,有了上下文之后,我们可以将相关数据放置在上下文,从而与协议无关(如ServletAPI)的访问/设置模型数据,一般通过ThreadLocal模式实现。
目的:
干净的web表现层:
模型和视图的分离;
控制器中逻辑控制和功能处理分离(收集并封装参数到模型对象、业务对象的调用);
控制器中视图选择与具体视图技术分离。
轻薄的web表现层:
做的事情越少越好,薄薄的,不应该包含无关代码;
只负责收集并组织参数到模型对象,启动业务对象的调用;
控制器只返回逻辑视图名由相应的应用控制器来选择具体使用的视图策略;
尽量少使用框架特定API,保证容易测试。