【JavaEE】如何开始基础的Servlet编程(基于Tomcat服务器)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

如何开始最简单的Servlet编程基于Tomcat服务器

知道了如何借助Tomcat开始进行最简单的Servlet编程后我们就可以进一步完善功能制作一个基础的网站了。

在此之前我们先了解一下Servlet的生命周期。

Servlet的生命周期

初始化init -> 处理请求service -> 销毁destroy

对生命周期而言这三个方法是最重要的标志着开头过程和结束。

Servlet的方法

init()

HttpServlet实例化后被调用一次

service()

收到HTTP请求就会调用

destroy()

HttpServlet实例不再被使用时调用一次

doGet()

收到GET请求后由service方法调用

doPost()

收到POST请求后由service方法调用

doDelete() \ doPut()…

收到其他请求后由service方法调用

在了解Servlet工作过程之前先查看一个概念Servlet容器。Servlet代码的运行环境就是Servlet容器说白了就是管理许多Servlet的创建、使用、销毁的东西如Tomcat、Jetty、Jboss一般而言是Web服务器。

Servlet工作过程

  1. 在Web服务器接收到第一个HTTP请求的时候会调用一次init()加载一个对应的Servlet。

  1. 随后Web服务器用多线程的方式每个请求对应一个线程去执行service()响应结果再返回Web服务器。

  1. 而destroy()是不一定被调用到的因为大部分情况程序会被强制关闭而非老老实实被销毁然后让JVM垃圾回收。

p.s. 开发中通常都是只需要重写doXXX方法service会根据方法调用不同的doXXX。

知道了Servlet的生命周期后我们就需要知道我们不仅得了解如何处理请求我们可能还要了解请求如何生成。

Servlet编程

前后端编程

前端通过ajax构建请求

后端设置响应

基本交互

逻辑

  1. 客户端发送ajax请求后触发服务器的doXXX

  1. 然后getWriter.write会触发客户端的ajax中success回调函数

如下

有表白墙代码供大家练习

<script>
        let container = document.querySelector('.container');
        let button = document.querySelector('button');
        button.onclick = function() {
            // 1. 获取到输入框的内容
            let inputs = document.querySelectorAll('input');
            let from = inputs[0].value;
            let to = inputs[1].value;
            let message = inputs[2].value;
            if (from == '' || to == '' || message == '') {
                alert('当前输入框内容为空!');
                 return;
             }
            console.log(from + ", " + to + ", " + message);
            // 2. 能够构造出新的 div, 用来保存用户提交的内容
            let rowDiv = document.createElement('div');
            rowDiv.className = 'row';
            rowDiv.innerHTML = from + " 对  " + to + " 说:  " + message;
            container.appendChild(rowDiv);
            // 3. 提交完之后, 清空输入框的内容
            for (let i = 0; i < inputs.length; i++) {
                 inputs[i].value = '';
             }
            // 将输入框里取到的数据构造成JS对象类似于JSON结构都是{}+:的字符串
            // 完整形式如
            // let messageJson = {
            //     "from": from,
            //     "to": to,
            //     "message": message
            // };
            // 当然可以省略key对象的引号写成下面的形式
            let messageJson = {
                 from: from,
                 to: to,
                 message: message
             };
            $.ajax ({
                 type:'post',
                 
                // 相对路径写法
                // 只需要写Context Path后的内容 
                 url:'mWall',
                // 绝对路径写法
                // 写localhost:8080后的内容
                 // url:'/newCat/mWall'
                 
                 contentType: 'application/json; charset:utf8',
                // JS自带的JSON转译 转成JSON对象
                 data:JSON.stringify(messageJson),
                // 服务器是2系列的时候执行
                 success:  function(){
                     alert("提交成功");
                 },
                // 服务器不是2系列的时候执行
                 error: function() {
                     alert("提交失败");
                 }
             });
         }
</script>  

这中间的ajax代码表示当点击了提交按钮后会自动构造一个POST请求提交数据内容是将input的内容打包成json格式发送给服务器。

后端代码处理这个POST请求

@WebServlet("/mWall")
public class MessageWall  extends HttpServlet {
//    ObjectMapper是Jackson Datamind提供用于IO Json的类
    private  ObjectMapper objectMapper = new ObjectMapper();
    List<Message> messageList = new ArrayList<>();
    @Override
    protected  void doPost(HttpServletRequest req,
                           HttpServletResponse  resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        messageList.add(message);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write("{ \"ok\": 1}");
     }
}
class Message {
    public  String from;
    public  String to;
    public  String message;
}

对POST的处理方式是将内容存储在List当中并且通过getWriter().write()返回响应响应会触发回调函数

success里的内容是一个提示所以有

