Java教程

Servlet 学习笔记

本文主要是介绍Servlet 学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 1、 servlet 开发流程
    • 1.1 开发阶段
    • 1.2 构建阶段
    • 1.3 运行阶段
    • 1.4 常见错误
      • 1.4.1 Tomcat 没有启动
      • 1.4.2 资源 URL 错误
      • 1.4.3 服务器内部出现问题
      • 1.4.4 排查错误思路
      • 1.4.5 Tomcat 打印日志信息
      • 1.4.6 浏览器开发者工具
      • 1.4.7 IDEA 调试器
  • 2、Servlet 运行基本原理
  • 3、Servlet 的使用
    • 3.1 读取 HTTP 请求内容
    • 3.2 发送响应
    • 3.3 获取浏览器(用户)提交的数据
    • 3.4 关联数据库操作
      • 3.4.1 裸文本
      • 3.4.2 html
      • 3.4.3 JSON(JavaScript Object Notation)


  • Java 官方提供了 Servlet 标准,Java 官方写好一套接口就和抽象类,用于连接 Tomcat 开发者 和 应用开发者的桥梁。Servlet 是一种实现动态页面的技术,是一组 Tomcat 提供的 API, 帮助我们简单高效的开发一个 web app。

在这里插入图片描述

1、 servlet 开发流程

1.1 开发阶段

  • servlet path
  • 设置pom.xml 文件
<!--设置打包方式为 war 方式 -->
    <packaging>war</packaging>

    <!-- 设置 maven 的编译器版本是 1.8  -->
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <!-- 添加 servlet 依赖 scope = provided表示这个依赖下的所有类只在开发、构建需要,运行时 Tomcat 内部已经有这套类了 -->
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

在这里插入图片描述
查找标准的依赖写法:https://search.maven.org/artifact/javax.servlet/javax.servlet-api/3.1.0/jar

  • 新建存在静态资源的目录
    在这里插入图片描述
  • 设置Web应用配置
    在这里插入图片描述
    web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
</web-app>
  • 新建java文件,动态资源
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;

/*
1. 继承 HttpServlet 抽象类
2. 通过 @WebServlet 注解,修饰类,填写资源路径,必须以 / 开头
3. 重写 doGet(...) 方法
 */
@WebServlet("/first")
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        1. 设置响应头 Content-Type:
         */
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/plain");

        /*
        2. 准备响应的正文部分
         */
        String s = "你好中国";

        /*
        3. 拿到写入正文的 writer
         */
        PrintWriter writer = resp.getWriter();

        /*
        4. 写入正文
         */
        writer.println(s);
    }
}

1.2 构建阶段

  • context path

  • 编译(build)----》打包(Package)----》部署(deploy)
    在这里插入图片描述
    在这里插入图片描述

  • 也可以使用 build artifact
    在这里插入图片描述

  • 使用专业版 IDEA 自带 Tomcat 插件启动
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

1.3 运行阶段

  • 运行 Tomcat,动态资源被修改以后,必须要重新启动 Tomcat,才可以生效。在这里插入图片描述
  • 在浏览器中访问资源。URL = context path + servlet path 。

1.4 常见错误

1.4.1 Tomcat 没有启动

在这里插入图片描述

  • 之前有写过 Tomcat 无法启动的解决方案:https://blog.csdn.net/ccyzq/article/details/122182173

1.4.2 资源 URL 错误

  • HTTP:404
    在这里插入图片描述
  • URL = context path(web 应用) + servlet path(各个资源)。如果在浏览器中没有输入正确的 URL ,就会出现 404 。

1.4.3 服务器内部出现问题

  • 例如 动态资源中的代码出现异常,就会出现 HTTP:500 错误。

1.4.4 排查错误思路

  • 小明写了一个 Web 应用,启动 Tomcat 后,访问了一个 URL 是 /hello.do 的资源,出现以下现象时,小明的怀疑是否合理?
  • 1、浏览器出现 404 ,小明怀疑自己的 Tomcat 启动失败了。
    不合理,浏览器出现 404 ,就说明有一个 web 服务器告诉浏览器资源是不存在的,所以,web 服务器一定是启动成功的。
    但是在某些场景下是合理的,例如之前安装过类似 Tomcat 这样的 Web 服务器,这次 Tomcat 启动失败,看到的 404 是之前安装的 web 服务器所导致的。
    总结:看到了HTTP 响应(1xx、2xx、3xx、4xx、5xx),都表示 web 服务器应答浏览器。没有启动只会显示无法访问,不能看到状态码。
  • 2、看到资源出现404,小明怀疑自己的资源路径放置错误
    有合理性,但是还有可能是自己的 URL 输入错误。
  • 3、看到资源出现500时,小明怀疑自己的资源路径放置错了/ URL输入错误
    不合理,出现500,直接看页面上的提示信息就可以。
  • 4、通过开发者工具看到响应是200,但是浏览器上没有显示
    HTTP 响应 = 控制数据 (响应行 + 响应头) + 负荷数据(响应体)。说明该资源的响应行和响应头是正确的,响应体(正文)可能是空,或者其他原因导致空白的内容(html 中 < body> 下为空… )
  • 5、出现405状态码
  • Method Not Allowed:客户端的问题。使用了错误的 HTTP 访问某个资源,就是 URL 对应的资源存在,但是访问的方法不对。
  • 不重写 doGet 方法,通过 GET 方法访问时,实际上会执行 对象doGet 方法(METHOD_NOT_ALLOWED),就会出现 405 。
  • 想要通过 post 方法访问某个资源:1、通过 form 表单,指定 method 属性。2、通过 js 代码来实现。
