Servlet
1、Servlet概述
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
2、Servlet的语法格式
第一步:创建包(com.hang.servlet.demo)
第二步:创建类(com.hang.servlet.demo.MyServlet),并且需要实现Servlet接口中的所有方法
package com.hang.servlet.demo;
import javax.servlet.*;
import java.io.IOException;
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("MyServlet init ...");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("MyServlet service ...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("MyServlet destroy ...");
}
}
方法介绍:
- init:Servlet初始化时调用的方法
- getServletConfig:获取当前Servlet的配置信息
- service:调用Servlet真正去处理逻辑的方法
- getServletInfo:它提供有关Servlet的信息,如作者、版本、版权
- destroy:Servlet销毁时调用的方法
配置映射(web.xml中新增以下代码)
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.hang.servlet.demo.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
配置介绍:
servlet标签用于配置Servlet的基本信息
- servlet-class:代表当前Servlet的具体类路径,注意最后不包含.java
- servlet-name:代表当前Servlet的别名,可以和原Servlet名称一样,也可以不一样,一般我们就一样就行了
servlet-mapping标签用于配置请求路径与具体处理Servlet的对应关系
- url-pattern:这里写你要匹配的地址路径
- servlet-name:如果匹配到请求,该交给哪一个Servlet处理,这里的servlet-name其实就是一个Servlet的别名
第四步:启动Tomcat
第五步:正常关闭Tomcat服务器,我们会看到调用销毁方法
3、Servlet执行过程
4、Servlet生命周期
Servlet运行在Servlet容器中,其生命周期由容器来管理。
Servlet的生命周期通过javax.servlet.Servlet接口中的init()、service()和destroy()方法来表示。
Servlet的生命周期包含了下面4个阶段:
- 类加载和实例化
- 初始化:init()
- 请求处理:service()
- 销毁:destroy()
5、servlet的继承体系
其实我们不难发现,现有的Servlet它的方法比较多,而且大多需要我们自己来实现,那有没有一种它的实现子类,把大部分方法都是实现了,而我们只要关注请求处理就行了,那答案肯定是有的,这个类就是HttpServlet,我们只要继承这个类重写GET、POST方法就能实现一个简单的Servlet请求处理,Servlet的继承体系如下图:
既然我们知道HttpServlet这个类了,我们就要使用一下:
第一步:创建类(com.hang.servlet.demo.MyHttpServlet),并且需要继承HttpServlet实现doPost、doGet方法。
package com.hang.servlet.demo;
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 MyHttpServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doPost method invoke ...");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doGet method invoke ...");
}
}
第二步:配置映射(在web.xml文件中新增以下代码)
<servlet>
<servlet-name>MyHttpServlet</servlet-name>
<servlet-class>com.hang.servlet.demo.MyHttpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyHttpServlet</servlet-name>
<url-pattern>/MyHttpServlet</url-pattern>
</servlet-mapping>
第三步:重启Tomcat
我们注意url-pattern它可以有多种拦截形式:
- 全路径匹配:
/a
- 前半段匹配:
/a/b/c/*
- 扩展名匹配:
*.action
6、ServletContext
每个web工程都只有一个ServletContext对象,也就是不管在哪个Servlet里面,获取到的这个类的对象都是同一个,它用来获取Servlet的上下文,在服务器启动的时候,会为托管的每一个web应用程序,创建一个ServletContext对象,当从服务器移除托管或者是关闭服务器时,ServletContext将会被销毁。它主要有以下几方面作用:
- 获取全局配置参数
- 获取web工程中的资源
- 在servlet间共享数据域对象
6.1 ServletContext
ServletContext官方叫Servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。
作用
- 是一个域对象
- 可以读取全局配置参数
- 可以搜索当前工程目录下面的资源文件
- 可以获取当前工程名字(了解)
域对象介绍
域对象是服务器在内存上创建的存储空间,用于在不同动态资源(servlet)之间传递与共享数据。
域对象方法
凡是域对象都有如下3个方法:
setAttribute(name,value);name是String类型,value是Object类型; | 往域对象里面添加数据,添加时以key-value形式添加 |
---|---|
getAttribute(name); | 根据指定的key读取域对象里面的数据 |
removeAttribute(name); | 根据指定的key从域对象里面删除数据 |
HttpServletRequest
HttpServletRequest这个对象封装了客户端提交过来的一切数据。
第一步:修改 index.jsp
<form action="RegisterServlet" method="get">
账户:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
<input type="submit" value="注册">
</form>
第二步:创建类(RegisterServlet)
package com.hang.servlet.demo;
import javafx.print.Collation;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取客户端传递过来的头部信息
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
System.out.println(headerName + ":" + headerValue);
}
System.out.println("====================");
// 获取客户端传递过来的参数信息
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
String parameterValue = request.getParameter(parameterName);
// 如果值有多个请使用:request.getParameterValues(parameterName)
System.out.println(parameterName + ":" + parameterValue);
}
System.out.println("====================");
// 以Map集合的形式获取客户端传递过来的参数信息
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> names = parameterMap.keySet();
for (String name : names) {
String[] value = parameterMap.get(name);
System.out.println(name + ":" + Arrays.toString(value));
}
System.out.println("====================");
// 获取一些其它地址、查询等信息
StringBuffer requestURL = request.getRequestURL();
String requestURI = request.getRequestURI();
String servletPath = request.getServletPath();
String queryString = request.getQueryString();
System.out.println("requestURL:" + requestURL);
System.out.println("requestURI:" + requestURI);
System.out.println("servletPath:" + servletPath);
System.out.println("queryString:" + queryString);
}
}
第三步:在web.xml中新增映射信息
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.hang.servlet.demo.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/RegisterServlet</url-pattern>
</servlet-mapping>
第四步:重启Tomcat服务器
在表单输入数据,然后点击提交
查看IDEA的控制台信息
host:localhost:8080
connection:keep-alive
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site:same-origin
sec-fetch-mode:navigate
sec-fetch-user:?1
sec-fetch-dest:document
referer:http://localhost:8080/myJavaWebDemo_war_exploded/
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
cookie:JSESSIONID=4342FA7CB5F51C5E4A5251E485E36E38
====================
username:zhangsan
password:123456
====================
username:[zhangsan]
password:[123456]
====================
requestURL:http://localhost:8080/myJavaWebDemo_war_exploded/RegisterServlet
requestURI:/myJavaWebDemo_war_exploded/RegisterServlet
servletPath:/RegisterServlet
queryString:username=zhangsan&password=123456
如何解决请求数据中文乱码问题?
GET方法
// 先用原来的编码解码再用UTF—8重新编码。
String newUsername = new String(username.getBytes("ISO-8859-1"), "UTF-8");
POST方法
// 这行设置一定要写在getParameter之前。
request.setCharacterEncoding("UTF-8");
HttpServletResponse
HttpServletResponse这个对象负责返回数据给客户端。
第一步:创建类(DisplayServlet)
package com.hang.servlet.demo;
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 DisplayServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 注意:以下两种方式一次只能使用一种,我们就用字符流方式了,另一种自己演示
*/
// 以字符流的方式写数据
response.getWriter().write("<h1>hello response 111 ...</h1>");
// 以字节流的方式写数据
// response.getOutputStream().write("hello response 222 ...".getBytes());
}
}
第二步:在web.xml文件中新增以下映射信息
<servlet>
<servlet-name>DisplayServlet</servlet-name>
<servlet-class>com.hang.servlet.demo.DisplayServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayServlet</servlet-name>
<url-pattern>/DisplayServlet</url-pattern>
</servlet-mapping>
第三步:重启Tomcat服务器
如何解决响应数据中文乱码问题?
-
以字符流输出:response.getWriter()
-
response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Type", "text/html; charset=UTF-8"); response.getWriter().write("你好,世界!");
-
-
以字节流输出:response.getOutputStream()
-
response.setHeader("Content-Type", "text/html;charset=UTF-8"); response.getOutputStream().write("你好,世界!".getBytes("UTF-8"));
-
重定向和请求转发
重定向
// 第一种:使用示例
response.setStatus(302);
response.setHeader("Location", "login_success.html");*/
// 第二种:使用示例
response.sendRedirect("login_success.html");
1. 地址上显示的是最后的那个资源的路径地址。
2. 请求次数最少有两次,服务器在第一次请求后,会返回302以及一个地址,浏览器在根据这个地址,执行第二次访问。
3. 可以跳转到任意路径,不是自己的工程也可以跳。
4. 效率稍微低一点,执行两次请求。
5. 后续的请求,没法使用上一次的request存储的数据,或者没法使用上一次的request对象,因为这是两次不同的请求。
请求转发
// 使用示例:
request.getRequestDispatcher("login_success.html").forward(request, response);
1. 地址上显示的是请求servlet的地址,返回200ok。
2. 请求次数只有一次,因为是服务器内部帮客户端执行了后续的工作。
3. 只能跳转自己项目的资源路径。
4. 效率上稍微高一点,因为只执行一次请求。
5. 可以使用上一次的request对象。
Cookie
Cookie其实是一份小数据,它是服务器给客户端并且存储在客户端上的一份小数据。
Cookie[] cookies = req.getCookies(); //获得Cookie
cookie.getName(); //获得cookie中的key
cookie.getValue(); //获得cookie中的vlaue
new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie的有效期
resp.addCookie(cookie); //响应给客户端一个cookie
- 一个Cookie只能保存一个信息;
- 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;
- Cookie大小有限制4kb;
- 300个cookie浏览器上限
- 不设置有效期,关闭浏览器,自动失效;
- 设置有效期时间为 0 ;
Session
由于Cookie会保存在客户端上,所以有安全隐患问题。还有一个问题,Cookie的大小与个数有限制,为了解决这个问题,于是就有了Session,Session是基于Cookie的一种会话机制。Cookie是服务器返回一小份数据给客户端,并且存放在客户端上。Session是数据存放在服务器端。
常见用法:
// 获取Session对象
HttpSession session = request.getSession();
// 获取SessionID
String id = session.getId();
//存值
session.setAttribute(name, value);
//取值
session.getAttribute(name);
//删值
session.removeAttribute(name);
生命周期:
- 创建:如果有在servlet里面调用了 request.getSession()
- 销毁:关闭服务器或者session会话时间过期。默认有效期: 30分钟。
限制,为了解决这个问题,于是就有了Session,Session是基于Cookie的一种会话机制。Cookie是服务器返回一小份数据给客户端,并且存放在客户端上。Session是数据存放在服务器端。
常见用法:
// 获取Session对象
HttpSession session = request.getSession();
// 获取SessionID
String id = session.getId();
//存值
session.setAttribute(name, value);
//取值
session.getAttribute(name);
//删值
session.removeAttribute(name);
生命周期:
- 创建:如果有在servlet里面调用了 request.getSession()
- 销毁:关闭服务器或者session会话时间过期。默认有效期: 30分钟。