Servlet技术
一.Servlet技术
Servlet是javaEE接口之一、Servlet是运行在服务器上的一个java小程序,servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求,它可以接受客户端发送过来的请求,并响应数据给客户端。
 1.Servlet是javaweb的三大组件之一、三大组件有Servlet程序、Filter过滤器、Listener监听器
二.实现Servlet程序
- 编写一个类去实现Servlet接口
- 实现service方法,处理请求,并响应数据
- 到web.xml里面配置Servlet程序的访问地址
 其中service最为重要
public class servlet1 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    /*
     * service方法是专门用来处理请求和响应的
     * */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service被访问了");
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
    }
web.xml配置为的是在Tomcat服务器进行访问到Servlet程序
    <!--servlet标签给Tomcate配置servlet程序-->
<servlet>
    <!--servlet-name标签Servlet程序起一个别名(使用类名比较好)-->
    <servlet-name>servlet1</servlet-name>
    <!--servlet-class是servlet程序起的全类名-->
    <servlet-class>com.content.Dome.servlet1</servlet-class>
</servlet>
    <!--servlet-mapping标签给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--servlet-name标签的作用是告诉服务器、我当前配置的地址给那个Servlet程序使用-->
        <servlet-name>servlet1</servlet-name>
        <!--url-pattern标签配置访问地址
        / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程名
        /servlet 表示http://ip:port/工程名/servlet
        -->
        <url-pattern>/servlet</url-pattern>
    </servlet-mapping>
:Servlet是如何通过Tomcat进行访问的呢!
| 客户端(游览器) | 服务器 硬件 电脑 IP地址 | |
|---|---|---|
| http://localhost:8080/servlet1/servlet | ||
| localhost是服务器ip | 通过IP地址定位服务器 | |
| :8080是服务器端口号 | 端口号定位Tomcat | |
| /servlet1 是工程路径 | 通过工程路径确定访问那个工程 | |
| /servlet 资源路径 | 资源路径执行Java中servlet的service的代码段 | 
三.Servlet声明周期
- 执行servlet构造器 —>项目执行会被创建
- 执行init初始化方法 —>执行时就进行初始化
- 执行service方法 —>项目存在时会一直执行service方法
- 执行destroy销毁方法 -->游览器停止时执行销毁方法
public class ServletTest implements Servlet {
    public ServletTest() {
        System.out.println(" 1 构造器方法");
    }
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2 初始化方法 init");
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3 服务方法 service");
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
        System.out.println("4  销毁方法 destroy");
    }
}

四.GET和POST请求的分发处理
1.在实现Serlvet类中的service方法获取表单的请求方式
 public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
        //获取GET和POST方法,需要先进性类型转换(因为里面有getMethod方法)
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        //获取请求方式
        String method = httpServletRequest.getMethod();
        System.out.println("method");
    }
2.大多数的开发为继承HttpServlet去获取Get和Post方法
public class ServletTest 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方法");
    }
一般开发中为继承HttpServlet方法
 
五.使用IDEA创建Servlet程序

配置Servlet信息、一般为类名大写,配置xml为类名的小写
 
六.Servlet继承体系
| javax.servlet Interface Servlet | Servlet接口,只是负责定义Servlet程序的访问规范 | 
|---|---|
| javax.servlet Class GenericServlet | GenericServlet 类实现lServlet接口,做了很多空实现,并且持有一个ServletConfig类的引用。并对ServletConfig的使用做一些方法 | 
| javax.servlet.http Class HttpServlet | HttpServlet抽取类实现了service()方法,并实现了请求的分发处理 | 
| 自定义的Servlet程序 —>根据需要重写doGet或doPost方法 | String method = req.getMethod(); | 
七.ServletConfig类
ServletConfig类为Servlet程序的配置信息类
 servlet程序和ServletConfig对象都说由Tomcat负责创建,我们负责使用,Servlet程序默认是第一次访问的时候创建,Servlet程序创建时,就创建一个对应的ServletConfig对象。
 1.ServletConfig类的三大应用
        1).可以获取Servlet程序的别名Servlet-name
        2).获取初始化参数init-param
        3).获取ServletContext对象
