Servlet配置与高效部署

作出网页后端的核心目标就是 , 基于 tomcat 编程进行网站后端的开发 , 肯定需要对 http 协议进行一系列操作 , 幸运的是 tomcat 已经把这些 http 相关的底层操作封装好了(监听端口 , 接收连接 , 读取请求 , 解析请求 , 构造请求对象等一系列操作) , 只需调用 tomcat 为我们提供的 api 即可. 而 Servlet 就是 Tomcat 给 java 提供的进行 web 开发的原生 api. 当然 Servlet 在企业中已经很少见了 , 但类似于Spring MVC 这样高效的 web 开发 api , 也是基于 Servlet 进行封装的 , 技术是层出不穷的 , 我们只有掌握最基础的框架 , 才能以不变应万变.
Servlet 是什么?

Servlet 是一种实现动态页面的技术. 是一组 Tomcta 提供给程序员的 API , 帮助程序员简单高效开发的一个 web api.

静态页面 vs 动态页面

  • 静态页面: 就是内容始终固定的页面 , 即使 用户不同/时间不同/输入参数不同 , 页面内容也不会发生变化.
  • 动态页面: 用户不同/时间不同/输入参数不同 , 页面内容会发生变化.

举个例子:

Tomcat的主页就是 静态页面

image-20230413144257055

B站的主页就是动态页面

image-20230424104712354

构建动态页面的技术有很多 , 每种语言都会有一些相关的库/框架来做这件事

Servlet 就是 Tomcat 这个 HTTP 服务器提供给 Java 的一组 API , 来完成构建动态页面这个任务 , 而不必关注 Socket , Http 协议格式 , 多线程并发等技术细节 , 降低了 web app 开发门槛 , 提高了开发效率.

Servlet 主要的工作

  • 允许程序员注册一个类 , 在 Tomcat 收到某个特定的 HTTP 请求的时候 , 执行这个类中的一些代码.
  • 帮助程序员解析 HTTP 请求 , 把 HTTP 请求从一个字符串解析成一个 HttpRequest对象
  • 帮助程序员构造 Http 响应 , 程序员只要给指定的 HttpResponse 对象填写一些属性字段 , Servlet 就会自动的按照 Http 协议的方式构造一个 Http 响应字符串 , 并通过 Socket 写回到客户端.

第一个 Servlet 程序

首先第一步 , 预期写个 servlet 程序 , 部署到 tomcat 上 , 通过服务器访问 , 得到 hello world 字符串. 该 hello world 堪称史上最难 hello world

一共七步 , 除了编写 hello world 代码之外 , 其余步骤都是固定的.

扫描二维码关注公众号,回复: 15069938 查看本文章
  1. 创建项目
  2. 引入依赖
  3. 创建目录结构
  4. 编写代码
  5. 打包程序
  6. 部署程序
  7. 验证

1.创建项目

此处我们要创建一个 maven 项目 , maven 是个"工程管理"工具.

主要作用是:

  1. 规范目录结构
  2. 管理依赖(使用了什么第三方库 , 都处理好)
  3. 构建
  4. 打包
  5. 测试

image-20230405163516003

按照上图选择即可~~

如果首次使用 maven , 项目创建好后 , 会从中央仓库加载一些 maven 的依赖 , 需要联网且耐心等待 , 只有第一次使用会这样 , 后续创建就方便了.

maven 虽然是个独立的项目 , 但是不需要单独下载 , 因为 IDEA 已经自带了.

注意创建好的项目目录:

image-20230405164234160

2.引入依赖

servlet 的 jar 包依赖

[Maven仓库](Maven Repository: Search/Browse/Explore (mvnrepository.com))

搜索 Servlet

image-20230405164628386

对应与Tomcat 8 的版本号 , 我们需要下载 3.1.0

image-20230405164752119

只需下面这段代码粘贴到pom.xml中.

image-20230405164847451

Tips: 这里不是随便粘贴 , 而是创建一个子标签 , 粘贴到该子标签中.

image-20230405165125246

如果首次使用依赖可能是红色(红色说明没有下载完) , 一般只要粘贴进来 , idea 的 maven 就会自动去maven仓库下载 , 这段配置就相当于该依赖在 maven 仓库的坐标.


