前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Servlet 学习笔记

Servlet 学习笔记

作者头像
bgZyy
发布2018-05-16 14:40:40
6310
发布2018-05-16 14:40:40
举报
文章被收录于专栏:Java 技术分享Java 技术分享

Servlet 运行在服务器上的 java 类;

Servlet 容器为 javaWeb 应用提供运行时环境,负责管理 servlet 和 jsp 生命周期,以及管理他们的共享数据。

现在我们知道了 Servlet 是运行在服务器上的 Java 类,那么什么是服务器?我们平常最常用的服务器都有哪些呢?

  服务器是一种被动程序:只有当Internet上运行其他计算机中的浏览器发出的请求时,服务器才会响应;

  最常用的Web服务器是ApacheMicrosoftInternet信息服务器。

对于现在大多数 Javaweb 学习者大多数使用的是 Apache 服务器,所以我们今天也就从 Tomact 服务器开始。

  Tomact 服务器的安装和配置

  首先从官网上下载 Tomact 压缩包到本地,然后解压到你想要解压到的目录,会得到一个解压后的目录如下

    --bin 存放启动和关闭 Tomact 的脚本文件

    -- conf 存放 Tomact 服务器的各种配置文件

    -- lib 存放第三方依赖 jar 包

    -- logs 存放日志文件

    -- temp 存放 Tomact 运行时产生的临时文件

    -- webapp 发布 web 应用时,通常把 web 应用的目录和文件放到这个目录下

    -- work 存放 jsp 被翻译为 Servlet 后编译的 class 文件

  启动 Tomact 服务器

    点击 bin/startup.bat 启动服务器;如果你点击之后只是闪了一下那么你可以查看日志文件查看错误信息,或者在 cmd 命令行下切换到 Tomact/bin 目录下,输入 startup 将会显示错误信息,而不是闪一下,找到错误信息之后发现它需要我们配置 JAVA_HOME(jdk 安装根目录) 或 JRE_HOME(jre 安装根目录) 中任何一个环境变量。

    配置完成后再次点击便会成功启动服务器。

    启动后在浏览器地址栏输入 localhost:8080(Apache 默认的端口号为 8080),如果出现 Apache 页面便说明启动成功(Tomcat 服务器只可以启动一个,如果你去启动第二个便会提示你端口被占用的错误信息)

    我们如果每次启动服务器在命令行中的任意目录去启动而不需要在特定的目录该多方便?那么该如何实现呢?首先我们需要知道 PATH 环境变量,安装和配置 Java 时也会用到;

    PATH是路径的意思,PATH环境变量中存放的值,就是一连串的路径。不同的路径之间,用英文的分号(;)分隔开。系统执行用户命令时,若用户未给出绝对路径,则首先在当前目录下寻找相应的可执行文件、批处理文件(另外一种可以执行的文件)等。若找不到,再依次在PATH保存的这些路径中寻找相应的可执行的程序文件。

    如上面所述,我们把 bin 目录配置到系统环境变量 path 下,这样便不会出现错误信息(xxx 不是内部命令或外部命令,也不是可运行程序或批处理文件),但是会提示另一个错误,需要我们设置另外一个环境变量(CATALINA_HOME,Tomact 解压的根目录),同上我们去设置 CATALINA 环境变量。

    设置成功后我们可以试着在任意目录下去输入 startup 来开启 Tomact。这时便可以正常启动服务器,你还可以在命令行中输入 catalina,查看 catalina 命令帮助,其中 catalina run 可以在当前窗口开启服务器,而不像 startup 那样开启另外一个窗口。开启之后可以按下 Ctrl + C 关闭服务器。

  服务器介绍完毕,开始我们的正题 ---- Servlet。

  1. 新建 web 工程,并新建一个类继承 Servlet 接口并实现其所有方法

  2. 在 web 工程队的 web.xml 中映射 servlet 类,如下:

