Tomcat

时间:2024-03-30 10:03:19

文章目录

  • Tomcat
    • 1. 快速入门
      • Tomcat 启动
      • Tomcat 目录结构
      • Tomcat 服务中部署 WEB 应用
      • IDEA启动Tomcat
    • 2. Servlet
      • 快速入门
      • 原理图
      • Servlet 生命周期
      • GET 和 POST 请求的分发处理
      • HttpServlet
      • 注解方式开发
        • 目录匹配
        • 扩展名匹配
        • 任意匹配
    • 3. ServletConfig
      • API
      • 应用实例
    • 4. ServletContext
      • API
      • 应用实例1
      • 应用实例2
    • 5. HttpServletRequest
      • 常用API
      • 应用实例
    • 6. 请求转发
      • 应用实例
      • 注意事项和细节
    • 7. HttpServletResponse
      • 常用API
      • 应用案例
      • 中文乱码问题
    • 8. 请求重定向
      • 方式一(推荐)
      • 方式二

Tomcat

Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器。

官方文档: https://tomcat.apache.org/tomcat-8.0-doc/

1. 快速入门

Tomcat 启动

  1. 双击 bin 目录下的 startup.bat 文件
  2. 在浏览器输入 http://localhost:8080/,显示如下界面代表安装成功, 默认在 8080 端口
  3. Tomcat 本质是一个 Java 程序,所以要 jdk, 会去根据 JAVA_HOME 使用指定 jdk,因此我们要确保jdk正确配置到环境变量

请添加图片描述

ps:在开发中,我们可以查看一下哪些端口在监听:netstat -anb (使用管理员权限)

Tomcat 目录结构

请添加图片描述

  • conf 目录下server.xml 用于配置 tomcat 的基本设置(启动端口,关闭端口, 主机名)

  • conf 目录下wex.xml 用于指定 tomcat 运行时配置(比如 servlet 等)

  • webapps 目录是存放 web 应用,就是网站

Tomcat 服务中部署 WEB 应用

一个 WEB 应用由多个 WEB 资源或其它文件组成,包括 html 文件、css 文件、js 文件、动态 web 页面、java 程序、支持 jar 包、配置文件等。开发人员在开发 web 应用时,按照规定目录结构存放这些文件。否则,在把 web 应用交给 web 服务器管理时,不仅可能会使web 应用无法访问,还会导致 web 服务器启动报错。

部署方式:将 web 工程的目录拷贝到 Tomcat 的 webapps 目录下,在浏览器输入: http://ip[域名]:port/工程名/子目录…/文件名

请添加图片描述

请添加图片描述

IDEA启动Tomcat

创建项目后选择"Open Module Settings"(或按下快捷键F4)打开项目的设置。将项目设置为web项目

请添加图片描述

将项目放在web(这里为fish目录)目录下

请添加图片描述

配置tomcat

请添加图片描述

2. Servlet

Servlet是Java编写的服务器端程序,它运行在Web服务器上,用于处理客户端发送的请求并生成响应。

Servlet可以接收HTTP请求、处理请求参数、访问数据库、生成动态HTML页面或其他格式的响应,并将响应发送回客户端。Servlet通常用于构建Web应用程序的后端逻辑。

Servlet的特点:

  • 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
  • 他是用java语言编写的, 本质就是Java类
  • 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
  • 功能强大,可以完成几乎所有的网站功能(在以前,都是使用Servlet开发网站)

快速入门

1)创建工程,并配置好Tomcat。

2)添加servlet-api.jar(在tomcat/lib下) 到工程, 因为servlet.jar 不是jdk自带的, 要引入。

3)在src 下创建包并实现Servlet接口

public class myServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @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() {
        System.out.println("destroy");
    }
}

4)在web.xml中配置映射关系

<servlet>
    <!-- 指定servlet的名称 --> 
    <servlet-name>myServlet</servlet-name> 
    
    <!-- 指定servlet的类名 -->
    <servlet-class>com.lhs.myServlet</servlet-class> 
</servlet>

<servlet-mapping>  
    <!-- 指定要映射的servlet的名称 --> 
    <servlet-name>myServlet</servlet-name> 
    
    <!-- 指定servlet的URL模式 --> 
    <url-pattern>/xxx</url-pattern> 
</servlet-mapping>

5)在浏览器中访问该路径即可调用servlet

原理图

请添加图片描述

Servlet 生命周期

主要有三个方法:

  • init() 初始化阶段
  • service() 处理浏览器请求阶段
  • destroy() 终止阶段

请添加图片描述

1)初始化阶段

Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init() 方法,init() 方法只会调用一次, Servlet 容器默认在第一次访问浏览器时装载 Servlet。

若要在项目启动时自动装载,需要在 web.xml 文件中添加

<load-on-startup>1</load-on-startup> 	<!-- 1 表示装载的顺序 --> 

2)处理浏览器请求阶段(service 方法)

每收到一个 http 请求,服务器就会产生一个新的线程去处理[线程]