3. 创建目录

  1. 在 main 目录下(和java , resources 并列) , 创建一个 webapp 目录.
  2. 在 webapp 下创建 WEB-INF 目录
  3. 在WEB-INF 目录下创建一个 web.xml 文件

image-20230405165650188

Tips: 此处创建的目录和结构 , 一点都不能错.

给 web.xml 写点代码

<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>

以上代码无需背 , 当前写的 servlet 程序和以往写的代码相比有一个非常大的区别 , 那就是没有 main 方法 , main 方法可以视为是汽车的发动机 , 有发动机才能跑. 但目前车辆没有发动机 , 为了让汽车跑起来 , 可以挂个车头 , 让车头拽着跑即可. 我们写的 servlet 程序就是车厢 , tomcat就是车头 , 我们把写好的 servlet 程序放在 webapps 目录下就相当于把车厢挂到车头之后 , WEB-INF/web.xml 就是告诉 tomcat 哪些车厢(文件)是需要拉的.

4.编写代码

在 java目录底下创建一个.java文件用于编写代码

image-20230405170745598

servlet api 里提供的现成的类 , 写 servlet 代码需要继承 HttpServlet , 这里继承的主要目的 , 是为了通过方法重写的方式 , 针对 HttpServlet 进行功能的扩展.

public class HelloServlet extends HttpServlet 

重写 doGet 方法 , 父类中已有 doGet , 此处希望用子类版本替代父类的.

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
//        super.doGet(req, resp);这段代码一定要去掉,父类只会返回一个错误页面

    }

我们写的 doGet 方法 , 无需我们手动调用 , 而是交给 Tomcat 来调用 , Tomcat 收到 get 请求 , 就会触发 doGet 方法. Tomcat 会构造好两个参数 , req(请求) 和 resp(响应).

  • req: TCP Socket 中读出来的字符串 , 按照 HTTP 协议解析到的对象 , 该对象里的属性和HTTP请求报文格式相对应.
  • resp: 是一个空的对象(不是 null , 只是 new 了个对象 , 里面的各种属性没设置) , 程序员需要在 doGet 中根据 req , 结合自己的业务逻辑构造出一个 resp 对象. doGet 做的工作就是根据请求计算响应 , 其中 resp 这个参数 , 本质上是一个"输出型参数". 在方法中将参数构造好之后 , 由调用者把结果写到 TCP Socket 里面传回到浏览器中.

编写代码:

//        这个仅仅是在服务器的控制台打印
        System.out.println("hello world");
//        要想把 hello world 返回到客户端 , 需要以下代码
//        getWriter 会得到一个 writer 对象
        resp.getWriter().write("hello world");

此处的 Writer 对象从属与 resp 对象 , write 操作其实是往 resp 的 body 部分进行写入 , 等 resp 对象整个构造好了 , tomcat 会统一的转成 http 的响应个数 , 再写进 socket.

最后注意在类的最外部加上注解

@WebServlet("/hello")

注解的作用是 , 针对一个类/方法 , 进行额外"解释的说明" , 赋予这个类/方法额外的功能/含义.

此处这个 @WebServlet 注解 , 作用是把当前类和一个 http 请求路径关联起来.

doGet 是 Tomcat 收到 Get 请求的时候就会调用 , 具体要不要调用 doGet , 还得看当前 Get 请求的路径是啥 , 不同的路径可以触发不同的代码(关联到不同类上) , 一个Servlet 程序中 , 可以有很多的 Servlet 类 , 每个 Servlet 类都可以关联到不同的路径(对应到不同的资源) , 因此多个 Servlet 就可以实现不同的功能.

例如: 我去餐馆吃鸡肉卷

我发起请求: 老板来个 . 鸡肉卷~~http://ip:port/鸡肉卷?葱=多放

老板收到请求后 , 就会按照"制作鸡肉卷"的流程来做饭(根据请求计算响应)

如果我还有两个请求:

5.打包程序

程序编译好之后(得到一些 .class 文件) , 把这些 .class 文件打成压缩包

jar 就是一种 .class 构成的压缩包 , 但此处要打的是 war 包 , jar 只是一个普通的 java 程序 , war 则是tomcat 专属的用来描述 webapp 的程序 , 一个 war 就是一个 webapp.

借助 maven 点击 package 即可

image-20230406090336409

