Servlet基础知识

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:低

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值