<form method="post" action="method">
        <button>通过 post 访问</button>
</form>

1.4.5 Tomcat 打印日志信息

  • 可以自己添加打印等工作。
public class method extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("运行到这里");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/plain");
        resp.getWriter().println("我是处理 method 的 POST 方法的");
    }
}

1.4.6 浏览器开发者工具

  • 元素面板(HTML、CSS)
  • 网络面板(HTTP协议)
  • 前端调试面板(JS)
  • 控制台面板(JS)

1.4.7 IDEA 调试器

  • 主要调试后端

2、Servlet 运行基本原理

  • 当浏览器给服务器发送请求的时候, Tomcat 作为 HTTP 服务器, 就可以接收到这个请求。
  • Tomcat = HTTP 服务器(对接浏览器)+ Servlet 容器(对接 Web 应用)。
  • HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作。
    在这里插入图片描述
  • Tomcat的工作
    • 1、通过网络读取 HTTP 请求,并解析。
    • 2、判断是 静态/动态 资源。
    • 3、动态资源找到对应的 Servlet 对象去处理,静态资源找路径对应下的文件,如果找不到就是404。
    • 4、根据动态资源的不同方法,来调用 doGet/doPost 。
    • 5、根据请求内容来填充响应对象。※
    • 6、根据响应对象来组装 HTTP 相应数据。
    • 7、通过网络把响应发送给浏览器。

3、Servlet 的使用

3.1 读取 HTTP 请求内容

  • 请求方法、资源路径、请求头

3.2 发送响应

  • ① 设置状态码,不修改的情况下就是200。resp.setStatus(200)
  • ② 这是响应头,resp.setCharacterEncoding("utf-8");resp.setContentType("text/plain"); text/html、text/css、application/javascript、application/json。
  • ③ 发送正文,resp.getWriter().println();

3.3 获取浏览器(用户)提交的数据

  • ① GET 方法获取(参数来自 URL 的 querystring 部分,?key1=value1&key2=value2)
package com.cc.servlet;

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;

@WebServlet("/get-param")
public class GetParam extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        System.out.printf("name = %s, age = %s\n",name, age);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/plain");

        PrintWriter writer = resp.getWriter();
        writer.printf("name = %s, age = %s\n",name, age);
    }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • ② 通过 POST 发送的参数(指的是 form 表单发送)。来自 query string,请求体。

在这里插入图片描述

  <form method="post" action="post-param">
    <input type="text" name="name">
    <input type="text" name="age">
    <button>提交</button>
  </form>
@WebServlet("/post-param")
public class PostParam extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	req.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        System.out.printf("name = %s, age = %s\n", name, age);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/plain");

        PrintWriter writer = resp.getWriter();
        writer.printf("name = %s, age = %s\n",name, age);
    }
}

在这里插入图片描述

  • ③ 读取用户通过 form 表单提交的参数(get/post),都可以加上req.setCharacterEncoding("utf-8");String name = req.getParameter("name");String[] names = req.getParameterValues("name");

3.4 关联数据库操作

  • 1、引入 JDBC 依赖
<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
</dependency>
  • 2、创建库、表,并添加数据

3.4.1 裸文本

package com.cc.servlet;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/user-list.txt")
public class UserListServlet extends HttpServlet {
    //使用 text/plain 形式显示
    // 通过添加打印信息, 观察中间过程的数据正确性
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            List<User> userList = queryFromDB();
            System.out.println(userList);
            String responseBody = userListToString(userList);
            System.out.println(responseBody);

            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/plain");

            PrintWriter writer = resp.getWriter();
            writer.println(responseBody);
        } catch (SQLException exc) {
            // 由于 SQLException 不在方法签名可以抛的异常列表内,并且不能更改方法签名,否则就不是方法重写了
            throw new ServletException(exc);
        }

    }

    private String userListToString(List<User> userList) {
        StringBuilder sb = new StringBuilder();

        for (User user : userList) {
            sb.append(user.toString());
            sb.append("\r\n");
        }

        return sb.toString();
    }

    private List<User> queryFromDB() throws SQLException {
        List<User> userList= new ArrayList<>();

        MysqlDataSource db = new MysqlDataSource();
        db.setServerName("127.0.0.1");
        db.setPort(3306);
        db.setUser("root");
        db.setPassword("123456");
        db.setDatabaseName("db_12_28");
        db.setUseSSL(false);
        db.setCharacterEncoding("utf8");
        db.setServerTimezone("Asia/Shanghai");

        try (Connection c = db.getConnection()) {
            String sql = "SELECT uid, name, age FROM users ORDER BY uid ASC";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                System.out.println(ps);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        User user = new User(
                                rs.getInt("uid"),
                                rs.getString("name"),
                                rs.getInt("age")
                        );
                        userList.add(user);
                    }
                }
            }
        }
        return userList;
    }
}