代码语言:javascript
复制
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5          version="3.1">
 6     <servlet>
 7         <!--Servlet 注册的名字-->
 8         <servlet-name>helloServlet</servlet-name>
 9         <!--Servlet 的全类名-->
10         <servlet-class>com.javaweb.firstServlet.HelloServlet</servlet-class>
11     </servlet>
12     <servlet-mapping>
13         <!--同上一致-->
14         <servlet-name>helloServlet</servlet-name>
15         <!--映射访问的具体路径,/ 表示根目录-->
16         <url-pattern>/hello</url-pattern>
17     </servlet-mapping>
18 </web-app>

   3. 我们继承 Servlet 接口的类如下,我们可以在 web 项目下的 jsp 文件中写一个超链接连接到 Servlet 的 URL,运行 web 项目执行 servlet,不断刷新页面,并在最后关闭服务器,我们可以看到控制台打印的消息,由此可知 servlet 执行顺序为(构造器-init 方法-service 方法 -----service 方法 – 关闭服务器调用 destroy 方法)

    1. 构造器(只有第一次请求 Servlet 时创建 Servlet 实例调用构造器,说明 Servlet 是单实例,所以不可以写全局变量)

    2.  init(只被调用一次,在创建好实例后立即被调用,用于初始化当前 Servlet,构造器也可以初始化,但是 init 方法传入了构造器所没有的参数,所以使用 init 初始化 Servlet)

    3. service(被调用多次,每次请求都会调用 Service 方法,被用于响应请求)

    4. destroy(只被调用一次,在当前 Servlet 所在的 WEB 应用被卸载前调用,用于释放 Servlet 所占用的资源)

代码语言:javascript
复制
 1 package com.javaweb.firstServlet;
 2 
 3 import javax.servlet.*;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.util.Enumeration;
 7 
 8 public class HelloServlet implements Servlet{
 9 
10     @Override
11     public void init(ServletConfig servletConfig) throws ServletException {
12 
13         System.out.println("init");
14     }
15 
16     @Override
17     public ServletConfig getServletConfig() {
18         System.out.println("getServletConfig");
19         return null;
20     }
21 
22     @Override
23     public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
24         System.out.println("service");
25     }
26 
27     @Override
28     public String getServletInfo() {
29         System.out.println("servletInfo");
30         return null;
31     }
32 
33     @Override
34     public void destroy() {
35         System.out.println("destroy");
36     }
37 
38     public HelloServlet() {
39         System.out.println("HelloServlet");
40     }
41 }

  4. web.xml 文件 <servlet> 节点中可以指定load-on-startup 属性,指定 servlet 被创建的时机,其值越小越先被创建,若为负数则在第一次请求时被创建,若为 0 或正数则在容器被加载的时候被创建

现在我们开始详细的讲解 servlet 类及其对象

  ServletConfig 类(封装了 Servlet 的配置信息,并且可以获取 ServletContext 对象)

  方法:   getInitParameter(String name) 获取指定参数名的初始化参数

           getInitParametersNames() 获取初始化参数组成的 Enumeration 对象

  首先我们需要会配置 servlet 初始化参数,如下 

代码语言:javascript
复制
 1 <servlet>
 2         <!--Servlet 注册的名字-->
 3         <servlet-name>helloServlet</servlet-name>
 4         <!--Servlet 的全类名-->
 5         <servlet-class>com.javaweb.firstServlet.HelloServlet</servlet-class>
 6         <!--配置初始化参数,必须在 load-on-startup 节点前面-->
 7         <init-param>
 8             <param-name>user</param-name>
 9             <param-value>root</param-value>
10         </init-param>
11         <init-param>
12             <param-name>password</param-name>
13             <param-value>zy961029</param-value>
14         </init-param>
15         <load-on-startup>1</load-on-startup>
16 </servlet>

  ServletContext 对象(可以认为是当前 WEB 应用的大管家 )

  定义了一组和 Servlet 容器通信的方法,每个应用程序都有一个 ServletContext(上下文),ServletContext 对象被称为application 对象,ServletContext 被包含在 ServletConfig 对象中,其拥有的方法和 servletConfig 一样,但获取的是当前 WEB 应用的初始化参数,当前 WEB 应用的初始化参数配置如下:

 ServletContext 对象的方法众多可以参考其官方 API。