public class ServletTest implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
//        1).可以获取Servlet程序的别名Servlet-name
        System.out.println("ServletTest 的别名为:" + servletConfig.getServletName());
//        2).获取初始化参数init-param
        System.out.println("初始化参数username为:"+ servletConfig.getInitParameter("username"));
        System.out.println("初始化参数password为:"+ servletConfig.getInitParameter("password"));
        System.out.println("初始化参数url为:"+ servletConfig.getInitParameter("url"));
        System.out.println("初始化参数Driver为:"+ servletConfig.getInitParameter("Driver"));
//        3).获取ServletContext对象
        System.out.println(servletConfig.getServletContext());
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
    }
}
这是在xml里面配置的init的参数它只可以得到自己的Servlet部署的信息,不能获取别的Servlet的信息
<servlet>
        <servlet-name>ServletTest</servlet-name>
        <servlet-class>com.Demo.Servlet.ServletTest</servlet-class>
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value></param-value>
        </init-param>
        <init-param>
            <param-name>Driver</param-name>
            <param-value>com.mysql.jdbc.Driver</param-value>
        </init-param>
    </servlet

八.ServletContext类
1.ServletContext是一个接口,他表示Servlet上下文
 2.一个web工程,只有一个ServletContext对象实例
 3.ServletContext对象是一个域对象(域对象是可以象Map那样存取数据的对象,叫域对象,域指的是存取数据的操作范围、Context的范围是整个web工程)
 4.ServletContext在web工程部署启动的时候创建,在web工程停止的时候销毁
| 存数据 | 取数据 | 删除数据 | |
|---|---|---|---|
| Map | put() | get() | remove() | 
| 域对象 | setAttribute() | getAttribute() | removeAttribute() | 
4.ServletContext类的四个作用
 1).获取web.xml中配置的上下文参数
        1.获取web.xml中配置的上下文参数
        2.获取当前的工程路径
        3.获取工程部署后服务器硬盘的绝对路径
        4.象Map一样存取数据
public class ContextServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//        1.获取web.xml中配置的上下文参数context-param
        ServletContext context = getServletConfig().getServletContext();
        String username = context.getInitParameter("username");
        System.out.println("context-param参数username的值为:" + username);
        System.out.println("context-param参数password的值为:" + context.getInitParameter("password"));
//        2.获取当前的工程路径
        System.out.println("当前路径:" + context.getContextPath());
//        3.获取工程部署后服务器硬盘的绝对路径
        //斜杠被服务器解析地址为:http://ip:port/工程名   映射到IDEAdaima的web目录
        System.out.println("工程部署的路径是:" + context.getRealPath("/"));
//        4.象Map一样存取数据
        ServletContext context1 = getServletContext();  //先获取servletContext对象
        context1.setAttribute("key1","value1");
        context1.setAttribute("key2","value2");
        context1.setAttribute("key3","value3");
        context1.setAttribute("key4","value4");
        System.out.println("Context1中key1的数据" + context1.getAttribute("key1"));
        System.out.println("Context1中key2的数据" + context1.getAttribute("key2"));
        System.out.println("Context1中key3的数据" + context1.getAttribute("key3"));
        System.out.println("Context1中key4的数据" + context1.getAttribute("key4"));
    }
}

九.Http协议
1.Http协议就是指客户端和服务器之间通信时,发送的数据,需要遵守的规则、Http协议中的数据又叫报文
 2.请求的Http协议格式
- 客户端给服务器发送数据叫请求
- 服务器给客户端回传数据叫响应
- 请求又分为GET请求、和POST请求
GET请求
-  请求行 
 1.请求的方式 GET
 2.请求的资源路径[+?+请求参数]
 3.请求协议的版本号 HTTP/1.1
-  请求头 
 1.key:value 组成 不同的键值对,表示不同的含义