前端再整个从服务器中获取页面的操作逻辑是构造Get请求希望服务器发送List的内容然后通过success回调去解析

   <script>
        // 从服务器获取页面操作
        // 函数在页面加载时候调用 (每次加载页面  / 刷新页面时候触发)
        // 通过该函数实现从服务器获取消息列表并显示到页面上
     
        function load() {
            $.ajax( {
                 type: 'get',
                 url: 'mWall',
                 success:  function(body) {
                     // 获取的body已经是js对象的数组
                     // ajax会自动 根据Content-Type 进行类型转换
                     // 将服务器返回的Json格式字符串时 Content-Type为application/json
                     // 则将 将json转为js对象
                     // 对响应的body进行解析
                     
                     // 遍历数组并将内容构造到页面上
                     for (let message of body) {
                         let newDiv = document.createElement('div');
                         newDiv.className = 'row';
                         newDiv.innerHTML = message.from + "  对" + message.to + " 说" + message.message;
                         container.appendChild(newDiv);
                     }
                 }
             })
         }
        // 函数调用写在这里页面加载的时候执行
        load();
    </script> 

后端响应如下

@Override
protected void doGet(HttpServletRequest  req,
                      HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("application/json;  charset=utf8");
//         这个方法可以将对象转为Json格式的字符串 这里是List的话就转成Json数组
    String  respString  = objectMapper.writeValueAsString(messageList);
    resp.getWriter().write(respString);
}

提交后抓包可以看到

每次刷新页面就会前端就会调用load代码然后构造了请求获取到了json键值对

使用数据库改进数据存储方式

  1. 在pom.xml中引入Maven依赖

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.31</version>
</dependency>
 
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

好像主要是使用mysql-connector-java

  1. 创建数据库表

  1. 把操作保存好

  1. 修改后端代码

  1. 和数据库建立连接建立一个DBUtil类封装connection、close等功能

public class DBUtil {
//    单例对象
    private  static DataSource dataSource = null;
 
    private  static DataSource getDataSource () {
        if (dataSource == null) {
            dataSource = new MysqlDataSource();
//            localhost:3306后跟的应该是数据库的名字
            ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/MessageWall?characterEncoding=utf8&useSSL=false");
            ((MysqlDataSource)dataSource).setUser("root");
            ((MysqlDataSource)dataSource).setPassword("1234");
         }
        return dataSource;
     }
 
    public  static Connection getConnection () throws SQLException  {
        return getDataSource().getConnection();
     }
 
    public  static void close (Connection  connection, PreparedStatement statement, ResultSet resultSet)  {
//        分开写可以保证一个异常了后南面的都可以执行到
        if (resultSet != null) {
            try  {
                 resultSet.close();
            } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
        if (statement != null) {
            try {
                 statement.close();
            } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
        if (connection != null) {
            try {
                 connection.close();
            } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
     }
}
  1. 通过JDBC完成对数据库的操作

private void save (Message message) {
    Connection  connection = null;
    PreparedStatement  statement = null;
    try {
//            和数据库构建连接
        connection = DBUtil.getConnection();
//            构造SQL语句
        String sql = "insert into  message values(?,?,?);";
        statement = connection.prepareStatement(sql);
        statement.setString(1,message.from);
        statement.setString(2,message.to);
        statement.setString(3,message.message);
//            执行SQL语句返回值表示操作影响了几行针对table而言
        int ret = statement.executeUpdate();
//            这里插入了一行数据就是影响了一行
        if (ret != 1) {
            System.out.println("插入失败!");
        } else {
            System.out.println("插入成功!");
         }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
//            关闭连接
        DBUtil.close(connection, statement, null);
     }
    System.out.println("Method save  has been executed!");
}
 
private List<Message> load (){
    Connection  connection = null;
    PreparedStatement  statement = null;
    ResultSet  resultSet = null;
    List<Message> messageList = new ArrayList<>();
    try {
//            和数据库创建连接
        connection = DBUtil.getConnection();
//            构造SQL语句
        String sql = "select *  from message;";
        statement = connection.prepareStatement(sql);
//            执行SQLexecuteQuery执行查询 返回结果是一个resultSet结果集
        resultSet = statement.executeQuery();
//            遍历结果集
        while (resultSet.next()) {
            Message message = new Message();
//            读取from这一列
            message.from = resultSet.getString("from");
            message.to = resultSet.getString("to");
            message.message = resultSet.getString("message");
            messageList.add(message);
         }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
//            释放资源
        DBUtil.close(connection, statement, resultSet);
     }
    System.out.println("Method load  has been executed!");
    System.out.println(messageList.toString());
    return  messageList;
}

主要是添加这两个方法将原来的通过类中的容器进行存储改成通过数据库进行存储。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6