1. 会话(Session)
1.1 相关概念
1.1.1 会话
从打开浏览器访问服务器开始,到访问服务器结束(关闭浏览器、到了过期时间)期间,产生的多次请求和响应加在一起就称之为两者之间的一次会话。
会话默认的超时时间是30分钟。
会话管理技术存在的意义是什么?
分析过程:
- 一个会话过程中肯定会产生多次请求响应
- 多次请求响应产生的数据需要共享,eg:登录状态/页面右上角显示的登录好的用户名。
- 问题在于:请求域的有效范围是当前这次请求,不易在多次请求之间共享。
所以就有了会话技术来:实现在一个会话中的多次请求响应之间共享数据。
完整总结:
在客户端或者服务器端
保存当前会话过程
中产生的一些数据
。
会话技术保证在同一个会话
的中多次请求
、多个页面跳转
时数据不会丢失。
Cookie:客户端会话管理技术(数据存在浏览器)
Session:服务器端会话管理技术(数据存在服务器,需要客户端配合)
2 cookie
2.1 概念
Cookie:浏览器端的会话管理技术。
Cookie的作用:把同一个会话中多次请求响应时产生的数据保存浏览器端并且共享。
cookie本质
:把一个字符串形式的键值对存储到客户端浏览器消息头(请求头/响应头)里面,消息头中只支持字符串。
xxx:yyyy ==> 浏览器的消息头(请求头/响应头)
第一次发起请求,在服务器创建一个cookie对象,设置name和vaule(String),resp.addCookie;如果响应对象向客户端响应了内容,响应对象会自动把设置好的cookie对象中的内容(name、value、path…)作为响应头传递给客户端。
当下次发起请求时,会自动携带刚才的cookie发起请求,后台可以通过request对象获取到之前已经存在的cookie并使用。
2.2 API
2.3 cookie的常见属性和方法
最重要的两个是name和value
/*
可以当做一个普普通通类来使用,先手动创建对象,再使用。
*/
public class Cookie implements Cloneable, Serializable {
private static final CookieNameValidator validation;
private static final long serialVersionUID = 1L;
/* 必须属性,被final,所以一旦赋值,不能修改。所以没有set方法*/
private final String name;
/* 必须属性,不要使用中文 */
private String value;
private int version = 0;
private String comment;
private String domain;
private int maxAge = -1;
private String path;
private boolean secure;
private boolean httpOnly;
/* 唯一的构造方法,决定了name和value是必须属性 */
public Cookie(String name, String value) {
validation.validate(name);
this.name = name;
this.value = value;
}
/* name没有setter */
public String getName() {
return this.name;
}
/* 其他的setter和getter成对出现 */
}
2.4 cookie的设置和获取
HttpServletResponse接口中定义的设置cookie方法。随着响应写入到了客户端。
void addCookie(Cookie var1);
HttpServletRequest接口中定义了获取cookie的方法,随着请求再次传递到了浏览器。
Cookie[] getCookies();// 获取请求对象中所有的cookie数组
2.4.1注意
先设置,下才能获取到
2.5 Cookie的使用
/*
Cookie的使用
*/
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.通过响应对象写出提示信息
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
pw.write("欢迎访问本网站,您的最后访问时间为:<br>");
//2.创建Cookie对象,用于记录最后访问时间
Cookie cookie = new Cookie("time",System.currentTimeMillis()+"");
//3.设置最大存活时间
cookie.setMaxAge(3600);
//cookie.setMaxAge(0); // 立即清除
//4.将cookie对象添加到客户端,该Cookie对象及其对应的消息头只有在下次请求时才会被提交到后台
// 后台通过request对象获取之后,使用
resp.addCookie(cookie);
//5.获取cookie
Cookie[] arr = req.getCookies();
for(Cookie c : arr) {
System.out.println("c.getPath() = " + c.getPath());
if("time".equals(c.getName())) {
//6.获取cookie对象中的value,进行写出
String value = c.getValue();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pw.write(sdf.format(new Date(Long.parseLong(value))));
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
判断cookie写入客户端成功?
开发者工具,查看当次请求的响应头,查找是否有一个叫set-Cookie
查看本次提交是否携带cookie?
开发者工具,查看当次请求的请求头,查找是否有一个叫cookie
效果
- 第一次访问时的请求响应消息头
- 下次访问时的请求响应消息头
属性详细说明
/*
name
Cookie 的名称只能包含 ASCII 码表中的字母、数字字符。
不能包含逗号、分号、空格,不能以 $ 开头。
value
Cookie 的值不建议使用中文
数量
API中表示20个/domain,300个/总量。
这是最开始的量,现在已经变大了,每个浏览器不一样,不用重点关注
大小
不能超过4k/个
maxAge
默认单位是秒
负数 cookie保存在浏览器内存中;关闭浏览器 ,cookie失效
0 cookie不保存;立即失效,无法使用
正数 cookie保存在浏览器本地文件,指定的时间(单位为秒)后失效
Cookie的路径(path)限制
取自第一次访问的资源路径前缀(/servlet/****)
只要以这个前缀为开头(包括子级路径),可以获取到
反之获取不到
可以手动通过cookie的setPath方法设置路径显示,调大/小范围,调大范围是要谨慎
经验:
1. 尽量少用path范围广的cookie
2. 范围广的cookie,如果要使用,尽量控制合理的有效期
3. 不用滥用cookie
*/
@WebServlet("/servlet/servletDemo02")
public class ServletDemo02 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie并添加
Cookie cookie = new Cookie("username","zhangsan");
cookie.setMaxAge(3600);
// cookie.setPath("/");
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
其他Servlet核心代码
@WebServlet("/servlet/servletDemo03") //前缀相同,可以获取到cookie
public class ServletDemo03 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] arr = req.getCookies();
for(Cookie c : arr) {
if("username".equals(c.getName())) {
String value = c.getValue();
resp.getWriter().write(value);
}
}
}
}
@WebServlet("/servlet/aaa/servletDemo04")//前缀相同,可以获取到cookie
public class ServletDemo04 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] arr = req.getCookies();
for(Cookie c : arr) {
if("username".equals(c.getName())) {
String value = c.getValue();
System.out.println("servletDemo04 c.getPath() = " + c.getPath());
System.out.println("servlet/servletDemo04");
resp.getWriter().write(value);
}
}
}
}
@WebServlet("/bbb/servletDemo05")//前缀不同,获取不到cookie。如果想获取到,可以在添加cookie的时候为其设置path 在ServletDemo02中 cookie.setPath("/");
public class ServletDemo05 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] arr = req.getCookies();
for(Cookie c : arr) {
if("username".equals(c.getName())) {
String value = c.getValue();
System.out.println("servletDemo05 c.getPath() = " + c.getPath());
System.out.println("servlet/servletDemo05");
resp.getWriter().write(value);
}
}
}
}
3 SESSION
受限于cookie这种会话管理技术的数量和大小限制,避免网络资源的浪费和不安全,就有了session这种服务器端的会话管理技术。
3.1 HttpSession概念
Session会话管理技术的接口
举例类比:某同学有巨额财富,喜欢喝牛肉汤
生活中 | Java中 |
---|---|
巨额财富 | 需要保存共享的数据 |
喝牛肉汤等消费 | 每次喝牛肉汤对应一个请求 |
开会员 | HttpSession 对象 |
会员卡/卡号 | 给客户端一个简单的特殊标识 |
概念总结
session
中存的共享数据是保存在服务器端的,浏览器端会持有一个与服务器session匹配的一个简单的特殊标记。
该特殊标记保存在浏览器cookie中,下次请求时携带该标记,就可以在服务器端找到一个与之对应的一个session
对象
3.2 HttpSession作用
作用:
- 在多个请求之间共享数据,而共享是通过
session域对象
这种载体实现的。 - 配合
cookie
实现用户追踪(本质上是第一种作用的一种具体应用场景)<案例:小播登录状态保存/右上角用户名>
作为域对象
存储数据
3.3 HttpSession的获取方式
方法解析:
HttpSession getSession()
:获取session,如果不存在自动创建一个新的。常用,重点。
HttpSession getSession(boolean autoCreate)
:获取session,获取不到是否自动创建,默认为true,自动创建。不用,麻烦。
执行流程解析:
- 情况1:携带JSessionID,找到就直接使用
- 情况2:携带JSessionID,没有找到就创建一个新的给使用,新session对象,新sessionid
- 情况3:未携带JSessionID,就创建一个新的给使用,新session对象,新sessionid
3.4 HttpSession常用方法
3.5 HttpSession使用
基本使用
/*
Session的基本使用
*/
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求的用户名
String username = req.getParameter("username");
//2.获取HttpSession的对象
HttpSession session = req.getSession();
System.out.println(session);
System.out.println(session.getId());
//3.将用户名信息添加到共享数据中
session.setAttribute("username",username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/*
Session的基本使用
*/
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取HttpSession对象
HttpSession session = req.getSession();
System.out.println(session);
System.out.println(session.getId());
//2.获取共享数据
Object username = session.getAttribute("username");
//3.将数据响应给浏览器
resp.getWriter().write(username+"");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
3.6 HttpSession使用细节
- 获取JSessionID
在前端
开发者工具里面,查看一个请求头cookie,值中含有“JSessionID=xxxxx”
在后台
session对象.getId();
- 禁用cookie后无法获取session的解决办法
产生原因:
session需要保存一个唯一标示在客户端,通过cookie技术;禁用cookie以后就不能保存该id,后面的方法就不能带着之前的session请求,所以无法获取session。
解决办法:
/*
Session的禁用的解决办法
*/
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求的用户名
String username = req.getParameter("username");
//2.获取HttpSession的对象
HttpSession session = req.getSession();
System.out.println(session);
System.out.println(session.getId());
//3.将用户名信息添加到共享数据中
session.setAttribute("username",username);
// 解决方式二:每个respone响应都要重写。与业务无关的代码不应该高频出现在业务代码中。
// 这种方式不推荐。
//实现url重写 相当于在地址栏后面拼接了一个jsessionid
resp.getWriter().write("<a href='"+resp.encodeURL("http://localhost:8080/session/servletDemo03")+"'>go servletDemo03</a>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
/*
Cookie的禁用
*/
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取HttpSession对象
HttpSession session = req.getSession(false);
System.out.println(session);
if(session == null) {
resp.setContentType("text/html;charset=UTF-8");
// 解决方式1:响应提示,提醒客户不要禁用cookie 推荐方式
resp.getWriter().write("为了不影响正常的使用,请不要禁用浏览器的Cookie~");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
- session的钝化和活化
目的是为了节省服务器内存,服务器重启维护时保证数据不丢失
会话开始:第一次访问时产生session
会话结束:关闭浏览器、调用session对象的销毁方法、会话超时(30min以上)
3.7 session的应用场景
常配合cookie使用,完成保存用户登录状态等信息
、购物车
等功能。
3.8 session和cookie的区别
项目 | cookie | session |
---|---|---|
存放位置 | 客户端浏览器 | 主要数据在服务器,同时浏览器存JSessionID |
存储内容不同 | ASCII 字符串 | 任何数据类型的数据,存入域对象(Map) |
安全性/隐式策略 | cookie对客户端来说可见 使用程序可以查删改其内容,不安全 | 数据存储在服务器session中,对客户端透明 不存在敏感信息泄露的风险 |
有效期 | 按需设置,setMaxAge() 可大可小 | session 有效期,默认半个小时 |
服务器压力 | 不大,数据存储在客户端 | 内存压力大 |
网络压力 | 大,所有数据都要通过网络传输 | 不大,传递只是一个JSessionID |
跨域支持 | 支持,通过domain 设置跨域 | 不支持,仅仅在当前项目的当前会话范围内有效 |
4. JSP
4.1 概念相关
JSP实现的项目是同步项目,体验不好,性能较低。
主流的是HTML实现异步项目,甚至是前后端分离。
web阶段要用它,web综合案例。是web阶段的重点。
4.1.1 规范
JavaEE的13大规范之一(jsp/servlet),是一种动态(资源)网页技术。
动态(资源):不同的人或不同的时间访问,看到的内容不一样
4.1.2 代码中
JSP ≈ html + servlet
页面(视图)模板,本质就是servlet。
之前怎么响应数据到页面
// 没有html结构
response.getWriter().write("xxx");
// 有页面结构的写法 很繁琐
response.getWriter().write("<html>");
response.getWriter().write("<a href='http://baidu.com'>点我啊</a>");
response.getWriter().write("</html>");
如果使用jsp之后,就不需要这么麻烦了
直接在jsp中编写HTML代码,他会自动解析,还可以把后台响应是数据填充到解析后的页面中。
4.2 JSP快速入门
JSP中支持所有在HTML中可用的标签,并能成功解析
<html>
<head>
<title>JSP</title>
</head>
<body>
<h1>这是我的第一个jsp</h1>
</body>
</html>
4.3 JSP执行过程
相对Servlet来说。多了翻译成java文件和编译成class文件这个步骤。(统一建模语言UML之一:时序图)
4.4 JSP生成的源码分析
4.4.1 idea做的工作
idea会为每一个web项目在idea的配置文件夹中创建一个tomcat配置的副本文件夹,jsp翻译的内容就在该文件夹中。
tomcat启动时,会在控制台输出如下内容:
会自动生成一个java文件和class文件,文件名:“jsp文件名_jsp.xxxx”。
4.4.2 jsp继承关系
jsp生成的java文件源码
// 由继承关系决定,jsp本质就是一个Servlet
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase{
}
HttpJspBase.java
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
}
4.4.3 JSP做了什么事情
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase{
// _jspService功能和servlet中service方法一致
public void _jspService(HttpServletRequest request, final HttpServletResponse response){
response.setContentType("text/html;charset=UTF-8");
// 输出流对象out 功能和respone.getWriter();一样
javax.servlet.jsp.JspWriter out = null;
out = pageContext.getOut();
// jsp帮我们完成了繁琐的页面布局内容的输出,会被浏览器解析
// 页面就变得有数据 + 样式布局 好看
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>JSP</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write(" <h1>这是我的第一个jsp</h1>\n");
out.write(" </body>\n");
out.write("</html>\n");
}
}
4.5 jsp语法
java代码块
和jsp声明
的区别
即:<%%>
和<%!%>
的区别
前者中的内容会被编译后放在_jspService()
方法中,局部位置。
后者的内容会在编译后放在当前JSP编译生成的Java类的成员位置。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp语法</title>
</head>
<body>
<%--
1. 这是注释
--%>
<%--
2.java代码块
System.out.println("Hello JSP"); 普通输出语句,输出在控制台
out.println("Hello JSP");
out是JspWriter对象,输出在页面上
println不会自动换行,请使用输出<br>换行
注意点:
写在<%%>java代码块中的内容,会被放在_jspServie()方法中
--%>
<%
System.out.println("Hello JSP");
out.println("Hello JSP<br>");
String str = "hello<br>";
out.println(str);
%>
<%--
3.jsp表达式 简化java代码块
<%="Hello"%> 相当于 out.println("Hello");
--%>
<%="Hello<br>"%>
<%--
4.jsp中的声明(变量或方法)
把声明的内容放在成员位置
如果加! 代表的是声明的是成员变量
如果不加! 代表的是声明的是局部变量
--%>
<%! String s = "abc";%>
<% String s = "def";%>
<%=s%>
<%-- 这个getSum是一个成员方法 --%>
<%! public void getSum(){}%>
<%-- 这个是想在_jspService() 方法中定义getSum2()。语法错误 --%>
<%--<% public void getSum2(){}%>--%>
</body>
</html>
4.6 jsp指令
重点
taglib
指令 引入第三方的标签库<%@ taglib uri=标签库的地址 prefix=前缀名称 %>
<%--
1.page指令 文档声明,完成Java代码相关功能。不用。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="/error.jsp" %>
<%--
2.include指令。整合其他jsp页面。不常用。
效果:就把另外一个jsp页面的内容完整的复制粘贴到当前位置
JSP有两种包含
静态包含:就是include指令。把被include的页面完整的复制过来,最终生成一个大的Servlet
动态包含: <jsp:include > (本质是servlet中的请求包含),最终生成的是两个Servlet
--%>
<%@ include file="/include.jsp"%>
<%--
3.taglib指令 引入第三方的标签库
--%>
<%@ taglib uri=标签库的地址 prefix=前缀名称 %>
<html>
<head>
<title>jsp指令</title>
</head>
<body>
<%--<% int result = 1 / 0; %>--%>
<%=s%>
<% out.println("aa");
%>
</body>
</html>
page指令标签的属性及作用(了解)
include指令标签(理解)
<%@ include file="/include.jsp"%>
taglib指令标签(后期重点学习)
<%@taglib prefix="" uri="" %>
4.7 动态包含和静态包含
4.7.1 相关概念和区别
include指令标签:静态包含:<%@ include file="/include.jsp"%>
动态包含:<jsp:include page="xxx.jsp">
静态包含:把被包含的页面整合(全部内容复制进来)进了包含页面,合成了一个Servlet
,对外提供服务。
动态包含:本质上就是请求包含。编译成两个Servlet
对外提供服务,先后顺序取决结构的上下顺序。相当于request.getRequestDispather(/jspinclude2_jsp).include(req,resp)
请求转发 ==> Servlet
和请求包含 ==> JSP
==> <jsp:include page="">
4.7.2 演示代码:静态包含
静态包含主页面
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="/error.jsp" %>
<%--
2.include指令,静态包含
--%>
<html>
<head>
<title>jsp-include指令:静态引入</title>
</head>
<body>
<%@ include file="/include.jsp"%>
<%=s%>
<%--
在使用s之后引入,使用s那行会报错
因为会把被引入的内容“粘贴”在引入的位置,造成先使用后声明的情况,不符合语法,所以报错。
<%@ include file="/include.jsp"%>
--%>
</body>
</html>
静态包含被页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>被包含的页面</title>
</head>
<body>
<% String s = "Hello"; %>
</body>
</html>
静态包含编译后效果,java
文件只有一个
所有代码都整合进主页面生成的java类的_jspService()
方法中:
4.7.3 演示代码:动态包含
动态包含主页面jspinclude1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>动态包含:主页面</title>
</head>
<body>
<%-- 包含代码的在页面结构中的位置,影响最终的显示效果 --%>
<jsp:include page="jspinclude2.jsp"/>
<h1>动态包含1</h1>
<h1>这是一个主JSP输出展示的内容</h1>
</body>
</html>
动态包含被包含页面jspinclude2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>动态包含:被包含页面</title>
</head>
<body>
<h1>动态包含2</h1>
<h1>这是被包含的jsp输出展示的内容</h1>
</body>
</html>
静态包含编译后效果,java
文件只有一个,每个文件保存自己编译后的代码
4.8 jsp九大内置对象(理解)
为了方便在jsp页面中使用servlet或者jsp中常用的对象,而把他们直接定义并初始化好,我们可以直接使用。
九大内置对象每个对象都是原来的对象,并没有做简化处理。
PageContext
- 可以通过该对象获取其他8大内置对象
- PageContext作为第四个域对象,可以直接操作其他3个域对象中的共享数据
4.9 四大域对象
三个servlet中的域对象和一个jsp中的域对象
从上到下,范围一次变大,能用小的,尽量不用大的。
九大内置对象中有四个本身就是域对象,通过pageContext这个内置对象(域对象)获取到另外三个域对象
使用原则:在满足业务需求的前提下,尽量使用范围小的域对象
5. web层MVC模型 + 软件三层(理解)
- 软件三层
- Web层(表现层):和前台页面打交道的
- M:Model,数据模型,对应实体类。作为整个项目数据传递的载体。
- V:View,视图,对应HTML/JSP。负责页面数据展示和收集。
- C:Controller,控制器,对应Servlet。负责简单数据和业务处理 。
- service(业务层):处理业务逻辑的
- dao(数据持久层):和后台数据库相关打交道的
- Web层(表现层):和前台页面打交道的
MVC 和 软件三层 是 两码事,是在不同的维度对项目进行拆分的方式
耦合
- 高内聚,低耦合
- OCP(open-close-principle):对增加开放,对修改关闭
动态包含2
这是被包含的jsp输出展示的内容
```4.8 jsp九大内置对象(理解)
为了方便在jsp页面中使用servlet或者jsp中常用的对象,而把他们直接定义并初始化好,我们可以直接使用。
九大内置对象每个对象都是原来的对象,并没有做简化处理。
PageContext
- 可以通过该对象获取其他8大内置对象
- PageContext作为第四个域对象,可以直接操作其他3个域对象中的共享数据
4.9 四大域对象
三个servlet中的域对象和一个jsp中的域对象
从上到下,范围一次变大,能用小的,尽量不用大的。
九大内置对象中有四个本身就是域对象,通过pageContext这个内置对象(域对象)获取到另外三个域对象
使用原则:在满足业务需求的前提下,尽量使用范围小的域对象
5. web层MVC模型 + 软件三层(理解)
- 软件三层
- Web层(表现层):和前台页面打交道的
- M:Model,数据模型,对应实体类。作为整个项目数据传递的载体。
- V:View,视图,对应HTML/JSP。负责页面数据展示和收集。
- C:Controller,控制器,对应Servlet。负责简单数据和业务处理 。
- service(业务层):处理业务逻辑的
- dao(数据持久层):和后台数据库相关打交道的
- Web层(表现层):和前台页面打交道的
MVC 和 软件三层 是 两码事,是在不同的维度对项目进行拆分的方式
耦合
- 高内聚,低耦合
- OCP(open-close-principle):对增加开放,对修改关闭