# JavaWeb1

# 1.BS和CS

对比维度 CS 架构(客户端 - 服务器) BS 架构(浏览器 - 服务器)
客户端要求 需要安装专用客户端软件 无需安装,使用标准浏览器即可
资源利用 客户端承担部分计算与存储,减轻服务器压力 所有计算与存储集中在服务器端
维护成本 高,需逐个客户端升级与维护 低,仅需更新服务器端应用
网络负荷 较低,客户端分担部分任务,数据传输量小 较重,频繁的请求 - 响应与数据交互
安全性 客户端可本地存储数据,存在一定安全风险 数据集中管理,安全性更易控制
适用场景 对性能要求高、离线可用的场景(如游戏、专业软件) 跨平台、易访问的场景(如网站、管理系统)

# 2.servlet入门

什么是Servlet? 1)Servlet是JavaEE规范之一。规范就是接口 2)Servlet是JavaWeb三大组件之一。三大组件分别是:Servlet程序、Filter过滤器、Listener监听器。 3)Servlet是运行在服务器上的一个java小程序。它可以接收客户端发送过来的请求,并响应数据给客户端。

1.在webapp下编写页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello World</h1>
<form action="add" method="post">
    名称:<input type="text" name="fname"/><br>
    价格:<input type="text" name="price"/><br>
    库存:<input type="text" name="stock"/><br>
    备注:<input type="text" name="remark"/><br>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

2.创建处理请求的java类

package com.demo.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class AddServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        String fname = request.getParameter("fname");
        String price = request.getParameter("price");
        int priceInt = Integer.parseInt(price);
        String stock = request.getParameter("stock");
        int stockInt = Integer.parseInt(stock);
        String remark = request.getParameter("remark");

        System.out.println(fname);
        System.out.println(priceInt);
        System.out.println(stockInt);
        System.out.println(remark);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

3.编写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>AddServlet</servlet-name>
        <servlet-class>com.demo.servlet.AddServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddServlet</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>
    <!--
1. 用户发请求,action=add
2. 项目中,web.xml中找到url-pattern = /add -> 第12行
3. 找第11行的servlet-name = AddServlet
4. 找和servlet-mapping中servlet-name一致的servlet,找到第7行
5. 找第8行的servlet-class -> com.demo.servlet.AddServlet
6. 用户发送的是post请求(method=post),因此 tomcat会执行AddServlet中的doPost方法
-->
</web-app>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

流程如下:

  1. 用户发请求,action=add
  2. 项目中,web.xml中找到url-pattern = /add -> 第12行
  3. 找第11行的servlet-name = AddServlet
  4. 找和servlet-mapping中servlet-name一致的servlet,找到第7行
  5. 找第8行的servlet-class -> com.demo.servlet.AddServlet
  6. 用户发送的是post请求(method=post),因此 tomcat会执行A

操作流程和注意事项:

  1. 新建项目 - 新建模块

  2. 在模块中添加 web

  3. 创建 artifact - 部署包

  4. lib - artifact

    先有 artifact,后来才添加的 mysql.jar。此时,这个 jar 包并没有添加到部署包中

    那么在 projectSettings 中有一个 Problems 中会有提示的,我们点击 fix 选择 add to...

    另外,我们也可以直接把 lib 文件夹直接新建在 WEB-INF 下。

    这样不好的地方是这个 lib 只能是当前这个 module 独享。如果有第二个 module 我们需要再次重复的新建 lib。

  5. 在部署的时候,修改 application Context。然后再回到 server 选项卡,检查 URL 的值。

    URL 的值指的是 tomcat 启动完成后自动打开你指定的浏览器,然后默认访问的网址。

    启动后,报错 404。404 意味着找不到指定的资源。

    如果我们的网址是:http://localhost:8080/pro01/,那么表明我们访问的是 index.html。

    我们可以通过<welcome-file-list>标签进行设置欢迎页(在 tomcat 的 web.xml 中设置,或者在自己项目的 web.xml 中设置)

  6. 405 问题。当前请求的方法不支持。比如,我们表单 method=post,那么 Servlet 必须对应 doPost。否则报 405 错误。

  7. 空指针或者是 NumberFormatException。因为有价格和库存。如果价格取不到,结果你想对 null 进行 Integer.parseInt () 就会报错。错误的原因 [略]

防止中文乱码:

  1. 设置编码 tomcat8之前,设置编码:
  1. get请求方式: //get方式目前不需要设置编码(基于tomcat8) //如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat8之前) String fname = request.getParameter("fname"); //1.将字符串打散成字节数组 byte[] bytes = fname.getBytes("ISO-8859-1"); //2.将字节数组按照设定的编码重新组装成字符串 fname = new String(bytes,"UTF-8");

  2. post请求方式: //post方式下,设置编码,防止中文乱码 //需要注意的是,设置编码这一句代码必须在所有的获取参数动作之前 request.setCharacterEncoding("UTF-8");


# 3.servlet继承关机以及service方法

1.继承关系:HttpServletGenericServletServlet

2.Servlet 中的核心方法:init()service()destroy()

