Servlet
Servlet技术
什么事Servlet
- Servlet是JavaEE规范之一。规范就是接口
- Servlet是JavaWeb三大组件之一。三大组件分别是:Servlet程序、Filter过滤器、Listener监听器
- Servlet试运行在服务器上的一个java小程序,他可以接后客户端发送过来的请求,并响应数据给客户端
手动实现Servlet接口
- idea创建项目准备
点击左上角 + 选择 local Tomcat
配置项目工程名
引入jar包
- 手动实现Servlet程序
- 编写一个类去实现Servlet接口
- 重写service方法,处理请求,并响应数据
- 到web.xml中去配置servlet程序的访问地址
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello servlet");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
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 标签给Tomcat配置的Servlet程序 -->
<servlet>
<!-- servlet-name 标签 servlet程序起一个别名(一般是类名) -->
<servlet-name>HelloServlet</servlet-name>
<!-- servlet-class 是 servlet程序全类名 -->
<servlet-class>com.zhj.controller.HelloServlet</servlet-class>
</servlet>
<!-- servlet-mapping 标签 给servlet程序配置访问地址 -->
<servlet-mapping>
<!-- 当前配置地址给那个servlet程序使用 -->
<servlet-name>HelloServlet</servlet-name>
<!--
url-pattern 配置标签访问地址
/ 在服务器解析的时候,表示地址为 :http://ip:port/工程名
/hello : http://ip:port/工程名/hello
-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Servlet的生命周期
- 执行Servlet构造方法
- 执行init初始化方法
第一步,第二步,是在第一次访问的时候servlet程序会调用 - 执行service方法
第三步,每次访问的时候都会调用 - 执行destroy销毁方法
第四步,在web工程停止的时候调用
请求分发 Get 与 Post
在service方法中加判断
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
if (httpServletRequest.getMethod().equals("GET")) {
doGet();
}
if (httpServletRequest.getMethod().equals("POST")) {
doPost();
}
}
private void doPost() {
System.out.println("post 请求 ------");
}
private void doGet() {
System.out.println("get 请求 ------");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
在web目录下创建 a.html,
访问 http://localhost:8080/my_servlet/a.html 测试
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://localhost:8080/my_servlet/hello" method="get">
<!--<form action="http://localhost:8080/my_servlet/hello" method="post">-->
<input type="submit" value="提交">
</form>
</body>
</html>
手动集成HttpServlet接口
- 编写一个类继承 HttpServlet 类
- 根据业务需要重写 doGet 或 doPost 方法
- 到web.xml中配置 Servlet 程序的访问地址
public class Hello2Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get 方法 ----");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post 方法 ----");
}
}
<servlet>
<servlet-name>Hello2Servlet</servlet-name>
<servlet-class>com.zhj.controller.Hello2Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello2Servlet</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
测试
<form action="http://localhost:8080/my_servlet/hello2" method="get">
<input type="submit" value="get 提交">
</form>
<form action="http://localhost:8080/my_servlet/hello" method="post">
<input type="submit" value="post 提交">
IDEA中快速创建Servlet方式
Servlet的继承体系
ServletConfig类
ServletConfig类从类名上来看,就知道是servlet程序的配置信息类
Servlet程序和ServletConfig对象都是Tomcat负责创建,我们负责使用
Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建是,就创建一个对应的ServletConfig
ServletConfig类三大作用
@Override
public void init(ServletConfig servletConfig) throws ServletException {
// 1. 可以获取Servlet程序的别名 servlet-name 的值
System.out.println(servletConfig.getServletName());
// 2. 获取初始化参数 init-param
System.out.println(servletConfig.getInitParameter("user"));
System.out.println(servletConfig.getInitParameter("password"));
// 3. 获取 ServletContext 对象
System.out.println(servletConfig.getServletContext());
}
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zhj.controller.HelloServlet</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>1234</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
细节说明
- 在一个Servlet程序中,任意地方都可以获取 servletConfig对象: getServletConfig()
- 如果重新 init的方法,必须调用一下 父类 super.init(config);
ServletContext类
什么是ServletContext?
- ServletContext是一个接口,他表示 Servlet 上下文对象
- 一个web工程,只有一个ServletContext对象实例
- ServletContext对象是一个域对象
- ServletContext是在web工程部署启动的时候创建。在web工程停止的时候销毁
什么是域对象?
域对象,是可以想Map一样存取数据的对象,叫做域对象
这里的域指存取数据的操作范围
域对象 setAttribute() getAttribute() removeAttribute()
ServletContext类的四个作用
- 获取web.xml中配置的上下文参数 context-param
- 获取当前工程路径,格式: /工程路径
- 获取工程部署后在服务器硬盘上的绝对位置
- 像Map一样存取数据
public class Hello4Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取 ServletContext 对象
// ServletContext servletContext = getServletConfig().getServletContext();
ServletContext servletContext = getServletContext();
// 1. 获取web.xml中配置的上下文参数 context-param
System.out.println(servletContext.getInitParameter("name"));
System.out.println(servletContext.getInitParameter("password"));
// 2. 获取当前工程路径,格式: /工程路径
System.out.println(servletContext.getContextPath());
// 3. 获取工程部署后在服务器硬盘上的绝对位置
/**
* / 斜杠被服务器解析地址为 http://ip:port/工程名/
* 映射到IDEA代码的web目录
*/
System.out.println(servletContext.getRealPath("/"));
System.out.println(servletContext.getRealPath("/css"));
// 4. 像Map一样存取数据
servletContext.setAttribute("zhangsan",333);
System.out.println(servletContext.getAttribute("zhangsan"));
}
}
<context-param>
<param-name>name</param-name>
<param-value>user</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
<servlet>
<servlet-name>Hello4Servlet</servlet-name>
<servlet-class>com.zhj.controller.Hello4Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello4Servlet</servlet-name>
<url-pattern>/hello4</url-pattern>
</servlet-mapping>
HTTP协议
什么是HTTP协议
什么是协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。
所谓的HTTP协议,就是指,客户端与服务器通信时,发送的数据需要遵守的规则,叫做HTTP协议。HTTP协议中的数据又叫报文
GET请求
POST请求
常用请求头说明
Accept: 表示客户端可以接收的数据类型
Accept-Language: 表示客户端可以接收的语言类型
User-Agent : 表示客户端浏览器的信息
Host : 表示请求时的服务器IP和端口号
HTTP响应
常用响应码说明
200 表示请求成功
302 表示请求重定向
404 表示请求服务器已经收到了,数据不存在
500 服务器错误
MIME类型的说明
HttpServletRequest类
HttpServletRequest类的作用
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。然后传递到service方法(doGet或者doPost中给我们使用,我们可以通过HttpServletRequest对象,获取所有请求的信息)
HttpServlet类的常用方法
- getRequestURI() 获取请求资源路径
- getRequestURL() 获取请求绝对路径
- getRemoteHost() 获取IP
- getHeader() 获取请求头信息
- getParameter() 获取请求参数
- getParameterValues() 获取请求多个参数
- getMethod() 获取请求方式
- setAttribute() 设置域值
- getAttribute() 获取域值
- getRequestDispatcher() 获取请求转发对象
public class Hello5Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 5. getParameter() 获取请求参数
// 6. getParameterValues() 获取请求多个参数
// 保证post请求中文不乱码
request.setCharacterEncoding("UTF-8");
System.out.println("用户名: "+request.getParameter("username"));
System.out.println("密码: "+request.getParameter("password"));
System.out.println("爱好: "+ Arrays.asList(request.getParameterValues("hobby")));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. getRequestURI() 获取请求资源路径
System.out.println("获取请求资源路径 " + request.getRequestURI());
// 2. getRequestURL() 获取请求绝对路径
System.out.println("获取请求绝对路径 " + request.getRequestURL());
// 3. getRemoteHost() 获取IP
System.out.println("获取IP "+request.getRemoteHost());
// 4. getHeader() 获取请求头信息
System.out.println("获取请求头信息 Accept " + request.getHeader("Accept"));
// 7. getMethod() 获取请求方式
System.out.println("获取请求方式 "+request.getMethod());
}
}
<form action="http://localhost:8080/my_servlet/hello5" method="post">
用户名: <input type="text" name="username">
密码 : <input type="password" name="password">
爱好:
<input type="checkbox" name="hobby" value="篮球">
<input type="checkbox" name="hobby" value="足球">
<input type="checkbox" name="hobby" value="乒乓球">
<input type="submit" value="提交">
</form>
请求转发
特点:
- 浏览器地址没有发生改变
- 他们是一次请求
- 它们共享Request域中的数据
- 可以转发到WEB-INF目录下(浏览器上面是无法访问的)
- 不可以访问工程以外的资源
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("name","zhangsan");
// 注意 必须加 / , 因为 / 表示: http://ip:port/项目名/
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
requestDispatcher.forward(req,resp);
}
}
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getAttribute("name"));
}
}
bash标签的作用
页面相对路径工作时参照的地址
href 属性就是参数的地址值
web 中 / 的不同意义
在web中 / 是一种绝对路径。
- / 如果被浏览器解析,得到的地址 是 :http://ip:port/
<a href="/"> 斜杠</a>
- / 如果被服务器解析,得到的地址是: http://ip:port/工程路径
<url-pattern>/servlet1</url-pattern>
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
servletContext.getRealPath("/")
- 特殊情况:response.sendRedirect(“/”) ;
把斜杠发送给浏览器解析: http://ip:port/
HttpServletResponse类
HttpServletResponse类的作用
HttpServletResponse类和HttpServletRequest类一样。每次请求进来,tomcat服务器都会创建一个Response对象传递给Servlet程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse表示所有响应信息
两个输出流的说明
字节流: getOutputStream(); 常用于下载(传递二进制数据)
字符流: getWriter(); 常用于回传字符串(常用)
注意: 两个流同时只能使用一个,否则 报错
乱码问题解决
方式一
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 方式一
*/
// 设置服务器端
resp.setCharacterEncoding("UTF-8");
// 设置浏览器端
resp.setHeader("Content-Type","text/html;charset=UTF-8");
resp.getWriter().write("中国你好");
}
方式二
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 方式二 : 此方法需要在获取流之前
*/
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("中国你好");
}
重定向
- 方案一
resp.setStatus(302);
resp.setHeader(“Location”,“http://localhost:8080”); - 方案二
response.sendRedirect(“http://localhost:8080”) ;
会话追踪技术
- 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,绘画结束,再一次会话中可以包含多次请求与响应(可以理解为打开一次浏览器)
- 会话追踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
- Http协议是无状态的,每次浏览器想服务器请求时,服务器多会将该请求视为新的请求,因此我们需要会话跟踪技术来实现来实现会话内数据共享
- 实现方式
- 客户端会话追踪技术:Cookie
- 服务端会话追踪技术: Sessioin
Cookie
Cookie的基本使用
- Cookie : 客户端会话追踪技术,以后每次请求都携带Cookie数据进行访问
- Cookie的基本使用:
- 创建Cookie对象,设置数据
Cookie cookie = new Cookie(“key”,“value”);
- 发送Cookie到客户端: 使用Response对象
response.addCookie(cookie);
- 获取客户端携带的所有Cookie,使用request对象
Cookie[] cookies = request.getCookies();
- 遍历数组,获取每个Cookie对象:for
- 使用Cookie对象方法获取数据
cookie.getName()
cookie.getValue()
Cookie原理
Cookie的实现是基于HTTP协议的
- 响应头: set-cookie
- 请求头: cookie
Cookie使用细节
-
Cookie存活时间
默认情况下,Cookie存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁但是
可以通过setMaxAge(int seconds) 设置Cookie存活时间- 正数:将Cookie写在浏览器所在电脑的硬盘,持久化存储。到时间后自动删除
- 负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie别销毁
- 零: 删除对应的Cookie
-
Cookie存储中文
Cookie 不能直接存储中文
但是
如果需要存储,则需要进行转码: URL编码
Session
服务端会话跟踪技术:将数据保存到服务器
JavaEE提供了HttpSession接口,来实现一次会话的多次请求间数据共享功能
Session基本使用
- 获取Session对象
HttpSession session = new HttpSession(); - Session对象的功能
setAttribute()
getAttribute()
removeAttribute()
Session是基于Cookie实现的
Session的使用细节
- Session钝化、活化
服务器重启后,Session中的数据是否存在?存在
钝化:在服务器正常关闭后,Tomcat会自动将Session数据写到硬盘的文件中
活化:再从启动服务器后,从文件加载数据到Session - Session销毁
默认情况下,无操作,30分钟自动销毁
在web.xml中可配置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
或者主动调用 Session对象的invalidate()方法销毁
Cookie与Session的区别
Cookie和Session都是来完成一次会话多次请求间数据共享的
区别:
- 存储位置:Cookie是将数据存储在客户端,Session是将数据存储在服务器
- 安全性:Cookie不安全,Session相对安全
- 数据大小: Cookie最大3KB,Session无大小限制
- 存储时间: Cookie可以长期存储,Session默认30分钟
- 服务器性能: Cookie不占服务器资源,Sessino占用服务器资源
Filter
- 概念:Filter表示过滤器,是JavaWeb三大组件(Servlet,Filter,Listener)之一
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
Filter快速入门
- 定义类,实现Filter接口,并重写其所有方法
- 配置Filter拦截资源的路径:在类定义@WebFilter注解
- 在doFilter方法中输出一句话,并放行
@WebFilter("/*")
public class FilterDemo implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 放行前逻辑
System.out.println("Filter 被执行了");
// 放行
filterChain.doFilter(servletRequest,servletResponse);
// 放行后逻辑
System.out.println("Filter 返回");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
Filter执行流程
Filter拦截路径配置
Filter可以根据需求,配置不同的拦截资源路径
@WebFilter(“/*”)
public class FilterDemo
- 拦截具体资源: /index.jsp : 只有访问index.jsp时才被拦截
- 目录拦截: /user/* :访问/user下的所有资源,都会被拦截
- 后缀名拦截: *.jsp : 访问后缀名为jsp的资源,都会被拦截
- 拦截所有: /* : 访问所有资源都会被拦截
过滤器链
监听器
- 概念:Listener 表示监听器,是JavaWeb三大组件(Servlet、Filter、Listener)之一
- 监听器可以监听到就是在application、sessoin、request三个对象创建、销毁或者往里面添加修改删除属性时自动执行代码的功能组件
- Listener分类: javaWeb提供了8个监听器
ServletContextListener使用
- 定义类,实现ServletContextListener接口
- 在类上添加@WebListener注解
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("servlet 容器 创建");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("servlet 容器 销毁");
}
}
JSP
- 概念: JAVA Server Pages. Java服务端页面
- 一种动态的页面技术,其中既可以定义HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容
- JSP = HTML + JAVA
JSP快速入门
- 导入JSP坐标
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
-
创建JSP文件
-
编写HTML标签和JAVA代码
<h1>hello world</h1>
<%
System.out.println("hello world");
%>
EL表达式
- Expression Lanuage表达式语言,用于简化JSP页面的Java代码
- 主要功能:获取数据
- 语法:${expression}
- JavaWeb的四大域对象:
page : 当前页面有效
request: 当前请求有效
session : 当前会话有效
application: 当前应用有效
el表达式获取数据,会依次从这四个域中寻找,直到找到为止
JSTL快速入门
- 导入坐标
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
- 引入JSP标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 使用
<c:if>
报错:
无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/jstl/core]
的错误
通过百度搜索到,需要如下操作:
把jstl-1.2.jar和standard.jar两个jar包拷贝到tomcat目录的lib目录下,因为tomcat没有这两个jar包