目录
通用方式获取请求参数(底层本质还是普通方式,只不过包装了一下)
概述
用Java技术来解决相关web互联网领域的技术栈.使用JAVAEE技术体系开发企业级互联网项目. 项目规模和架构模式与JAVASE阶段有着很大的差别. 在互联网项目下,首先需要明白客户端和服务器的概念
客户端 :与用户进行交互,用于接收用户的输入(操作)、展示服务器端的数据以及向服务器传递数据
服务端:与客户端进行交互,接收客户端的数据、处理具体的业务逻辑、传递给客户端其需要的数据
请求
客户端向服务端传递数据的主要方式之一,客户端主动向服务端发送请求,可以携带数据,交给服务端处理. 请求只能是客户端向服务端
响应
服务端向客户端传递数据的主要方式之一,在接收请求后开始对数据进行处理,将结果反馈给客户端使用.响应只能是服务端向客户端
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和和数据都存储在服务端
CS架构:Client/Server,客户端/服务器架构模式
WebApp
目录结构
一个可以部署在tomcat/webapps中的标准的app目录结构
-
app 本应用根目录
-
static 非必要目录,约定俗成的名字,一般在此处放静态资源 ( css js img)
-
WEB-INF 必要目录,必须叫WEB-INF,受保护的资源目录,浏览器通过url不可以直接访问的目录
-
classes 必要目录,src下源代码,配置文件,编译后会在该目录下,web项目中如果没有源码,则该目录不会出现
-
lib 必要目录,项目依赖的jar编译后会出现在该目录下,web项目要是没有依赖任何jar,则该目录不会出现
-
web.xml 必要文件,web项目的基本配置文件. 较新的版本中可以没有该文件,但是学习过程中还是需要该文件
-
-
index.html 非必要文件,index.html/index.htm/index.jsp为默认的欢迎页
-
其余目录名可以更改,但是WEB-INF(名子不能改)中的目录名必须是固定的(其中的目录名也不能改)
Http协议
超文本传输协议,规定了浏览器和服务器之间数据传输的规则
特点:
- 基于TCP协议:面向连接,安全
- 基于请求-响应模型的:一次请求对应一次响应
- HTTP协议是无状态的协议:对于事务处理没有记忆能力,每次请求-响应都是独立(后一次请求不会记录前一次请求)
- 缺点:多次请求间不能共享数据
- 优点:速度快
请求协议
请求行
请求数据第一行(请求方式、资源路径、协议)
请求头
第二行开始,格式key:value
请求体
POST请求才有请求体,存放POST请求参数
GET与POST
GET
- 发送的数据附加在URL之后,作为查询字符串的一部分,因此数据在浏览器的地址栏中可见。
- 由于数据附加在URL中,因此受到URL长度限制。
- 请求会被浏览器缓存,用户可以通过点击浏览器的刷新按钮来重复GET请求。
- 通常只用于发送ASCII字符。
- 适用于搜索、查询、排序等不需要改变服务器资源状态的操作。
- 请求会被保存在浏览器的历史记录中。
POST
- 数据通常放在HTTP请求的请求体(body)中,不在URL中显示,因此对于用户不可见。
- 没有数据大小限制,可以发送大量数据。
- 请求不会被缓存,刷新按钮通常不会重复POST请求,除非特别设置。
- 可以发送非ASCII字符,如二进制数据。
- 适用于需要在服务器上创建资源的操作,如注册、登录、上传文件等。
- 请求不会保存在浏览器的历史记录中。
响应协议
响应行
响应数据第一行(协议、状态码、描述)
状态码大类:
- 200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
- 302: 重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location指定新请求的URL地址;
- 304:使用了本地缓存
- 404:请求的资源没有找到,说明客户端错误的请求了不存在的资源;
- 405:请求的方式不允许
- 500:请求资源找到了,但服务器内部出现了错误;
响应头
第二行开始,格式key:value
响应体
最后一部分,存放响应数据
Servlet
简介
Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口
- 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器
- 不是所有的JAVA类都能用于处理客户端请求,能处理客户端请求并做出响应的一套技术标准就是Servlet
- Servlet是运行在服务端的,所以Servlet必须在WEB项目中开发且在Tomcat这样的服务容器中运行
快速入门
Servlet生命周期
生命周期简介
Servlet容器
- Servlet对象是Servlet容器创建的,生命周期方法都是由容器(目前我们使用的是Tomcat)调用的。这一点和我们之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多的将精力放在业务逻辑的实现上。
Servlet主要的生命周期执行特点
生命周期 | 对应方法 | 执行时机 | 执行次数 |
加载和实例化 | 构造器 | 第一次请求或者容器启动 | 1 |
初始化 | init() | 构造完毕后 | 1 |
请求处理 | service(HttpServletRequest req,HttpServletResponse resp) | 每次请求 | 多次 |
服务终止 | destory() | 容器关闭 | 1 |
生命周期总结
通过生命周期测试我们发现Servlet对象在容器中是单例的
容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程
多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量
load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复
Tomcat容器中,已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5
Servlet体系结构
-
HttpServletRequest 代表请求对象,是有请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息
-
HttpServletResponse 代表响应对象,该对象会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息
-
Servlet对象的生命周期(创建,初始化,处理服务,销毁)是由tomcat管理的,无需我们自己new
-
HttpServletRequest HttpServletResponse 两个对象也是有tomcat负责转换,在调用service方法时传入给我们用的
- 自定义Servlet中,必须要对处理请求的方法进行重写
- 要么重写service方法
- 要么重写doGet/doPost方法(HttpServlet)
Servlet urlPattern配置
ServletConfig和ServletContext
ServletConfig的使用
ServletConfig:
-
为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象
-
容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性
ServletConfig是一个接口,定义了如下API:
package jakarta.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
}
方法名 | 作用 |
---|---|
getServletName() | 获取<servlet-name>HelloServlet</servlet-name>定义的Servlet名称 |
getServletContext() | 获取ServletContext对象 |
getInitParameter() | 获取配置Servlet时设置的『初始化参数』,根据名字获取值 |
getInitParameterNames() | 获取所有初始化参数名组成的Enumeration对象 |
ServletConfig测试代码如下:
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
// 根据参数名获取单个参数
String value = servletConfig.getInitParameter("param1");
System.out.println("param1:"+value);
// 获取所有参数名
Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
// 迭代并获取参数名
while (parameterNames.hasMoreElements()) {
String paramaterName = parameterNames.nextElement();
System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));
}
}
}
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
// 根据参数名获取单个参数
String value = servletConfig.getInitParameter("param1");
System.out.println("param1:"+value);
// 获取所有参数名
Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
// 迭代并获取参数名
while (parameterNames.hasMoreElements()) {
String paramaterName = parameterNames.nextElement();
System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));
}
}
}
ServletContext的使用
ServletContext是什么:
-
ServletContext对象有称呼为上下文对象,或者叫应用域对象
-
容器会为每个app创建一个独立的唯一的ServletContext对象
-
ServletContext对象为所有的Servlet所共享
-
ServletContext可以为所有的Servlet提供初始配置参数
ServletContext怎么用:
-
配置ServletContext参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<context-param>
<param-name>paramA</param-name>
<param-value>valueA</param-value>
</context-param>
<context-param>
<param-name>paramB</param-name>
<param-value>valueB</param-value>
</context-param>
</web-app>
-
在Servlet中获取ServletContext并获取参数
package com.atguigu.servlet;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从ServletContext中获取为所有的Servlet准备的参数
ServletContext servletContext = this.getServletContext();
String valueA = servletContext.getInitParameter("paramA");
System.out.println("paramA:"+valueA);
// 获取所有参数名
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
// 迭代并获取参数名
while (initParameterNames.hasMoreElements()) {
String paramaterName = initParameterNames.nextElement();
System.out.println(paramaterName+":"+servletContext.getInitParameter(paramaterName));
}
}
}
ServletContext其他重要API
获取资源的真实路径:
String realPath = servletContext.getRealPath("资源在web目录中的路径");
-
例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径. 只要使用了servletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题
获取项目的上下文路径:
String contextPath = servletContext.getContextPath();
-
项目的部署名称,也叫项目的上下文路径,在部署进入tomcat时所使用的路径,该路径是可能发生变化的,通过该API动态获取项目真实的上下文路径,可以帮助我们解决一些后端页面渲染技术或者请求转发和响应重定向中的路径问题
域对象的相关API
-
域对象: 一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同
-
ServletContext代表应用,所以ServletContext域也叫作应用域,是webapp中最大的域,可以在本应用内实现数据的共享和传递
-
webapp中的三大域对象,分别是应用域,会话域,请求域
API | 功能解释 |
---|---|
void setAttribute(String key,Object value); | 向域中存储/修改数据 |
Object getAttribute(String key); | 获得域中的数据 |
void removeAttribute(String key); | 移除域中的数据 |