3.服务方法:当有请求过来时,service 方法会自动响应(其实是 Tomcat 容器调用的)

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

1)在 HttpServlet 中会去分析请求的方式:到底是 get、post、put还是 delete 等

2)然后再决定调用的是哪个 do 开头的方法

 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }
1
2
3
4
5
6
7
8
9
10

3)在 HttpServlet 中这些 do 方法默认都是 405 的实现风格 —— 要我们子类去实现对应的方法

因此,我们在新建 Servlet 时,才会去考虑请求方法,从而决定重写哪个 do 方法


# 4.servlet生命周期

  1. 生命周期定义

    从出生到死亡的过程就是生命周期,对应 Servlet 中的三个核心方法:

  • init():初始化
  • service():服务处理
  • destroy():销毁
  1. 默认执行流程

第一次接收请求时:

  • 实例化(调用构造方法)
  • 初始化(调用 init()
  • 服务处理(调用 service()

从第二次请求开始:每次仅调用 service() 方法

容器关闭时:所有 Servlet 实例被销毁,调用 destroy() 方法

  1. 关键特性与结论

Tomcat 只会创建 一个 Servlet 实例,所有请求都由该实例响应。

默认在第一次请求时才实例化和初始化,好处是提高系统启动速度

若需提高响应速度,可调整 Servlet 初始化时机。

  1. 初始化时机配置

默认:第一次接收请求时实例化、初始化。

可通过 <load-on-startup> 配置启动顺序:

数字越小,启动越靠前,最小值为 0

配置后,Servlet 会在容器启动时就完成实例化和初始化,而非等待首次请求。

  1. 单例与线程安全

单例:所有请求共享同一个 Servlet 实例。

线程不安全:多个线程并发访问时,若修改成员变量,会导致逻辑错误。

启发:尽量不要在 Servlet 中定义成员变量;若必须使用,避免修改成员变量的值和进行逻辑判断。


# 5.Http协议

  1. HTTP 定义

    HTTP:超文本传输协议

    无状态协议:不保存任何状态信息,每个请求相互独立

  2. HTTP 请求 - 响应模型

    包含:请求、响应两部分

  3. HTTP 请求结构

    请求行

    • 请求方式(GET/POST 等)
    • 请求 URL
    • 请求协议(如 HTTP/1.1)

    请求消息头

    • 客户端信息(浏览器型号、版本等)
    • 内容类型、内容长度等

    请求主体

    • GET:无请求体,参数以 queryString 形式在 URL 中(如 ?name=xxx&age=xxx
    • POST:有请求体,如 form data
    • JSON:有请求体,如 request payload
  4. HTTP 响应结构

    响应行

    • 协议
    • 响应状态码
    • 响应状态描述

    响应头

    • 服务器信息
    • 内容媒体类型(如 text/htmlapplication/json)、编码、内容长度等

    响应体

    • 响应的实际内容(页面、数据等)

# 6.Session

通俗解释:比如你打开浏览器登录淘宝,浏览商品、加入购物车、下单,直到关闭浏览器,这整个过程就是一次 “会话”。

  1. HTTP 无状态特性

    • 默认是无状态协议
    • 无法判断两次请求是否来自同一个客户端
    • 实际问题:例如结账操作可能被另一个账户付款
  2. 解决方案:会话跟踪技术(Session)

    • 首次访问时,服务器会创建一个会话,并生成唯一的 sessionId
    • 后续请求携带该 sessionId,服务器即可识别客户端身份
    • 默认会话超时时间:1800 秒(30 分钟),超时未访问则会话被回收
  3. 保存会话作用域

    • session保存的作用域和具体某一个session是对应的

    • 常用API

              session.setAttribute("username","张三");
              session.getAttribute("username");
              session().removeAttribute("username");
      
      1
      2
      3
    • 当一个会话存入session,其他会话也能获取


# 7.服务器转发和重定向

  1. 服务器转发(内部转发)
  • 核心代码:request.getRequestDispatcher("/demo5").forward(req, resp);
  • 特性:属于服务器内部行为,客户端不知道转发次数
  • 地址栏:路径保持不变(显示最初请求的 URL)
  1. 重定向
  • 核心代码:response.sendRedirect("/demo5");
  • 特性:包含两次请求 - 响应过程,客户端能感知 URL 变化
  • 地址栏:路径会更新为重定向后的 URL

# 8.Thymeleaf

Thymeleaf是一个流行的模板引擎,该模板引擎采用Java语言开发。 使用步骤 1)添加thymeleaf的jar包 2)在web.wml文件中添加配置 3)新建一个Servlet类viewBaseServlet 4)使得我们的Servlet集成ViewBaseServlet


# 9、Servlet保存作用域

保存作用域:原始情况下,保存作用域我们可以认为有四个:

  • page(页面级别,现在几乎不用)

  • request(一次请求响应范围)

  • session(一次会话范围)

  • application(整个应用程序范围)

1)request:一次请求响应范围(内部转发也相当于一次)

2)session:一次会话范围有效(session不过期就相当于1次)

3)application:整个应用程序范围 (application.setAttribute())

最近更新: 9/19/2026, 1:27:08 PM
编程NOTE   |