| Accept | 告诉服务器,客户端可以接受的数据类型 | 
|---|---|
| Accept-Language | 考试服务器客户端可以接收的语言类型 zh-CN–>中文中国 en-US -->英文美国 | 
| User-Agent | 浏览器的信息 | 
| Accept-Encoding | 告诉服务器,客户端可以接收的数据编码格式 | 
| Host | 表示请求的服务器ip和端口哈 | 
| Connection | 告诉服务器请求连接如何处理 | 
| Keep-Alive | 告诉服务器回传数据不要马上关闭,保存一小时的连接 | 
| Closed | 马上关闭 | 
POST请求
-  请求行 
 1.请求的方式 POST
 2.请求的资源路径[+?+请求参数]
 3.请求协议的版本号 HTTP/1.1
-  请求头 
 1.key:value 组成 不同的键值对,表示不同的含义
-  请求体 —>就是发送给服务器的数据 
| Accept | 告诉服务器,客户端可以接受的数据类型 | 
|---|---|
| Accept-Language | 考试服务器客户端可以接收的语言类型 zh-CN–>中文中国 en-US -->英文美国 | 
| Referer | 表示请求发起时,浏览器地址栏中的地址从(那里来) | 
| User-Agent | 浏览器的信息 | 
| Content-Type | 表示发送的数据类型 | 
| application/x-www-form-urlencoded | 表示提交的数据格式是:name=value,然后对其进行url编码 | 
| url编码 | 是八非英文内容转换为:%xx%xx | 
| multipart/form-date | 表示以多段的新式提交给数据给服务器(以流的形式提交,用于上传) | 
| Content-Length | 表示发送的数据的长度 | 
| Cache-Control | 表示如何控制缓存 No-cache不缓存 | 
常用请求头
- Accept : 表示客户端可以接收的数据类型
- Accpet-Language: 表示客户端可以接收的语言类型
- User-Agent : 表示客户端浏览器的信息
- Host : 表示请求时的服务器ip和端口号
那些是GET请求、那些是POST请求
-  GET请求 
 1.form标签 method=get
 2. a 标签
 3. link 标签引入 css
 4. Script 标签引入 js 文件
 5. img 标签引入图片
 6. iframe 标签引入 html 页面
 7. 在浏览器地址栏中输入地址后回车
-  POST请求 
 1.form标签 method=Post
-  常用的响应码说明 
| 200 | 表示请求成功 | 
|---|---|
| 302 | 表示请求重定向 | 
| 404 | 表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误) | 
| 500 | 表示服务器已经收到请求,但服务器内部错误(代码错误) | 
MIME类型说明
- MIME是HTTP协议中数据类型,多功能Internet邮件扩充服务。MIME格式是”大类型/小类型“,并与某一种扩展名相对应
| 文本 | MIME类型 | 
|---|---|
| 超文本 | .html txt/html | 
| 普通文本 | .txt text/plain | 
| JPEG图形 | .jpeg image/jpeg | 
| AVI文件 | .avi video/mpeg | 
十.HttpServletRequest类
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的Http协议信息解析好封装daoRequest对象中。然后传递到Service方法(doGET 和doPost)中给我们使用,我们可以通过HttpServletRequest对象,获得到所有请求的信息
 HttpServletRequest类的常用方法
| getRequestURI() | 获取请求的资源路径 | 
|---|---|
| getRequestURL() | 获取请求的统一资源定位符(绝对路径) | 
| getRemoteHost() | 获取客户端的ip地址 | 
| getHeader() | 获取请求头 | 
| getParameter() | 获取请求的参数 | 
| getParameterValues() | 获取请求的参数(多个值的时候使用) | 
| getMethod() | 获取请求的方式GET或POST | 
| setAttribute(key,value) | 设置域数据 | 
| getAttribute(key) | 获取域数据 | 
| getRequestDispatcher() | 获取请求转发对象 | 
public class ServletTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("URI-->" + req.getRequestURI());
        System.out.println("URL-->" + req.getRequestURL());
        System.out.println("客户端地址ip"+ req.getRemoteHost());
        System.out.println("请求头User - Agent" + req.getHeader("User-Agemt"));
        System.out.println("请求的方式"+ req.getMethod());
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

