跳到主要内容

Java Web 演进过程

C/S、B/S、Java Bean、Cookie、Session、Servlet

两端

Java Web 是指用 Java 语言来解决相关 Web 领域的技术总和,一个 Web 应用程序包括 Web 客户端和 Web 服务器两个部分,即基于B/S(浏览器/服务器)架构的应用程序。

Web 客户端:一般是指浏览器

Web 服务器:一台或多台可运行 Web 应用程序的计算机;在浏览器输入的网站地址,就是服务器地址;Java 在服务器端的应用非常丰富,如 Servlet、JSP 和第三方框架等

两站

静态网站:

  • 早期的 Web 应用主要是静态页面的浏览,即静态网站。
  • 这些网站使用HTML语言来编写,放在Web服务器上,用户使用浏览器通过 HTTP 协议请求服务器上的 Web 页面,Web 服务器处理接收到的用户请求后发送给客户端浏览器显示给用户

动态网站:

  • 用户所访问的资源已不局限于服务器中保存的静态网页,更多的内容需要根据用户的请求动态生成页面信息,即动态网站
  • 这些网站通常使用 HTML 语言和动态脚本语言(如 JSP、ASP 或 PHP 等)编写,并将编写后的程序部署到 Web 服务器中
  • 由 Web 服务器处理动态脚本代码并将其转换为浏览器可以解析的 HTML 代码,最后返回客户端浏览器显示给用户

两结构

C/S 结构:Client(客户端) / Server(服务端)

⬇️(缩窄)

B/S 结构:Browser(浏览器) / Server(服务端)

内置对象:

  • Request 对象:
    • Request 对象是 javax.servlet.http.HttpServletRequest 类的实例
    • 代表请求对象,主要用于接受客户端通过HTTP协议连接传输到服务器端的数据,比如:表单中的数据、网页地址后带的参数等
  • Response 对象:
    • Response 对象是 javax.servlet.http.HttpServletResponse 类的实例
    • 代表响应对象,主要用于向客户端发送数据
  • Out 对象:
    • Out 对象是 javax.servlet.jsp.JspWriter 类的实例
    • 主要用于向客户端浏览器输出数据
  • session 对象:
    • Session 对象是 javax.servlet.http.HttpSession 类的实例
    • 主要用来保持在服务器与一个客户端之间需要保留的数据,比如在会话期间保持用户的登录信息等
    • 会话状态维持是 Web 应用开发者必须面对的问题,当客户端关闭网站的所有网页或关闭浏览器时,session 对象中保存的数据会自动清除;
    • 由于 HTTP 协议是一个无状态协议,不保留会话间的数据,因此通过 session 对象扩展了 HTTP 的功能,比如用户登录一个网站之后,登录信息会暂时保存在 session 对象中,打开不同的页面时,登录信息是可以共享的,一旦用户关闭浏览器或退出登录,就会清除 session 对象中保存的登录信息
  • Application 对象:
    • Application 对象是 javax.servlet.ServletContext 类的实例
    • 主要用于保存用户信息,代码片段的运行环境
    • 它是一个共享的内置对象,即一个容器中的多个用户共享一个 application 对象,故其保存的信息被所有用户所共享
  • PageContext 对象:
    • PageContext 对象是 javax.servlet.jsp.PageContext 类的实例
    • 用来管理网页属性,为 JSP 页面包装页面的上下文,管理对属于 JSP 中特殊可见部分中已命名对象的访问,它的创建和初始化都是由JSP容器来完成的
  • Config 对象:
    • Config 对象是 javax.servlet.ServletConfig 类的实例
    • 是代码片段配置对象,表示 Servlet 的配置
  • Page(相当于 this)对象:
    • Page 对象是 javax.servlet.jsp.HttpJspPage 类的实例
    • 用来处理 JSP 网页,它指的是 JSP 页面对象本身,或者说代表编译后的 servlet 对象,只有在 JSP 页面范围之内才是合法的
  • Exception 对象:
    • Exception对象是 java.lang.Throwable 类的实例
    • 处理 JSP 文件执行时发生的错误和异常只有在 JSP 页面的 page 指令中指定 isErrorPage="true" 后,才可以在本页面使用 exception 对象