代码语言:javascript
复制
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5          version="3.1">
 6     <context-param>
 7         <param-name>url</param-name>
 8         <param-value>jdbc:mysql:///sh_db</param-value>
 9     </context-param>
10     <context-param>
11         <param-name>driverClass</param-name>
12         <param-value>com.mysql.jdbc.Driver</param-value>
13     </context-param>
14 <web-app>

    当前 WEB 应用的初始化参数和 Servlet 初始化参数的区别:

      Servlet 初始化参数在当前 Servlet 中也就是 局部的,WEB 应用参数在 servlet 外边,相当于全局的,所有的 Servlet 可以获取

    下面的是 ServletConfig 对象和 ServletContext 对象的方法实现

代码语言:javascript
复制
 1 package com.javaweb.firstServlet;
 2 
 3 import javax.servlet.*;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.util.Enumeration;
 7 
 8 /**
 9  * Created by shkstart on 2017/11/06.
10  */
11 public class HelloServlet implements Servlet{
12 
13     @Override
14     public void init(ServletConfig servletConfig) throws ServletException {
15 //        获取当前 Servlet 的初始化参数
16         Enumeration<String> names = servletConfig.getInitParameterNames();
17 
18         while (names.hasMoreElements()) {
19             String name =  names.nextElement();
20             String value = servletConfig.getInitParameter(name);
21             System.out.println("name:" + name + "; value: " + value);
22         }
23 
24 //        获取当前 WEB 应用的初始化参数
25         ServletContext servletContext = servletConfig.getServletContext();
26         Enumeration<String> contextNames = servletContext.getInitParameterNames();
27         while (contextNames.hasMoreElements()) {
28             String contextName = contextNames.nextElement();
29             String contextValue = servletContext.getInitParameter(contextName);
30             System.out.println(contextName + "-->" + contextValue);
31         }
32 //        获取当前 WEB 应用的名称
33         String contextPath = servletContext.getContextPath();
34         System.out.println(contextPath + "+------+");
35 
36 //        获取某一个文件对应的输入流
37         InputStream inputStream2 = servletContext.getResourceAsStream("/First.jsp");
38         System.out.println(inputStream2 + "-----+-----");
39 
40 //        获取部署在服务器上的绝对路径
41         String realPath = servletContext.getRealPath("First.jsp");
42         System.out.println(realPath);
43     }
44 
45     @Override
46     public ServletConfig getServletConfig() {
47         System.out.println("getServletConfig");
48         return null;
49     }
50 
51     @Override
52     public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
53         System.out.println("service");
54     }
55 
56     @Override
57     public String getServletInfo() {
58         System.out.println("servletInfo");
59         return null;
60     }
61 
62     @Override
63     public void destroy() {
64         System.out.println("destroy");
65     }
66 
67     public HelloServlet() {
68         System.out.println("HelloServlet");
69     }
70 }

  ServletRequest 和 ServletResponse 对象

  ServletRequest 封装了请求信息,可从中获取到任何的请求信息;ServletResponse 封装了响应信息,如果想给用户什么响应,具体可以使用该接口的方法实现 ,其常用方法有

           String getParameter(String name); 获取请求的参数值,根据所传入的参数,例如输入框;

      String[] getParameterValues() 返回参数的字符串类型的数组,例如多选框;

      getWriter() 方法返回一个 PrintWirter 对象,打印到浏览器页面其他方法可以参考官方 PAI,在这里就不再啰嗦。

    上面的方法具体如下:

代码语言:javascript
复制
 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3   <head>
 4     <title>$Title$</title>
 5   </head>
 6   <body>
 8     <form action="loginServlet">
 9       UserName: <input type="text" name="userName"><br>
