Servlet 核心笔记整理
一、Servlet 是什么
全称:Servlet = Server Applet(运行在服务器端的小程序)
本质:是一个接口,定义了 Java 类被浏览器访问(Tomcat 识别)的规则
核心特征:
运行在服务器端,依赖于服务器(如 Tomcat)才能运行
属于动态资源,由 Java 代码实现,无主方法
需遵循特定规则,才能被 Tomcat 识别并处理
二、快速入门步骤
-
创建 Java EE 项目
-
定义一个类,实现 Servlet 接口
java
public class ServletDemo implements Servlet { ... }
-
实现接口中的抽象方法(核心: init() 、 service() 、 destroy() )
-
配置 Servlet(通过 URL 访问)
在 web.xml 中配置:
xml
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>全类名</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
作用:建立 URL 路径与 Servlet 类的映射关系
- 增加虚拟目录,部署到 Tomcat 后即可通过 URL 访问
三、执行原理
以访问 http://localhost:8080/项目名/demo1 为例:
-
解析 URL:Tomcat 接收客户端请求,解析出访问的 Servlet 资源路径 /demo1
-
查找映射:在 web.xml 中查找匹配的 <url-pattern>
-
定位类:通过 <servlet-name> 找到对应的 <servlet-class> (全类名)
-
加载创建:
-
将对应字节码文件加载到内存( Class.forName() )
-
Tomcat 通过反射创建该 Servlet 对象( cls.newInstance() )
- 调用方法:执行 service() 方法处理请求
四、Servlet 生命周期
- 核心方法
方法名 执行时机 执行次数 作用
init() Servlet 被创建时 1 次 初始化资源
service() 每次客户端访问时 多次 处理请求、提供服务
destroy() Servlet 正常销毁(服务器关闭)时 1 次 释放资源
- 创建时机
默认情况:第一次被访问时创建
可配置:在 <servlet> 标签下添加 <load-on-startup>
负数:第一次访问时创建(默认行为)
正数:服务器启动时创建,数字越小优先级越高
单例特性:一个 Servlet 在内存中只存在一个对象,是单例模式,多个用户共享同一个对象
- 线程安全问题
多个用户同时访问同一个 Servlet 对象时,可能存在线程安全问题
注意:尽量不要在 Servlet 中定义可修改的成员变量
-------------请求和响应
一、Tomcat请求响应基础
-
Web服务器接收到客户端HTTP请求后,会为**每一次请求**单独创建`HttpServletRequest`(请求对象)和`HttpServletResponse`(响应对象)。
-
`request`对象封装了客户端的请求数据,获取客户端提交数据需通过该对象实现。
-
`response`对象封装了服务器对客户端的响应数据,向客户端输出数据需通过该对象实现。
二、HttpServletRequest核心功能
`HttpServletRequest`是Servlet的`service()`方法参数之一,核心功能为封装请求数据、作为域对象存储数据、实现请求转发,其功能可分为四大类:封装请求头数据、封装请求正文数据、作为域对象、请求转发。
-
获取请求头数据
-
核心方法由Tomcat封装到`request`中,可在`service()`方法直接调用:
`String getHeader(String name)`:根据指定请求头名称获取对应值。
`Enumeration getHeaderNames()`:获取所有请求头的名称,可遍历获取所有请求头的键值对。
-
遍历示例:通过`getHeaderNames()`获取所有请求头名称,再通过`getHeader(name)`逐个获取值,可打印到控制台或响应到页面。
-
获取请求相关的其他核心方法
此类方法用于便捷获取请求头、请求URL相关数据,部分方法区分GET/POST请求(GET无正文,部分方法返回null/-1):
-
`int getContentLength()`:获取请求正文字节数,GET请求返回-1。
-
`String getContentType()`:获取请求类型,GET返回null,POST默认返回`application/x-www-form-urlencoded`。
-
`String getMethod()`:返回请求方法,如GET、POST、DELETE、PUT等。
-
`Locale getLocale()`:返回客户端浏览器支持的区域信息,用于国际化开发。
-
`String getCharacterEncoding()`:获取请求编码,未设置时返回null(默认ISO-8859-1)。
-
`void setCharacterEncoding(String code)`:设置请求编码,**仅对POST请求正文有效**,需在调用`getParameter()`前执行。
-
与请求URL相关方法(以`http://localhost:8080/hello/oneServlet?name=zhangSan\`为例):
-
`String getContextPath()`:返回项目上下文路径,例:`/hello`。
-
`String getQueryString()`:返回URL中的参数部分,例:`name=zhangSan`。
-
`String getRequestURI()`:返回请求URI路径,例:`/hello/oneServlet`。
-
`StringBuffer getRequestURL()`:返回完整请求URL(无参数),例:`http://localhost/hello/oneServlet\`。
-
`String getServletPath()`:返回Servlet访问路径,例:`/oneServlet`。
- 与客户端/服务器相关方法:
-
`String getRemoteAddr()`:返回客户端IP地址。
-
`String getRemoteHost()`:返回客户端主机名(实际仍获取IP)。
-
`int getRemotePort()`:返回客户端端口号(每次请求随机变化)。
-
`String getScheme()`:返回请求协议,例:`http`。
`String getServerName()`:返回服务器主机名,例:`localhost`。
`int getServerPort()`:返回服务器端口号,例:`8080`。
- 获取客户端请求参数(精通)
(1)参数传递的两种方式
-
GET方式:地址栏直接拼接、超链接拼接、表单`method="GET"`提交,参数在URL的queryString中,有长度限制。
-
POST方式:表单`method="POST"`提交,参数在请求正文中,无长度限制,更安全。
(2)获取参数的核心方法
无论GET/POST,获取参数的方法一致,方法适用于不同参数类型(单值/多值):
-
`String getParameter(String name)`:通过参数名获取**单值参数**,如文本框、单选框、隐藏域。
-
`String[] getParameterValues(String name)`:通过参数名获取**多值参数**数组,如复选框(同一name对应多个value)。
-
`Enumeration getParameterNames()`:获取所有请求参数的名称,可遍历获取所有单值/多值参数。
-
`Map<String, String[]> getParameterMap()`:获取所有参数的键值对Map,key为参数名,value为参数值数组(统一处理单/多值参数)。
(3)单值参数接收
-
前台:表单/超链接传递单值参数,如`<input type="text" name="p1">`。
-
后台:通过`getParameter(name)`直接获取,可结合`getParameterNames()`/`getParameterMap()`遍历所有参数。
(4)多值参数接收
-
前台:复选框使用同一name,如`<input type="checkbox" name="hobby" value="netplay">`。
-
后台:通过`getParameterValues(name)`获取字符串数组,或通过`getParameterMap()`遍历获取。
-
中文乱码处理(熟练)
request接收参数的乱码根源为**编码不统一**(默认ISO-8859-1,不支持中文),GET/POST请求处理方式不同,项目中通常统一使用UTF-8编码。
(1)POST请求中文乱码
POST参数在请求正文中,有两种处理方式,**推荐第二种**:
- 手动转码:先通过ISO-8859-1获取字节数组,再通过UTF-8重新编码为字符串。
示例:`name = new String(name.getBytes("ISO-8859-1"),"UTF-8");`
- 统一设置请求编码:在调用所有`getParameter()`前执行`request.setCharacterEncoding("UTF-8")`,一次设置全局生效,仅对POST正文有效。
(2)GET请求中文乱码
GET参数在URL中,无请求正文,`setCharacterEncoding()`无效,有两种处理方式:
-
手动转码:与POST手动转码方式一致,对每个中文参数单独处理。
-
配置服务器编码:修改Tomcat的`/conf/server.xml`,在`<Connector>`标签添加`URIEncoding="UTF-8"`,对整个Tomcat的GET请求生效。
-
注意:Tomcat8.5及以上版本已默认支持URL中文UTF-8编码,无需手动配置;**不建议使用GET请求传递中文参数**。
5. 请求转发与request作用域
(1)请求转发
-
概念:也叫**服务器端跳转**,Servlet处理完业务逻辑后,通过`request`跳转到目标资源(静态页面/Servlet/JSP),地址栏**不发生变化**。
-
核心方法:`request.getRequestDispatcher("资源路径").forward(request, response);`
-
特点:跳转过程中可通过`request`传递数据,目标资源能获取传递的属性值。
(2)request作用域
-
`request`是域对象,作用范围**仅在一次请求-响应过程中**,每一次请求都会创建新的`request`对象,请求结束后对象销毁。
-
数据操作方法:
-
`void setAttribute(String name, Object value)`:向request域中存入键值对数据。
-
`Object getAttribute(String name)`:从request域中根据键获取数据。
- 与ServletContext对比:ServletContext是全局域对象(服务器启动创建,关闭销毁),request是局部域对象(一次请求有效),request存数据更安全,不会造成数据共享冲突。
三、HttpServletResponse核心功能
`HttpServletResponse`是Servlet的`service()`方法参数之一,核心作用是**响应客户端请求,向客户端输出信息**,封装了服务器的响应数据(响应头、状态码、响应正文),核心功能分为四类:设置响应头、发送状态码、设置响应正文、实现重定向。
-
核心功能分类
-
设置响应头信息:如设置编码、刷新、重定向等响应头。
-
发送状态码:如200(成功)、404(资源不存在)、500(服务器错误)。
-
设置响应正文:向客户端输出文本、HTML等内容。
-
重定向:实现客户端跳转,地址栏发生变化。
-
设置状态码和基础编码方法
-
`response.setContentType("text/html;charset=utf-8")`:**核心方法**,同时设置响应内容类型为HTML、响应编码为UTF-8,解决响应页面中文乱码,需在输出内容前执行。
-
`response.setCharacterEncoding("utf-8")`:单独设置响应正文的编码,若未设置`contentType`,浏览器默认按ISO-8859-1解析,仍会乱码,通常与`setContentType`配合使用。
-
`response.setStatus(int sc)`:设置响应状态码,如`response.setStatus(200)`。
-
`response.sendError(int sc, String msg)`:发送错误状态码并携带提示信息,如`response.sendError(404, "您要查找的资源不存在")`,Tomcat会跳转到对应错误页面并显示提示。
-
设置响应头信息
-
`response.setHeader(String name, String value)`:设置自定义响应头,与`setContentType()`功能一致(`setContentType`是便捷方法),例:`response.setHeader("contentType", "text/html;charset=utf-8")`。
-
定时刷新/重定向:`response.setHeader("Refresh", "5; URL=http://www.baidu.com")`,表示5秒后自动跳转到指定URL。
-
响应中文乱码处理
向客户端输出中文时,需**先设置编码,再输出内容**,核心代码:
```java
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("中文内容");
-
重定向
-
概念:也叫**客户端跳转**,Servlet处理完业务逻辑后,通过`response`告诉客户端跳转到新的资源地址,客户端会重新发送请求,地址栏**发生变化**。
-
核心方法:`response.sendRedirect("资源路径")`。
-
特点:重定向后原`request`域中的数据全部失效,会创建新的`request`对象;支持跨域跳转(跳转到其他服务器的资源)。
四、请求转发(forward)与重定向(redirect)的区别(核心面试题)
-
处理流程不同
-
请求转发:客户端发送1次请求 → 服务器Servlet处理业务 → 服务器内部跳转到目标资源 → 服务器将目标资源结果返回客户端(**全程1次请求**)。
-
重定向:客户端发送1次请求 → 服务器Servlet处理业务 → 服务器返回跳转地址给客户端 → 客户端重新发送2次请求到新地址 → 服务器返回新资源结果(**全程2次请求**)。
-
地址栏表现不同
-
请求转发:**地址栏不变**,始终显示第一次请求的地址(服务器端内部跳转,客户端无感知)。
-
重定向:**地址栏变为新资源地址**,客户端能看到跳转后的地址。
3. 绝对路径中"/"的含义不同
-
请求转发:服务器内部跳转,`/`代表**当前Web应用的根目录**,例:`/success.jsp`(直接指向项目下的success.jsp)。
-
重定向:客户端重新请求,`/`代表**Tomcat服务器的根目录**,例:需写`/项目名/资源名`(`/param_demo/success.html`)。
-
相对路径:两者使用无区别,均基于当前页面路径解析。
-
数据传递不同
-
请求转发:属于同一次请求,可通过`request.setAttribute()`/`getAttribute()`传递数据(request作用域有效)。
-
重定向:属于两次不同请求,原request域数据失效,无法通过request传递数据,需使用session或URL拼接参数。
-
跳转范围不同
-
请求转发:**仅能跳转到当前Web应用内部的资源**,无法跨域(如跳转到百度)。
-
重定向:**支持跨域跳转**,可跳转到任意服务器的资源(如百度、其他项目)。