Java Bean

产生背景

在 JSP 网页开发的初级阶段并没有框架与逻辑分层概念,需要将 Java 代码嵌入到网页中处理 JSP 页面中的一些业务逻辑,如字符串处理和数据库操作等

作用

如果使 HTML 与 Java 代码相分离,将 Java 代码单独封装成为一个处理某种业务逻辑的类,然后在 JSP 页面中调用此类,则可以降低 HTML 与 Java 代码之间的耦合度,并且简化 JSP 页面,提高 Java 程序代码的重用性及灵活性。这种与 HTML 代码相分离,而使用 Java 代码封装的类就是一个 JavaBean 组件。在 Java Web 开发中可以使用该组件来完成业务逻辑的处理

应用

JavaBean 是用 Java 语言所写成的可重用组件,其应用十分广泛,可以应用于系统的很多层中,如 PO、VO、[[DTO]] 和 POJO 等。

VO 用于后端向前端传输数据,DTO 用于前端向后端传输数据,BO 用于微服务之间传输数据,PO 等同于 Entity,DO 是 Entity 的一种,三者用于表示数据库的一条记录,通常用 Entity1

如何让服务器知道你来过?

Cookie 的作用:通俗地说就是当一个用户通过 HTTP 协议访问一个服务器的时候,这个服务器会将一些 Key/Value 键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。

这个作用就像你去超市购物时,第一次给你办张购物卡,这个购物卡里存放了一些你的个人信息,下次你再来这个连锁超市时,超市会识别你的购物卡,下次直接购物就好了。

由于 HTTP 协议是一种无状态协议,当用户的一次访问请求结束后,后端服务器就无法知道下一次来访问的还是不是上次访问的用户。在一个很短的时间内,如果与用户相关的数据被频繁访问,可以针对这个数据做缓存,这样可以大大提高数据的访问性能。Cookie 的作用正是在此:由于是同一个客户端发出的请求,每次发出的请求都会带有第一次访问时服务端设置的信息,这样服务端就可以根据 Cookie 值来划分访问的用户。

@WebServlet("/CookieTest")
public class CookieTest extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
Cookie[] cookies = request.getCookies();

PrintWriter out = response.getWriter();

if(cookies!=null){
out.println("上次访问的时间是:");
for (Cookie cookie : cookies) {
if("lastTime".equals(cookie.getName())){
long lastTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastTime);
out.println(date.toLocaleString());
}
}
}else{
out.println("你是第一来");
}

Cookie cookie = new Cookie("lastTime", String.valueOf(System.currentTimeMillis()));
//给cookie设置一些信息
//cookie.setMaxAge(500); //有效期
//cookie.setPath(uri);
//服务器端给客户端一个Cookie
response.addCookie(cookie);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

解决乱码:

//传中文,避免乱码。可以进行编码
Cookie cookie = new Cookie("lastTime",URLEncoder.encode("你好", "utf-8"));

//取出Cookie值,需要解码
URLDecoder.decode(cookie.getValue(),"utf-8");

Session

Cookie 可以让服务端程序跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些 Cookie,如果 Cookie很多,这无形地增加了客户端与服务端的数据传输量,而 Session 的出现正是为了解决这个问题

同一个客户端每次和服务端交互时,不需要每次都传回所有的 Cookie 值,而是只要传回一个 ID,这个 ID 是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有了一个唯一的ID,客户端只要传回这个 ID 就行了,这个 ID 通常是 NANE 为 JSESIONID 的一个 Cookie。

通俗来说就是:一个浏览器去服务器租房子,服务器记录一下浏览器的行为和数据,然后给了浏览器一把房间的钥匙,然后每次浏览器可以使用自己的钥匙去打开自己的房间,使用房间的所有东西。