10       PassWord: <input type="password" name="passWord"><br>
11       Interest: <input type="checkbox" name="interest" value="TV">TV
12                 <input type="checkbox" name="interest" value="MP3">MP3
13                 <input type="checkbox" name="interest" value="SPORT">SPORT
14       <button type="submit">Submit</button>
15     </form>
16   </body>
17 </html>
代码语言:javascript
复制
 1 package com.javaweb.firstServlet;
 2 
 3 import javax.servlet.*;
 4 import javax.servlet.http.HttpServletRequest;
 5 import java.io.IOException;
 6 import java.io.PrintWriter;
 7 
 8 /**
 9  * Created by shkstart on 2017/11/06.
10  */
11 public class LoginServlet implements Servlet {
12     @Override
13     public void init(ServletConfig servletConfig) throws ServletException {
14 
15     }
16 
17     @Override
18     public ServletConfig getServletConfig() {
19         return null;
20     }
21 
22     @Override
23     public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
24         String userName = servletRequest.getParameter("userName");
25         String passWord = servletRequest.getParameter("passWord");
26 //        获取上面 jsp 文件中的输入框的值
27         System.out.println("userName: " + userName + "; passWord: " + passWord);
28 //         获取上面 jsp 文件中多选框的值
29         String[] interests = servletRequest.getParameterValues("interest");
30         for (String inter : interests) {
31             System.out.println("INTEREST: " + inter);
32         }
33 
34 //        获取请求的 URI,获取与 HTTP 请求有关的需要使用 ServletRequest 子接口 HttpServletRequst
35         HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
36         String uri = httpServletRequest.getRequestURI();
37         System.out.println(uri);
38 
39         String method = httpServletRequest.getMethod();
40         System.out.println(method);
41 
42 
43 //        获取 Servlete 的映射路径
44         String servletPath = httpServletRequest.getServletPath();
45         System.out.println(servletPath);
46 
47 //        设置响应内容类型,为 word
48 //        servletResponse.setContentType("application/msword");
49 
50         PrintWriter printWriter = servletResponse.getWriter();
51         printWriter.print("HelloWorld");
52     }
53 
54 
55     @Override
56     public String getServletInfo() {
57         return null;
58     }
59 
60     @Override
61     public void destroy() {
62 
63     }
64 }

   如果每次都要像上面这样继承 Servlet 接口,且其大多数方法并不会经常用到,如果你感到这样很烦琐就对了,因为  Servlet 接口有一个子接口 GenericServlet,GenericServlet 实现了 Servlet 和 ServletConfig 接口的所有方法的一个抽象类,其中的 serevice 方法为抽象方法,因为每次请求都要去实现 service 方法;在其中 声明了一个 servletConfig 成员变量,在 init(ServletConfig) 方法中对其进行初始化;利用 ServletConfig 成员变量的方法实现了 ServletConfig 接口的方法,还定义了一个 init() 方法,在 init(ServletConfig) 方法对其进行调用,子类可以直接覆盖 init() 在其中实现对 Servlet 的初始化,这样我们继承 GenericServlet 就可以极大简化我们的代码。

  我们如果在 service 方法中想要获取有关 URL 的相关信息,我们还必须使用 HttpServletRequest 和 HttpServletResponse,如果我们继承 GenericServlet ,那么每次还需要去强制转换,特别麻烦,和上面所述一样我们有封装好的类去专门用作开发----HttpServlet,HttpServlet 继承自 GenericServlet,针对 HTTP 协议所定制;特点是在 service 方法中直接把 ServletRequest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse,并调用 service(HttpServletRequest resquest, HttpServletResponse response);

  我们在平常开发中的 Servlet 便是继承自 HttpServlet,如果对上面所述的 GenericServlet 和 HttpServlet 想理解的更清楚可以去阅读源代码,看看他们的具体实现,下一篇文章将会对上面所述的四个对象的方法加以更加详细的讲解。

  以上就是本周对 Servlet 学习的知识总结,有点乱,如果有什么疑问或者错误可以提出来我会尽快回复。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-11-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档