十一如何获取参数代码演示
public class ServletTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTF-8");
    System.out.println("这是Get方法");
       //获取请求的参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobby");
        System.out.println("用户名 :" + username);
        System.out.println("密码 :" + password);
        System.out.println("兴趣爱好 :" + Arrays.asList(hobby)); //要转化为数据Arrays进行输出因为是多个数据,单个数据直接输出就可
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      req.setCharacterEncoding("UTF-8");
    System.out.println("这是POST方法");
       //获取请求的参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobby");
        System.out.println("用户名 :" + username);
        System.out.println("密码 :" + password);
        System.out.println("兴趣爱好 :" + Arrays.asList(hobby)); //要转化为数据Arrays进行输出因为是多个数据,单个数据直接输出就可
    }
}
十二.测试表单
<%--
  Created by IntelliJ IDEA.
  User: 程序员小徐同学
  Date: 2022-01-11
  Time: 14:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>程序员小徐同学</title>
  </head>
  <body>
  <h3>开始了新的测试</h3>
  <form action="http://localhost:8888/day2/servlet" method="get">
    用户名:<input type="text" name="username"><br>
    密码 : <input type="password" name="password"> <br>
    兴趣爱好 : <input type="checkbox" name="hobby" value="java"> java<br>
    <input type="checkbox" name="hobby" value="c++">c++<br>
    <input type="checkbox" name="hobby" value="php">php<br>
    <input type="submit" value="提交">
  </form>
  </body>
</html>


 在使用中可能会出现中文乱码问题,这就需要在doGet和doPost方法的第一行加上以下语句
 req.serCharacterEncoding(“UTF-8”);
十三.请求转发
客户端(浏览器)通过工程进行访问服务器Tomcat,先访问Servlet1程序,进行Servlet1的事件处理,Servlet1处理完后,由Servlet1指向Servlet2程序,执行Servlet2的事件,
从Servlet1到Servlet2就是请求转发
 请求转发特点
- 浏览器地址栏没有发生变化
- 是一次请求
- 可以共享Request域中的数据
- 可以转发到WEB-INF目录下(WEB-INF是禁止浏览器访问的 、但请求转发可以)
下面需要在web.xml配置好路径
public class ServletTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //获取请求的参数
        req.setCharacterEncoding("UTF-8");
        System.out.println("在Servlet1中查看参数");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("用户名 :" + username);
        System.out.println("密码 :" + password);
        req.setAttribute("key1","Servlet一结束");
        //开始请求转发
        /*请求转发必须要以斜杠打头  ,斜杠表示地址为:http://ip:port/工程名, 映射到IDEA代码的web目录
        * */
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
        //走向servlet2
        requestDispatcher.forward(req,resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
@WebServlet(name = "ServletTest2")
public class ServletTest2 extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的参数
        req.setCharacterEncoding("UTF-8");
        System.out.println("在Servlet2中查看参数");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("用户名 :" + username);
        System.out.println("密码 :" + password);
        //查看Servlet1是否有盖章
        Object key1 = req.getAttribute("key1");
        System.out.println("Servlet1 是否有值"+ key1);
        //处理自己的事件
        System.out.println("Servlet2 处理自己的事件");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

 Base标签的作用
base标签可以设置当前页面中所有相对路径工作时,参照那个路径来进行跳转
下面是一个实例
 当我们点击a标签进行跳转的时候,浏览器的地址栏中的地址是http://localhost:8080/day2/test/Dome/t1.html
跳转回去的a标签的路径是: …/…/index.jsp
 所有相对路径在工作时候都会参照当前游览器地址栏中的地址来进行跳转
 那么参照后得到的地址是:http://localhost:8080/day2/index.jsp
 正确的跳转地址
到我们用请求转发;来进行跳转的时候,浏览器地址栏中的地址是http://localhost:8080/day2/forward
 跳转回去的a标签路径是: …/…/index.jsp
 所有相对路径在工作时候都会参照当前浏览器地址栏中的地址来跳转
 那这参照来得到的地址是:http://localhost:8080/index.jsp
 错误的路径
<%--
  Created by IntelliJ IDEA.
  User: 程序员小徐同学
  Date: 2022-01-11
  Time: 14:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>首页</title>
  </head>
  <body>
  <h3>开始了新的测试</h3>
<a href="test/d/t1.html">这是test下Dome下t1.html页面</a>
<a href="http://localhost:8888/day2/context">这是请求转发t1.html页面</a>
  </body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>t1.html</title>
    <!--base标签设置页面相对路径工作时参照的地址-->
    <base href="http://localhost:8888/day2/test/d/t1.html">
</head>
<body>
<h3>这是web下test下Dome下的t1.html页面</h3>
<a href="../../index.jsp">跳回首页</a>
</body>
</html>
public class ContextServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("经过请求转发Forward程序");
        request.getRequestDispatcher("/test/d/t1.html").forward(request,response);
    }
}
三者的路径关系 在javaweb中,路径分为相对路径和绝对路径两种:
 相对路径