创建一个用于封装 HTTP 请求消息的 ServletRequest 对象和一个代表 HTTP 响应消息的ServletResponse 对象,然后调用 Servlet 的 service() 方法并将请求和响应对象作为参数传递进去

3)终止阶段 destory 方法(体现 Servlet 完整的生命周期)

当web 应用被终止,或者Servlet 容器终止运行,或者Servlet 类重新装载时,会调用 destroy() 方法

GET 和 POST 请求的分发处理

// servlet没有获取请求方式的方法,需要转型成其子类HttpServletRequest才能调用getMethod方法
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

String method = httpServletRequest.getMethod();

if("GET".equals(method)) {
    doGet(); //用 doGet() 处理 GET 请求
} else if("POST".equals(method)) {
    doPost(); //用 doPost() 处理 POST 请求
}

HttpServlet

继承servlet的实现类HttpServlet可以更好地处理请求。

代码示例:

public class myServlet01 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");
    }
}

注解方式开发

代码示例:

@WebServlet(urlPatterns = {"/zzz","/yyy"})
public class myServlet01 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");
    }
}
目录匹配

上述"/zzz","/yyy"为精确路径匹配,我们也可以用 “*” 来表示匹配任意目录,例如“@WebServlet(urlPatterns = “/zzz/*”)” 表示只要路径以"zzz"开头都可匹配(可以有多级子路径)。

扩展名匹配

可用@WebServlet(“*.action”)匹配任意.action目录,例如"http://localhost:8080/xxx.action"

@WebServlet(“/*.action”) , 不能带 / , 否则 tomcat 报错。

任意匹配

@WebServlet(“/”) @WebServlet(“/*”)表示任意匹配,会匹配所有请求,尽量避免使用

当 Servlet 配置了 “/”, 会覆盖 tomcat 的 DefaultServlet, 当其他的 utl-pattern 都匹配不上时,都会走这个Servlet, 这样就会拦截到其它静态资源。

优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > /* > /

3. ServletConfig

ServletConfig 类是为 Servlet 程序的配置信息的类,Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象。

API

ServletConfig接口定义了以下方法:

  • String getServletName():返回Servlet的名称。
  • ServletContext getServletContext():返回Servlet的上下文对象,用于获取全局的配置信息。
  • String getInitParameter(String name):根据参数名称获取Servlet的初始化参数。
  • Enumeration getInitParameterNames():获取所有初始化参数的名称。

应用实例

要求:在 Servlet 执行 doGet()/doPost() 时,可以获取到 web.xml 配置的用户名和密码

在web.xml文件中配置初始化参数:

<servlet>
    <servlet-name>myServlet</servlet-name>
    <servlet-class>com.lhs.myServlet</servlet-class>
    <init-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </init-param>
    <init-param>
        <param-name>password</param-name>
        <param-value>123</param-value>
    </init-param>
</servlet>
public class myServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取当前servlet的servletConfig对象
        ServletConfig servletConfig = getServletConfig(); 
        // 获取初始化参数username
        System.out.println(servletConfig.getInitParameter("username"));
        // 获取初始化参数password
        System.out.println(servletConfig.getInitParameter("password"));

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

4. ServletContext

ServletContext 是一个接口,它表示 Servlet 上下文对象。

一个 web 工程,只有一个 ServletContext 对象实例(ServletConfig对象是每一个Servlet都会有一个)。

ServletContext 对象 是在 web 工程启动的时候创建,在 web 工程停止的时销毁。

ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext 对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。

由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个 Servlet 间通讯。ServletContext 对象通常也被称之为域对象。

请添加图片描述

API

ServletContext接口定义了以下方法:

  • String getInitParameter(String name):根据参数名称获取ServletContext的初始化参数。
  • Enumeration getInitParameterNames():获取所有初始化参数的名称。
  • Object getAttribute(String name):根据属性名称获取ServletContext的属性值。
  • Enumeration getAttributeNames():获取所有属性的名称。
  • void setAttribute(String name, Object value):设置ServletContext的属性值。
  • ServletContext getContext(String uripath):获取指定路径的ServletContext对象。
  • String getServletContextName():获取ServletContext的名称。

应用实例1

需求如下:

  1. 获取 web.xml 中配置的上下文参数 context-param
  2. 获取当前的工程路径,格式: /工程路径
  3. 获取工程部署后在服务器硬盘上的绝对路径

代码示例:

// 获取ServletContext对象
ServletContext servletContext = getServletContext();
// 获取web.xml中配置的参数
System.out.println(servletContext.getInitParameter("name"));
//获取当前工程路径
System.out.println(servletContext.getContextPath());
//获取项目的绝对路径
System.out.println(servletContext.getRealPath("/"));

应用实例2

需求: 完成一个简单的网站访问次数计数器,每访问一次次数+1

代码示例:

ServletContext servletContext = getServletContext();

// 获取count属性
Object count = servletContext.getAttribute("count");
int c;
// 如果获取不到则表示是第一次访问
if (count == null){
    servletContext.setAttribute("count",1);
    c = 1;
}else {
    c = (int)count +1;
    servletContext.setAttribute("count",c);
}
// 将结果显示到页面
// 设置响应类型
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println("当前访问次数为:"+c);
writer.flush();
writer.close();

5. HttpServletRequest

HttpServletRequest 对象代表客户端的请求

当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中

通过这个对象的方法,可以获得客户端这些信息

常用API

  1. getRequestURI() 获取请求的资源路径

  2. getRequestURL() 获取请求的统 一 资源定位符 ( 绝 对 路 径 )

  3. getRemoteHost() 获取客户端的主机, getRemoteAddr()

  4. getHeader() 获取请求头

  5. getParameter() 获取请求的参数

  6. getParameterValues() 获取请求的参数(多个值的时候使用) , 比如 checkbox, 返回的数组

  7. getMethod() 获取请求的方式 GET 或 POST

  8. setAttribute(key, value); 设置域数据

  9. getAttribute(key); 获取域数据

  10. getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象

应用实例

需求: 在一个表单提交数据给 Servlet , 然后在 Servlet 通过 HttpServletRequest对象获取相关数据

创建个表单:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册</title>
    </head>
    <body>
        <h1>注册用户</h1>
        <form action="http://localhost:8080/xxx" method="get">
            u: <input type="text" name="username"/><br><br>
            p: <input type="password" name="pwd"/><br><br>
            选择:
            <input type="checkbox" name="hobby" value="1">1
            <input type="checkbox" name="hobby" value="2">2
            <input type="checkbox" name="hobby" value="3">3<br/><br/>
            <input type="submit" value="注册用户"/>
        </form>
    </body>
</html>

获取请求信息:

System.out.println(req.getRequestURI());
System.out.println(req.getRequestURL());
System.out.println(req.getParameter("username"));
System.out.println(req.getParameter("pwd"));
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
    System.out.println(hobby);
}

ps:获取 doPost 参数中文乱码解决方案:在request.getParameter()前添加setCharacterEncoding("utf-8")

6. 请求转发

请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外一个 web 资源进行处理。

HttpServletRequest 对象提供了一个 getRequestDispatcher 方法,该方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发。

HttpServletRequest对象同时也是一个域对象,可以通过setAttributegetAttribute等方法在实现转发时,把数据通过 request 对象带给其它 web 资源处理。

请添加图片描述

应用实例

需求:在servlet01中获取username,并赋予角色身份,在servlet02中获取到该角色

servlet01:

String username = req.getParameter("username");
if("tom".equals(username)){
    req.setAttribute("role","admin");
}else{
    req.setAttribute("role","user");
}
// 根据URI获取请求转发器
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/yyy");
// 表示把当前 servlet 的 request 对象和response 对象,传递给下一个 servlet 使用
requestDispatcher.forward(req,resp);

servlet02:

// 从request中拿出servlet01中设置好的角色信息
Object role = req.getAttribute("role");
System.out.println((String) role);

注意事项和细节

1)浏览器地址不会变化(地址会保留在第 1 个 servlet 的 url)

2)在同一次 HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求

3)在同一次 HTTP 请求中,进行多次转发,多个 Servlet 可以共享 request 域/对象的数据(因为始终是同一个 request 对象)

4)可以转发到 WEB-INF 目录下

5)不能访问当前 WEB 工程外的资源

6)因为浏览器地址栏会停止在第一个 servlet ,如果刷新页面,会再次发出请求(并且会带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付

7. HttpServletResponse

每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。

HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可。

常用API

1)void setStatus(int sc):设置响应的状态码。

2)void setContentType(String type):设置响应的内容类型。

3)void setHeader(String name, String value):设置响应头部的值。

4)PrintWriter getWriter():获取用于向客户端输出字符数据的PrintWriter对象。

5)ServletOutputStream getOutputStream():

6)void sendRedirect(String location):重定向到指定的URL。

7)void addCookie(Cookie cookie):添加Cookie到响应中。

8)void setCharacterEncoding(String charset):设置响应的字符编码。

应用案例

需求:浏览器请求 , 返回 hello, world

代码示例:

resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.println("hello world");
writer.flush();
writer.close();

中文乱码问题

设置服务器字符集为utf-8(并不会影响浏览器的显示):

resp.setCharacterEncoding("utf-8");

设置浏览器也使用utf-8的两种方式:

// 方式一:
resp.setContentType("text/html;charset=utf-8");

// 方式二:
resp.setHeader("Content-Type","text/html;charset=utf-8");

8. 请求重定向

请求重定向指一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web资源。

请添加图片描述

方式一(推荐)

// 访问内部资源
resp.sendRedirect("/servlet/yyy");

// 访问外部资源
resp.sendRedirect("https://www.baidu.com");

访问内部资源时需要带上项目路径,因为该路径由浏览器解析(请求转发由服务器解析,因此不需要携带)。

方式二

resp.setStatus(302);
resp.setHeader("Location","/servlet/yyy");