User.java

package com.cc.servlet;

public class User {
    public Integer uid;
    public String name;
    public Integer age;

    public User(Integer uid, String name, Integer age) {
        this.uid = uid;
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid=" + uid +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在这里插入图片描述

3.4.2 html

package com.cc.servlet;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/user-list.html")
public class UserListHtmlServlet extends HttpServlet {
    // 用 text/html 形式显示
    // 通过添加打印信息, 观察中间过程的数据正确性
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            List<User> userList = queryFromDB();
            System.out.println(userList);
            String responseBody = userListToString(userList);
            System.out.println(responseBody);

            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html");

            PrintWriter writer = resp.getWriter();
            writer.println(responseBody);
        } catch (SQLException exc) {
            // 由于 SQLException 不在方法签名可以抛的异常列表内,并且不能更改方法签名,否则就不是方法重写了
            throw new ServletException(exc);
        }

    }

    // 以 table 形式展示
    private String userListToString(List<User> userList) {
        StringBuilder sb = new StringBuilder("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>用户列表</title>\n" +
                "    <link rel=\"stylesheet\" href=\"css/style.css\">\n" +
                "</head>\n" +
                "<body>\n");

        sb.append("<table border=\"1\">\n");
        for (User user : userList) {
            sb.append("<tr>\n");
            sb.append("<td>").append(user.uid).append("</td>\n");
            sb.append("<td>").append(user.name).append("</td>\n");
            sb.append("<td>").append(user.age).append("</td>\n");
            sb.append("</tr>\n");
        }

        sb.append("</table>");
        sb.append("</body>\n" +
                "</html>");
        return sb.toString();
    }

    private List<User> queryFromDB() throws SQLException {
        List<User> userList= new ArrayList<>();

        MysqlDataSource db = new MysqlDataSource();
        db.setServerName("127.0.0.1");
        db.setPort(3306);
        db.setUser("root");
        db.setPassword("123456");
        db.setDatabaseName("db_12_28");
        db.setUseSSL(false);
        db.setCharacterEncoding("utf8");
        db.setServerTimezone("Asia/Shanghai");

        try (Connection c = db.getConnection()) {
            String sql = "SELECT uid, name, age FROM users ORDER BY uid ASC";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                System.out.println(ps);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        User user = new User(
                                rs.getInt("uid"),
                                rs.getString("name"),
                                rs.getInt("age")
                        );
                        userList.add(user);
                    }
                }
            }
        }
        return userList;
    }
}

在这里插入图片描述
使用结构化方式进行输出,结构化的方式有很多。结构化实际上是对象序列化的一种。

3.4.3 JSON(JavaScript Object Notation)

  • JSON是一种基于文本的轻量级的数据交换格式可以被任何编程语言读取和作为数据的格式传递。

  • JS 对象格式

     {
        “key1”:“value1”,
        “key2”:“value2”
    }
    
  • 数组格式

    [
        	“item1”,“item2”
    ]
    
  • 使用 java 中的第三方库来完成:

    • jackson:推荐,在 Spring 中默认使用的 jackson
    • gson:google公司
    • fast-json:阿里

导入依赖:

<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.4</version>
</dependency>
package com.cc.servlet;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/user-list.json")
public class UserListJSONServlet extends HttpServlet {
    //使用 text/plain 形式显示
    // 通过添加打印信息, 观察中间过程的数据正确性
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            List<User> userList = queryFromDB();
            System.out.println(userList);
            String responseBody = userListToString(userList);
            System.out.println(responseBody);

            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/plain");

            PrintWriter writer = resp.getWriter();
            writer.println(responseBody);
        } catch (SQLException | JsonProcessingException exc) {
            // 由于 SQLException 不在方法签名可以抛的异常列表内,并且不能更改方法签名,否则就不是方法重写了
            throw new ServletException(exc);
        }

    }

    private String userListToString(List<User> userList) throws JsonProcessingException {
        ObjectMapper om = new ObjectMapper();

        return om.writerWithDefaultPrettyPrinter().writeValueAsString(userList);
    }

    private List<User> queryFromDB() throws SQLException {
        List<User> userList= new ArrayList<>();

        MysqlDataSource db = new MysqlDataSource();
        db.setServerName("127.0.0.1");
        db.setPort(3306);
        db.setUser("root");
        db.setPassword("123456");
        db.setDatabaseName("db_12_28");
        db.setUseSSL(false);
        db.setCharacterEncoding("utf8");
        db.setServerTimezone("Asia/Shanghai");

        try (Connection c = db.getConnection()) {
            String sql = "SELECT uid, name, age FROM users ORDER BY uid ASC";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                System.out.println(ps);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        User user = new User(
                                rs.getInt("uid"),
                                rs.getString("name"),
                                rs.getInt("age")
                        );
                        userList.add(user);
                    }
                }
            }
        }
        return userList;
    }
}

在这里插入图片描述

这篇关于Servlet 学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!