| . | 点表示当前路径 | 
|---|---|
| . . | 表示上一级路径 | 
绝对路径为: http://ip:port/工程路径/资源路径

十四.HttpServletResponse类
httpServletResponse类和HttpServletRequest类一样,每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用。HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,
 我们如果需要设置返回给客户端的消息,都可以通过HttpServletResponse对象来进行设置
 1.两个输出流的说明
 两个流同时只能使用一个,使用字节流就不能再使用字符流,反之亦然,否则就会报错
| 字节流 | getOutputStream() — 常用于下载(传递二进制数据) | 
|---|---|
| 字符流 | getWriter(); – 常用于回传字符串(常用) | 
要求:往客户端回传一个字符串
 响应在浏览器出现乱码,我们需要先设置编码方式一般将服务器和客户端都使用UTF-8编码此方法一定要在获取流对象之前调用才有效response.setContentType(“text/html;character=UTF-8”);
public class ContextServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // System.out.println(response.getCharacterEncoding());//默认是ISO-8859-1编码格式
        //设置服务器字符为UTF-8
     // response.setCharacterEncoding("UTF-8");
      //通过响应头设置浏览器也使用UTF-8字符集
 //       response.setHeader("Content-Type","text/html;character=UTF-8");
        //下面我们使用一种方便的改字符的方式、它会使服务器和客户端都使用UTF-8字符集,还设置了响应头
        // 此方法一定要在获取流对象之前调用才有效
        response.setContentType("text/html;character=UTF-8");
       //要求:往客户端回传一个字符串
        PrintWriter writer = response.getWriter();
        writer.write("response 的中文响应");
    }
}
十五.请求重定向
指的是客户端给服务器发请求,然后服务器告诉客户端说,我给你一些地址,你去新地址访问,叫请求重定向(前地址可能被废弃)
 请求重定向特点
- 浏览器地址栏会改变
- 两次请求
- 不共享Req域的数据
- 不能访问WEB-INF下的资源
- 可以访问工程外的资源

 下面为第一种简单的
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Response1 现在状态");
        //设置响应状态码302,表示重定向
        resp.setStatus(302);
        //设置响应头,说明新的地址
        resp.setHeader("Location","http://localhost:8888/day2/servlet2");
    }
第二种更简单的
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Response1 现在状态");
        //设置响应状态码302,表示重定向
        //resp.setStatus(302);
        //设置响应头,说明新的地址
       // resp.setHeader("Location","http://localhost:8888/day2/servlet2");
        resp.sendRedirect("http://localhost:8888/day2/servlet2");
    }
十六.还有什么问题可以留言给我,会尽心解答的,觉得文章不错的话点个赞把