上下文

ServletContext、ApplicationContext 由来

可以理解为建设在服务器上的公开场所、体育馆,所有浏览器都可以使用这些共享资源(减少服务器压力)。

Servlet 上下文

运行在 Java 虚拟机中的每一个 Web 应用程序都有一个与之相关的 Servlet 上下文。Java Servlet API 提供了一个 ServletContext 接口用来表示上下文。

在这个接口中定义了一组方法,Servlet 可以使用这些方法与它的 Servlet 容器进行通信,例如,得到文件的 MIME 类型,转发请求,或者向日志文件中写入日志消息。

ServletContext 对象是 Web 服务器中的一个已知路径的根。

比如:Servlet 上下文被定位于 http://localhost:8080/demo,那么以 /demo 请求路径(称为上下文路径)开始的所有请求被发送到与此 ServletContext 关联的 Web 应用程序(日常使用较多的是 / 根路径)

ServletContext:这个是来自于 servlet 规范里的概念,它是 servlet 用来与容器间进行交互的接口的组合,也就是说:这个接口定义了一系列的方法,servlet 通过这些方法可以很方便地与自己所在的容器进行一些交互。在一个应用中(一个 JVM),servlet 容器可以有多个,而所有的 servlet 容器共享一个 ServletContext。

两个时代

Model 1 时代

最初的 JSP 开发模式为 Model 1 模式:JSP + JavaBean

Model 2 时代

慢慢演变成 Model 2 模式:JSP + Servlet + JavaBean

一个简单的 Servlet 程序

参考了这篇文章2写了一个简单的 Servlet HelloWorld 程序,实际操作发现文章中有好几个步骤是多余的~

以下是简化后的操作步骤:

创建项目:

Add Framework Support:

编写 servlet 代码:

package com.xzp;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) {
System.out.println("get请求");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) {
System.out.println("post请求");
}
}

其中要引入 servlet 相关依赖包:

编写 jsp 页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>

编写 web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>servletTest</servlet-name>
<servlet-class>com.xzp.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletTest</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>

配置 Tomcat 启动项目:

浏览器查看页面,点击触发请求事件:

控制台成功打印:

信息

示例代码:code/learn-servlet/hello-servlet

Java Web 学习之谈

《初学 Java Web 开发,请远离各种框架,从 Servlet 开发》3

总结:

  1. 要有 Java 基础
  2. 环境准备:选择一个你喜爱的 Servlet 容器,或者说大一点就是应用服务器,推荐 Tomcat 、Resin 或者 Jetty 这些轻量级的产品
  3. 了解 Servlet 和 Filter:
  4. Servlet 和 HTTP 的对应关系:Servlet 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了
  5. 再谈 Session:HTTP 协议里是没有关于 Session 会话的定义,Session 是各种编程语言根据 HTTP 协议的无状态这种特点而产生的;其实现无非就是服务器端的一个哈希表,哈希表的 Key 就是传递给浏览器的名为 jsessionid 的 Cookie 值
  6. 关于 JSP:任何一个 JSP 页面在执行的时候都会编译成一个 Servlet 类文件;JSP 适合用来做视图,而 Servlet 则适合做控制层
  7. 最后:熟知 Servlet 规范之前,请不要学习任何框架;使用最简单的工具,不要任何向导和可视化;熟知 HTTP 协议

参考

Footnotes

  1. 浅析领域驱动模型VO、DTO、BO、PO 等的概念、区别及其用法 - 楼兰胡杨 - 博客园: https://www.cnblogs.com/east7/p/15057400.html

  2. 使用 Idea 创建一个 Servlet 项目并自动部署到 Tomcat 上 - 郑瀚Andrew - 博客园: https://www.cnblogs.com/LittleHann/p/17777980.html

  3. 初学 Java Web 开发,请远离各种框架,从 Servlet 开发 - OSCHINA - 中文开源技术交流社区: https://www.oschina.net/question/12_52027