文章目录
- JavaWeb - 03
- 一、Cookie
- 1. Cookie 应用
- 2. 注意点
- 二、Session
- 三、JSP
- 1. 概述
- 2. JSP 基础语法和指令(了解)
- 3. 内置对象及作用域
- 4. JSP 标签、JSTL 标签
- 四、JavaBean
- 五、MVC 三层架构
- 1. 之前的架构
- 2. 现在的 MVC 三层架构
- 注意:
JavaWeb - 03
一、Cookie
会话:代表的是客户端与服务器的一次交互过程,这个过程可以是连续也可以是时断时续的。会话存活期间,我们就能认为用户一直处于正在使用着网站的状态,一旦会话 Session 超期过时,那么就可以认为用户已经离开网站,停止交互,会话结束。
保存会话的两种技术:
- Cookie:客户端技术,一般保存在本地的用户目录下。
- Session:服务器技术,可以保存用户的会话信息,可以把信息或者数据放在 Session 中。
1. Cookie 应用
Cookie 应用:保存用户上一次访问的时间。
思路:
- 服务器从请求中拿到(得到) Cookie 信息,如:
Cookie[] cookies = request.getCookies();
;- 服务器响应给客户端 Cookie,如:
response.addCookie(cookie);
。
构造器 | 说明 |
---|---|
public Cookie(String name, String value) | 通过构造器新建一个 Cookie |
Cookie 方法 | 说明 |
---|---|
public void setMaxAge(int expiry) | 设置 Cookie 的有效期 expiry |
public String getName() | 获得 Cookie 的 key |
public String getValue() | 获得 Cookie 的 value |
注意:设置 Cookie 的有效期 expiry 为 0 时,相当于删除 Cookie 。
// 保存用户上一次访问的时间
request.setCharacterEncoding("utf-8");
response.setHeader("Content-type", "text/html; charset=utf-8");
// response.setContentType("text/html");
// response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 1. 服务器从客户端获取 Cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
// 如果存在,遍历数组,取出想要的 Cookie
out.println("您上次访问的时间为:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if ("lastLoginTime".equals(cookie.getName())) {
Long time = Long.parseLong(cookie.getValue());
// 格式化时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = sdf.format(time);
out.println(format);
}
}
} else {
System.out.println("这是您第一次访问");
}
// 2. 服务器给客户端响应一个 Cookie
Cookie cookie = new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis()));
cookie.setMaxAge(24*60*60); // 设置 cookie 的有效期
response.addCookie(cookie);
注意:服务器本次从客户端获取的 Cookie 是上一次响应的 Cookie,因此可以获得上一次访问的时间,并更新本次访问的时间。
2. 注意点
- 一个 Cookie 只能保存一个信息;
- 一个 Web 站点可以给浏览器发送多个 Cookie,最多存放 20 个 Cookie;
- Cookie 大小有限制,4kb;
- Cookie 浏览器限制为 300 个;
- 删除 Cookie 的方法:1. 不设置有效期,关闭浏览器就自动失效;2. 设置有效期时间为 0。
二、Session
- 服务器会给每个用户(浏览器)创建一个 Session 对象。
- 一个 Session 独占一个浏览器,只要浏览器没有关闭,这个 Session 就存在。
- 用户登录之后,整个网站都可以访问,使用场景如:购物车的信息、登录用户的信息等。
获得 Session:HttpSession session = request.getSession();
。
Session 方法 | 说明 |
---|---|
void setAttribute(String var1, Object var2) | 存信息 |
Object getAttribute(String var1) | 得到 value |
void removeAttribute(String var1) | 移除信息 |
String getId() | 得到 Session 的 ID |
boolean isNew() | 判断 Session 是否是新创建的 |
void invalidate() | 设置默认失效时间 |
// Demo01:给 Session 中存东西
request.setCharacterEncoding("utf-8");
response.setHeader("Content-type", "text/html; charset=utf-8");
// 得到 Session
HttpSession session = request.getSession();
// 给 Session 中存东西
session.setAttribute("name", "Sun3285");
session.setAttribute("person", new Person("太阳3285", 24, "reading"));
System.out.println(session.getAttribute("name"));
System.out.println(session.getAttribute("person").toString());
String id = session.getId();
if (session.isNew()) {
response.getWriter().println("Session 创建成功,ID:" + id);
} else {
response.getWriter().println("Session 在服务器中已经存在,ID:" + id);
}
// Demo02-1:手动注销 Session
session.removeAttribute("name");
session.invalidate();
<!-- Demo02-2:在 web.xml 中设置默认失效时间来注销 Session -->
<session-config>
<!-- 1 分钟后 Session 自动失效,以分钟为单位 -->
<session-timeout>1</session-timeout>
</session-config>
总结:
- 可以给 Session 中存东西,第二个参数为 Object 类型的数据,而 Cookie 只能存 String 类型。
- 同一个浏览器,只要没有关闭,无论开多少个窗口,Session 都不会改变。一旦关闭浏览器再重新打开,Session 都会发生改变,这是因为会生成一个新的
JSESSIONID
,通过这个新的JSESSIONID
获取到的 Session 就不是之前的 Session 了,但要注意,之前的 Session 并没有注销!- 当同一种浏览器用不同的窗口同时打开时,这两个窗口的 Session 一样。
- 关闭浏览器再次打开,Session 发生改变;使用不同类型的浏览器打开,Session 发生改变。
- 注销 Session 有两种方式,分为手动注销(调用方法设置失效)和自动注销(在
web.xml
中设置默认失效时间)。- 通过 Session 的 ID,可以保证这个用户是唯一的。
- Cookie 和 Session 的区别:
- Cookie 是把用户的数据写给用户的浏览器,浏览器(客户端)保存,可以保存多个;
- Session 是把用户的数据写到用户独占的 Session 中,服务器端保存,用来保存重要的信息,减少服务器资源的浪费;
- Session 存数据是 session 对象调用 setAttribute 方法,将数据存到服务器中;而 Cookie 存数据则是 response 调用 addCookie 方法,将 Cookie 存到浏览器中。
三、JSP
1. 概述
Java Server Pages:Java 服务器端页面,用于动态 Web 技术。
JSP 和 HTML 区别:
- HTML 只给用户提供静态的数据;
- JSP 页面中可以嵌入 Java 代码,为用户提供动态数据。
JSP 原理:JSP 本质上就是一个 Servlet(查看源码,可以发现 index_jsp
是一个 Java 类,并且继承了 HttpServlet
)。
注意:
- 浏览器向服务器发送请求,不管访问什么资源,其实都是在访问 Servlet,因此,JSP 最终也会被转换为一个 Java 类;
- JSP 中写 Java 代码,用
<% %>
括住。
打开 index_jsp.java
文件可以发现 JSP 的九大内置对象,这些对象都可以在 JSP 页面中直接使用:
final javax.servlet.jsp.PageContext pageContext; // pageContext:页面上下文
javax.servlet.http.HttpSession session = null; // session
final javax.servlet.ServletContext application; // application:ServletContext
final javax.servlet.ServletConfig config; // config
javax.servlet.jsp.JspWriter out = null; // out
final java.lang.Object page = this; // page:当前页面,几乎不用
final javax.servlet.http.HttpServletRequest request; // request
final javax.servlet.http.HttpServletResponse response; // response
exception // exception:异常
JSP 文件/页面执行流程:
注意:
- JSP 中写 Java 代码,用
<% %>
括住,转换为 java 文件时,会原封不动的显示;- JSP 中写 HTML 代码,转换为 java 文件时,会以一个个
out.write("<h2>Hello World!</h2>\n");
输出到前端;- 在浏览器中访问 JSP 页面时,地址栏需要写文件名和后缀,如
hello.jsp
。
2. JSP 基础语法和指令(了解)
- 准备工作
- 在
pom.xml
中导入依赖
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
- 配置 Tomcat 时,选项目为
war exploded
,热部署,改变代码不需要重启服务器,页面上的内容会自动刷新。
- JSP 基础语法
<%java 代码%> 作用:写 java 代码片段
<%=变量%> 作用:输出变量或者表达式的值,但一般用 EL 表达式(${变量})输出
<%!全局变量%> 作用:定义全局的变量、方法等
<%--注释--%> 作用:注释
<%@指令%> 作用:指令
- JSP 指令
<%@page args... %>
<%@include args... %> 作用:将两个页面合二为一
<%@taglib args... %>
举例:java 代码错误,跳转到自定义的错误页面。(两种方法)
<%-- 方法一:在 JSP 页面中用指令(一般写在最上面),该页面若有错误,跳转到指定的错误页面 --%>
<%@ page errorPage="error/500.jsp" %>
<!-- 方法二:在 web.xml 配置文件中配置错误页面,根据状态码来跳转 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
自定义的错误页面中插入图片的方法:
<%-- 方式一:返回上级路径,再进行选择 --%>
<img src="../errorimage/500.png" alt="500错误">
<%-- 方式二:获取当前项目路径 --%>
<img src="${pageContext.request.contextPath}/errorimage/404.png" alt="404错误页面">
注意:
- 方式一中的
../
为返回上一级文件夹;alt
表示若图片显示不出来的文字说明;- 最好用一个文件夹来存放图片,并且这个文件夹需要标记为资源文件夹,否则图片不能显示;
- 在 JSP 文件中,路径是从本 JSP 文件所在的文件夹开始,而
web.xml
文件中,路径是从该项目开始,即从生成的target
中的项目开始。
效果
3. 内置对象及作用域
九大内置对象见概述。
可以存数据的有(作用域从小到大):pageContext、request、session、application(ServletContext)。
- pageContext:保存的数据只在一个页面中有效,请求转发到新页面后,这个数据失效;
- request:保存的数据只在一次请求中有效,请求转发会携带这个数据;
- session:保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器;
- application:保存的数据在服务器中有效,从打开服务器到关闭服务器,其他用户(浏览器)也可以使用。
<%-- demo01.jsp:在四大作用域中存放数据,取数据 --%>
<%
pageContext.setAttribute("age1", 12);
request.setAttribute("age2", 24);
session.setAttribute("name1", "Sun3285");
application.setAttribute("name2", "Sun1234");
%>
<h1>${age1}</h1>
<h1>${age2}</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
<%-- demo02.jsp:只取数据 --%>
<h1>${age1}</h1>
<h1>${age2}</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
运行结果:
- 运行
demo01.jsp
后,结果:可以取到四个数据;- 在该浏览器下,重新开一个页面,运行
demo02.jsp
取数据,结果:只能取到后两个数据;- 换一个浏览器,运行
demo02.jsp
取数据,结果:只能取到最后一个数据。
两个补充知识:
- 用 JSP 语法输出变量与用 EL 表达式输出变量的区别
<%=变量%> | ${变量} | |
---|---|---|
相同点 | 可以输出变量的值 | 可以输出变量的值 |
不同点:当变量的值为空时 | 输出为 null | 没有输出 |
不同点:输出的条件 | 变量在内存中就可以输出 | 只能获取保存在四大作用域里面的变量 |
注意:EL 表达式只能获取保存在四大作用域里面的变量,如果没有获取到变量,就不会返回任何值,获取变量时,会在四大作用域中,从小到大依次找,直到找到值返回。
例如一,下列情况就不会输出 value1
的值,因为 value1
不是保存在四大作用域里面的变量。
<% String value1 = (String) pageContext.findAttribute("name1"); %>
<h1>${value1}</h1>
例如二,下列情况输出 name1
的值为 Sun1111
,因为获取变量时,会在四大作用域中,从小到大依次找,一找到值就返回。
<%
request.setAttribute("name1", "Sun1111");
session.setAttribute("name1", "Sun3333");
%>
<h1>${name1}</h1>
- 用
pageContext
也可以实现请求转发,请求转发只能跳转一次。
<%
// 请求转发
pageContext.forward("/error/500.jsp");
request.getRequestDispatcher("/demo01.jsp").forward(request, response);
application.getRequestDispatcher("/index.jsp").forward(request, response);
%>
4. JSP 标签、JSTL 标签
JSTL 标签的使用就是为了弥补 HTML 标签的不足,自定义了许多标签,可以使用,用到去查。
功能:和 Java 代码一样。
举例:用 JSTL 标签遍历集合。
<%-- JSTL 的核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:forEach var="s" items="${weather}" begin="1" end="3" step="2">
<c:out value="${s}" /> <br>
</c:forEach>
注意:
- 使用 JSTL 标签时,需要提前导入依赖(见第二节准备工作)以及 JSTL 的核心标签库(如图所示);
- 遍历集合中,
var
为每一次遍历出来的对象、items
为要遍历的对象、begin、end、step
为可选,分别为开始索引、结束索引以及步长;- 需要将集合存放在 request 作用域中,便于后面用 EL 表达式。
四、JavaBean
JavaBean 就是一个实体类,具有特定的写法:
- 必须要有一个无参构造器;
- 属性必须私有化;
- 必须有对应的 get/set 方法。
JavaBean 一般用来和数据库的字段做映射 ORM(对象关系映射,Object Relational Mapping):
- 数据库中的表 --(映射为)–> 类;
- 字段 --(映射为)–> 属性(成员变量);
- 行记录 --(映射为)–> 对象。
总结:每创建一个对象,就是创建了表中的一行数据,对象的每个属性就是表的每个字段。
举例:一个数据库
People
,对应了一个实体类People
。
- 数据库
people
- 对应的实体类
People
- 通过实体类创建对象来创建表的一行数据:
People p1 = new People(4, "周六", 19, "河北省");
五、MVC 三层架构
MVC 三层架构:模型(Model)、视图(View)、控制器(Controller)。
1. 之前的架构
注意:
- Servlet 和 JSP 都可以写 Java 代码,但是为了易于维护和使用,Servlet 专注于处理请求和控制视图跳转,而 JSP 专注于显示数据;
- 早些年的开发将控制器和视图层与实体类直接相连,这样,用户直接访问控制层,控制层就可以直接操作数据库。也就是说,在 Servlet 中不仅需要写处理请求、响应、视图跳转的代码,还需要写处理 JDBC 的代码,此外还需要写处理业务代码以及处理逻辑的代码,会导致程序十分臃肿,不利于维护;
- 解决上述问题:加一层。
2. 现在的 MVC 三层架构
MVC 三层架构分别负责:
- Model:
- 业务处理:业务逻辑(service);
- 数据持久层:CRUD(Dao)。
- View:
- 展示数据;
- 提供链接,发起 Servlet 请求。
- Controller:
- 接受用户的请求,例如用
request
接受请求的参数以及Session
信息等; - 交给业务层处理;
- 控制视图跳转。
- 接受用户的请求,例如用
举例:如果用户进行登录操作,会进行以下过程:
- 在视图层,用户点击【登录】按钮;
- 在控制层,接受用户的登录请求,并将数据(用户名,密码等数据)交给业务层;
- 在业务层中,由 service 判断用户名和密码是否正确;
- 在 Dao 层中,查询数据库中存放的用户名和密码;
- (第 3 步逆向)由 service 判断输入的信息与数据库中的信息是否一致;
- (第 2 步逆向)返回数据给控制层,进行视图跳转(重定向或转发);
- (第 1 步逆向)用户在视图层中可以看到视图跳转后的界面或存在数据的界面。
注意:
- long 类型的数据转换为 String 类型的数据:
String.valueOf(long 类型数据)
。 - String 类型的数据转换为 long 类型的数据:
Long.parseLong(String 类型数据)
。 - 中文显示乱码问题解决:
- 想让中文不乱码显示可以通过编码:
String str = URLEncoder.encode("中文", "utf-8");
。 - 对应的解码(恢复原来的编码):
String str1 = URLDecoder.decode(str, "utf-8");
。
- 想让中文不乱码显示可以通过编码:
- Java 包含了 Servlet,是 Servlet 一定是 Java。
- 更改了
web.xml
配置,必须重启服务器才能生效。 webapp
文件夹中放着一些 JSP 页面和用到的资源(如图片等)。- 在 Java 中跳转页面的方法:
- ServletContext:context 对象调用 getRequestDispatcher 实现请求转发;
- HttpServletRequest:request 对象调用 getRequestDispatcher 实现请求转发;
- HttpServletResponse:response 对象调用 sendRedirect 实现重定向;
- 跳转到自定义的错误页面:在 JSP 页面中用指令或在 web.xml 配置文件中配置错误页面。
- 请求转发只能跳转一次。
- 没有什么是加一层解决不了的。
- 通过
response.setHeader("Content-type", "text/html; charset=utf-8");
可以同时设置响应的页面类型和编码,也可以分别设置。