文章目录
1 Servlet简介
Servlet是一种独立于平台和协议的服务器端的Java技术,可以用来生成动态的Web页面
Servlet主要用户处理客户端传来的HTTP请求,并返回一个响应。通常Servlet是指HttpServlet,用于处理HTTP请求
2 Http简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写
HTTP是一个基于TCP/IP通信协议来传递数据,建立连接要通过三次握手,断开连接要经过四次挥手
3 URL简介
URL是对互联网上得到的资源的位置和访问方法的一种简洁表示,是互联网上标准资源的地址。URL它具有全球唯一性,正确的URL应该是可以通过浏览器打开此网页的,但如果您访问外网,会提示网页无法打开,这并不能说明这个URL是错误的。只不过在国内不能访问而已。
4 Servlet的体系结构
4.1 Servlet接口:定义了五个抽象方法
4.2 GenericServlet抽象类:实现了四个方法,service未实现
4.3 HttpServlet抽象接口: 实现了service方法
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;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
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);
}
}
4.4 自定义的Servlet:继承了抽象类HttpServlet接口
5 Servlet的生命周期
加载和实例化–>初始化–>请求处理–>销毁
5.1. 加载和实例化(创建Servlet对象)
第一种情况:
当请求到达容器时,容器查找该servlet对象是否存在,如果不存在,才会创建实例。
第二种情况:
容器在启动时,或者新部署了某个应用时,会检查web.xml当中,servlet是否有 load-on-starup配置。如果有,则会创建该servlet实例。
load-on-starup参数值越小,优先级越高(最小值为0,优先级最高)。
5.2. 初始化init()
在Servlet实例化后,容器调用init()方法初始化这个对象,为了让Servlet对象在处理客户端请求之前完成一些初始化工作,例如简历数据库的连接,获取配置信息等。
5.3. 请求处理 service()
Servlet容器调用service()方法对请求进行处理。
HttpServlet的service()方法,会依据请求方式来调用doGet()或者doPost()方法进行请求处理,并且通过调用ServletResponse对象的方法设置响应信息。
5.4. 销毁 destroy()
当容器检测到Servlet实例应该从服务器中被移除的时候,当需要释放内存或容器关闭时候,容器或调用Servlet实例等destroy()方法。
当destroy()方法调用之后,容器会释放这个Servlet实例,随后会被Java等垃圾收集器所回收,如果在此需要这个Servlet处理请求,Servlet容器会创建一个新的
Servlet实例。
6 Servlet的工作流程
- 1、用户通过点击链接或者直接输入URL访问Servlet。
- 2、Web服务器接收到请求后,交给Servlet容器。
- 3、Servlet容器实例化Servlet。
- 4、调用Servlet特定方法对请求进行处理,并且产生一个响应。
- 5、响应由Servlet容器返回给Web容器。
- 6、Web容器包装这个响应,以HTTP响应的形式发送给浏览器。
7 Tomcat服务器和Servlet容器的区别
7.1 Servlet容器
Servlet容器也叫做Servlet引擎,是Web服务器的一部分,用于在发送的请求和响应之上提供服务
Servlet没有main方法,不能独立运行,它必须被部署到Servlet容器中,由容器来实例化和调用 Servlet的方法(如doGet()和doPost()),Servlet容器在Servlet的生命周期内包容和管理Servlet
7.2 Tomcat服务器接受客户请求并做出响应的过程如下:
- 1)客户端(通常都是浏览器)访问Web服务器,发送HTTP请求。
- 2)Web服务器接收到请求后,传递给Servlet容器。
- 3)Servlet容器加载Servlet,产生Servlet实例后,向其传递表示请求和响应的对象。
- 4)Servlet实例使用请求对象得到客户端的请求信息,然后进行相应的处理。
- 5)Servlet实例将处理结果通过响应对象发送回客户端,容器负责确保响应正确送出,同时将控制返回给Web服务器。
8 案例一:Servlet入门案例
- 编写代码:Servlet1
package com.tedu;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 案例一:Servlet入门
*
* Servlet程序的实现的三种方式:
* implements Servlet,
* extends GenericServlet
* extends HttpServlet
*/
@WebServlet("/test/servlet1")
public class Servlet1 extends HttpServlet {
//doPost()用来处理那些 post的请求
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost");
}
//doGet()用来处理那些 get的请求
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
System.out.println("doGet");
}
}
- 编写页面:s1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试前后端的交互</title>
</head>
<a href="http://localhost:8080/test/servlet1">我是第一个servlet的案例</a>
<body>
</body>
</html>
- 运行访问
9 案例二:Servlet多数会主动调用doGet()方法
- 编写代码:Servlet2—只重写doGet()方法
package com.tedu;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 案例二:Servlet多数会主动调用doGet()
*
*/
@WebServlet("/add/servlet2")
public class Servlet2 extends HttpServlet {
//大多数的请求会以get方式来访问,Servlet会主动调用doGet()
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet方法被触发");
}
}
- 运行代码浏览器访问
- 访问路径:http://localhost:8080/add/servlet2
10 案例三:Servlet生命周期
- 编写代码:Servlet4
package com.tedu;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Servlet的生命周期
*/
@WebServlet("/test/Servlet4")
public class Servlet4 extends HttpServlet {
//只执行1次,而且是在这个Servlet程序第一次被访问时执行的
public void init() throws ServletException {
System.out.println("init()开始初始化...");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) {
//获取请求方式
String method = req.getMethod();
System.out.println("service()开始服务..." + method);
}
//只执行1次,而且是在Tomcat服务器正常关闭时执行的(Tomcat现在已经被springboot整合了,啥时候真正关闭我们控制不了)
public void destroy() {
System.out.println("destroy()开始销毁...");
}
}
- 编写页面:s4.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试 前后端交互</title>
</head>
<body>
<!-- 测试 get/post 提交数据时, 不同的处理方式 -->
<!-- 会以get方式提交这次请求 -->
<a href="http://localhost:8080/test/Servlet4">点我,访问Servlet程序</a>
<!-- 会以post方式提交这次请求 -->
<form method="post" action="http://localhost:8080/test/Servlet4">
用户名:<input type="text" placeholder="用户名.." name="user"/>
<br />
密码: <input type="password" placeholder="密码.." name="pwd"/>
<br />
<button type="submit">提交</button>
</form>
</body>
</html>
- 运行访问,查看结果
11 案例四:request对象的API
- 编写代码:Servlet5:
package com.tedu;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
/**
* request的API
*/
@WebServlet("/insertUser/userServlet5")
public class Servlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("恭喜您,请求成功~~");
// Servlet解析请求参数HttpServletRequest
//1.getParameter()--根据参数名获取参数值
String s = request.getParameter("user ");
String p = request.getParameter("pwd");
System.out.println(s+p);
//2.getParameterValues()--根据参数名获取参数值,可以获取多个值,存入数组
String[] datas = request.getParameterValues("like");
System.out.println( Arrays.toString(datas) );//[足球, 篮球]
//3.HttpServletRequest的其他API
System.out.println( request.getCharacterEncoding() );//获取请求使用的字符集UTF-8
System.out.println( request.getMethod() );//获取请求方式GET
System.out.println( request.getContextPath() );//获取项目名称(被缺省)
System.out.println( request.getRequestURI() );//要访问的资源路径:/add/user/userServlet5
System.out.println( request.getRequestURL() );//包含着:http://localhost:8080/add/user/userServlet5
System.out.println( request.getRemotePort() );//发起请求时的端口号
System.out.println( request.getQueryString() );//获取请求时携带的参数
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 编写页面:s5.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试获取数据</title>
</head>
<body>
<form method="get" action="http://localhost:8080/insertUser/userServlet5?user=jack&pwd=123">
用户名:<input type="text" placeholder="用户名.." name="user"/>
<br />
密码: <input type="password" placeholder="密码.." name="pwd"/>
<br />
爱好:
<input type="checkbox" name="like" value="汽车" />汽车<br />
<input type="checkbox" name="like" value="科技" />科技<br />
<input type="checkbox" name="like" value="房产" />房产<br />
<input type="checkbox" name="like" value="旅游" />旅游<br />
<button type="submit">提交</button>
</form>
</body>
</html>
- 运行页面访问:
12 案例五:模拟Servlet解析获取http–GET请求中的参数的过程
- 编写代码:TestServlet
package com.tedu;
/**
* 模拟Servlet解析获取http--GET请求中的参数的过程
*/
public class TestServlet {
public static void main(String[] args) {
String url = "http://localhost:8080/add/user/userServlet5?user=jack&pwd=123";
//1,按照?切割字符串,得到两个字符串,并存入数组中
String[] strs = url.split("\\?");
//2,重点解析数组中 第二部分的字符串
String data = strs[1]; //user=jack&pwd=123
//3,按照&切割字符串,又得到数组
String[] datas = data.split("&");[user=jack,pwd=123]
//4,遍历数组,获取每个数据 user=jack pwd=123
for (String s:datas){
String[] s1 = s.split("=");
// 5,按照=切割,又又得到数组[user,jack],[pwd,123]只要第二个元素jack,123
String input = s1[1];
System.out.println(input);
}
}
}
- 运行查看结果
13 案例六:Servlet组合JDBC完成入库操作
- 编写代码:Servlet6
package com.tedu.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
@WebServlet("/addUser/Servlet6")
public class Servlet6 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
System.out.println("恭喜您,成功的提交了用户的数据!");
//TODO 解析请求参数
String user = request.getParameter("user");
String pwd = request.getParameter("pwd");
String age = request.getParameter("age");
System.out.println(user + pwd + age);
//TODO jdbc入库
try {
//1,导入jar包(在pom.xml里添加jar包的坐标依赖)
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql:///user_db?characterEncoding=utf8";
Connection c = DriverManager.getConnection(url, "root", "root");
//获取传输器
String sql = "insert into user_tab values(null,?,?,?)";//sql骨架
PreparedStatement ps = c.prepareStatement(sql);
ps.setObject(1, user);
ps.setObject(2, pwd);
ps.setObject(3, age);
//执行SQL
ps.executeUpdate();//执行增删改的SQL
//释放资源
ps.close();
c.close();
System.out.println("恭喜您,用户信息已经入库成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doGet (HttpServletRequest request, HttpServletResponse response){
System.out.println("恭喜您,成功的提交了部门的数据!");
//TODO 解析请求参数(部门编号,名称,地址)
String deptno = request.getParameter("dept_no");
String deptname = request.getParameter("dept_name");
String deptloc = request.getParameter("dept_address");
//TODO jdbc入库
try {
//1,导入jar包(在pom.xml里添加jar包的坐标依赖)
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql:///user_db?characterEncoding=utf8";
Connection c = DriverManager.getConnection(url, "root", "root");
//获取传输器
String sql = "insert into dept values(?,?,?)";//sql骨架
PreparedStatement ps = c.prepareStatement(sql);
ps.setObject(1, deptno);
ps.setObject(2, deptname);
ps.setObject(3, deptloc);
//执行SQL
ps.executeUpdate();
//释放资源
ps.close();
c.close();
System.out.println("恭喜您,部门信息已经入库成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 编写页面:s6.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试 Servlet解析请求参数</title>
</head>
<body>
<h1>1.以get方式提交的数据</h1>
<form action="http://localhost:8887/addUser/Servlet6">
部门编号:<input type="text" name="dept_no" placeholder="在这里输入部门编号.."/> <br />
部门名称:<input type="text" name="dept_name" placeholder="在这里输入部门名称.."/> <br />
部门地址:<input type="text" name="dept_address" placeholder="在这里输入部门地址.."/> <br />
<button type="submit">提交</button>
<button type="reset">取消</button>
</form>
<h1>2.以post方式提交的数据</h1>
<form method="post" action="http://localhost:8887/addUser/Servlet6">
账号:<input type="text" name="user" placeholder="在这里输入用户名.."/> <br />
密码:<input type="password" name="pwd" placeholder="在这里输入密码.."/> <br />
年龄:<input type="number" name="age" placeholder="在这里输入年龄.."/> <br />
<button type="submit">提交</button>
<button type="reset">取消</button>
</form>
</body>
</html>
-
运行页面
-
查看结果
14 案例七:response对象响应数据
- 编写代码:Servlet7
package com.tedu.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* response响应数据
*/
@WebServlet("/getUser/Servlet7")
public class Servlet7 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//TODO 解析请求参数
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
//响应时使用的默认的字符集iso-8859-1,为了防止响应时的中文乱码问题,加以下代码
response.setContentType("text/html;charset=utf8");
//响应解析到的数据
PrintWriter out = response.getWriter();
out.write(name);//提供了一个换行写出的功能
out.write(pwd);
}
}
- 编写页面:s7.html
```<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>response响应</title>
</head>
<body>
<form action="http://localhost:8887/getUser/Servlet7">
用户名:<input type="text" name="name" placeholder="请输入用户名"/><br/>
密码:<input type="password" name = "pwd" placeholder="请输入密码" /><br/>
提交:<input type="submit" />
</form>
</body>
</html>
- 运行访问
15 案例八:请求转发
- 编写代码ServletA和ServletB
package com.tedu.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/testA")
public class ServletA extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletA...doGet()被触发!");
//请求转发: 实现 访问A时,A背后调用B 的效果
//特点: 地址栏不变 + 同一个request对象(在A里存,在B里取)
request.setAttribute("name","jack");
//参数是 目标资源的访问规则.目标资源必须是在同一个项目里才能请求转发
request.getRequestDispatcher("/testB").forward(request,response);
}
}
package com.tedu.request;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/testB")
public class ServletB extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletB...doGet()被触发!");
//获取A中存好的数据
Object o = request.getAttribute("name");
System.out.println(o);//jack
}
}
- 访问ServletA:http://localhost:8887/testA
16 案例九:重定向
- 编写代码:ServletC
package com.tedu.response;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* response重定向
*/
@WebServlet("/redirect/servletC")
public class ServletC extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//TODO 解析请求参数
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
System.out.println(name+pwd);
//响应时使用的默认的字符集iso-8859-1,为了防止响应时的中文乱码问题,加以下代码
response.setContentType("text/html;charset=utf8");
//重定向数据
//response.sendRedirect("/testA");
response.sendRedirect("http://www.baidu.com");
}
}
- 运行访问:http://localhost:8887/redirect/servletC
17 转发和重定向的区别
-
1.从地址栏显示来说
forward是服务器请求资源,服务直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的URL。 -
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据。
redirect:不能共享数据。 -
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块。
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等。 -
4.从效率来说
forward:高
redirect:低