此时打的包只是 jar 包 , 要想部署到 tomcat 上需要打成 war 包.

<packaging>war</packaging>

打 war 包还需添加插件否则会报错 , 打 jar 包无需添加 , finalName 则是给 war 包重命名.

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
            </plugin>
        </plugins>
        <finalName>hello_servlet</finalName>
    </build>

打包成功后 target 目录下会多一个 war 包.

image-20230406091318610

IDE 明明可以直接运行 , 我们为什么还要这么麻烦的打包?

因为 IDE 直接运行是在本地 , 工作时开发环境(自己写代码的电脑)和运行环境(另一个服务器)很可能不是同一个环境.

6.部署

把打包好的 war 拷贝到 tomcat 的 webapps 目录中即可 , 然后启动 tomcat.

image-20230406091659601

7.验证

打开浏览器, 输入 url , 访问写好的代码.

Tips: 路径名一定要正确.

image-20230406092240957

小结:

浏览器地址栏中国输入 URL , 浏览器就构造了一个对应的 http Get请求 , 发送给 tomcat , tomcat 就会根据第一级路径 , 确定具体的 webapp. 根据第二级路径, 确定是调用了哪个类 , 最后通过 Get/Post 方法确定调用 HelloServlet 的哪个方法(doGet, doPost…)

简而言之:

Http 服务器 , 也是基于 TCP 的服务器 , 创建 TCP server socket 绑定端口 , accept 接收请求 , 收到请求之后 , 从 socket 读取请求 , 把收到的请求构造成 HttpServletRquest 对象 , 再根据请求里的 URL 两级路径 , 确定一个 Servlet 类.(Http 服务器里提前构造好的一个 hash 保存路径和类) , 创建对应 Servlet 实例 , 根据 http 方法决定 Servlet 类的方法 , 执行完方法之后得到 HttpServletResponse 对象 , 按照 http 协议构造 HTTP 响应(得到字符串) , 写回到 socket 即可.


Tomcat 插件高效部署:

上述操作部分过程可以简化 , 例如: 创建项目有项目模板 , 打包部署有固定插件.

因此 IDEA 提供了一些 API , 可以让程序员开发插件 , 对 IDEA 的现有功能进行扩展.

1.打包部署项目的常见插件有 Smart Tomcat(更简单好用)

image-20230407105330812

2.下载好插件之后 , 首次使用 SmartTomcat 需要配置 , 点击 Edit Configuration

image-20230407105558693

3. 添加 add SmartTomcat

image-20230407105639838

5.配置一下 Tomcat 的 context path 路径 , 其余的都不用管.

Tips: context path 开头不要大写字母 , 因为浏览器会把context path 默认转成小写 , 导致无法正确访问页面.

Smart Tomcat 加载单个 webapp 运行 , 与本地的 tomcat 不在一起 , idea 调用 tomcat , 会让 tomcat 加载当前项目的目录 , context path 默认是项目名称 , 如果项目名称开头大写可以修改一下. 这个过程没有打 war 包 , 也没有拷贝和解压缩的过程 , 但是像 webapps 下的一些内容(访问 127.0.0.1:8080 显示欢迎页面)就没有了.

image-20230407111244936

6.运行 Tomcat 即可

7.如下图所示即运行成功:

Tips: 不要点击 idea 中的链接 , 一定 404 , 因为不包含 servlet path.

image-20230407111201952

8.访问网页

image-20230407111142810

常见错误:

出现 404:
  1. 路径错误
  2. webapp 未正确部署
  3. web.xml 写错了
  4. 少写了 Servlet Path
  5. Servlet Path 与 URL 不匹配
出现 405

Tips: 一定要注释掉父类的 super.doGet 方法 , 因为父类默认返回一个 405 的错误页面.

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
    
    
            resp.sendError(405, msg);
        } else {
    
    
            resp.sendError(400, msg);
        }

    }
出现 500:

本质上就是代码报错 , 日志中会明确告诉你异常调用栈中哪一行代码出错.

出现"空白页面":

代码中没写 resp.getWriter.write()

出现"无法访问此网站"

tomcat 没启动 , 检查 tomcat 是不是启动好 , 查看目录中有啥异常 , 常见是端口冲突.


猜你喜欢

转载自blog.csdn.net/liu_xuixui/article/details/130337893
今日推荐