Servlet

105 阅读5分钟

Tomcat给java提供的原生的进行web开发的api。

网页分为静态页面和动态页面。

静态页面:页面内容始终是固定不变的。

动态页面:页面内容随着输入参数的不同而改变。

第一个Servlet程序:

1.创建项目

image.png

image.png

首次使用maven会从中央仓库下载一些依赖,耐心等待,或者配置国内镜像。

2.引入依赖

Maven Repository: servlet (mvnrepository.com)

image.png

找到3.x版本,该版本和tomcat8.x版本匹配:

image.png

复制上述代码,将其复制到项目中的porm.xml配置文件中:

image.png

image.png

<!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>

4.编写代码

image.png

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello");
    }
}

5.打包程序

在porm.xml文件中修改配置:

image.png

找到图示打包程序,双击运行,或者右键点击运行:

image.png

打包成功:

image.png

左侧target目录下生成刚才打好的包:

image.png

6.部署

将刚才的war包复制到tomcat的webapps目录下,启动tomcat。

7.验证

image.png

使用IDEA上的插件,简化上述步骤,方便开发阶段进行验证:

image.png

1.新增一个运行时配置

image.png

2.设置tomcat所在的路径:

image.png

3.运行

image.png

如果运行产生乱码问题,修改编码格式:

image.png

验证:

image.png

查看端口使用进程:

image.png

image.png

Servlet常用api介绍:

image.png

servlet生命周期:

开始的时候,执行init()方法;每次收到请求的时候,执行service();销毁之前,执行destroy()。

另外几种方法的测试:

@WebServlet("/method")
public class MethodServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doGet");
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPut");
        resp.getWriter().write("doPut");
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doDelete");
        resp.getWriter().write("doDelete");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
        resp.getWriter().write("doPost");
    }
}

构造http请求:

1.使用postman

image.png

2.ajax()

image.png

HttpServletRequest介绍:

image.png

示例:

```
@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //设置返回数据的格式
        resp.setContentType("text/html");

        //用stringBuilder将api返回结果拼装起来,并返回到页面
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(req.getMethod());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getContextPath());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("<br>");
        stringBuilder.append("<br>");
        stringBuilder.append("<br>");
        stringBuilder.append("<br>");


        //获取到header(报头)中的每一个键值对
        Enumeration<String> Headers = req.getHeaderNames();
        while(Headers.hasMoreElements()){
            String head = Headers.nextElement();
            //req.getHeader() 传入key,获得对应的value
            stringBuilder.append(head + ": " + req.getHeader(head) +"<br>");
        }

        resp.getWriter().write(stringBuilder.toString());
    }
}
```

运行结果:

image.png

前端给后端传参的方式:

1.通过get方法里的query string来传递:

示例:学生id和老师id studentId=10&teacherId=20

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");

        StringBuilder stringBuilder = new StringBuilder();

        /*//通过queryString字符串获取
        String queryString = req.getQueryString();
        String[] strings = queryString.split("&");

        //获取学生id
        String[] student = strings[0].split("=");
        String studentId = student[1];
        stringBuilder.append(studentId);
        stringBuilder.append("<br>");

        //获取老师id
        String[]  teacher = strings[1].split("=");
        String teacherId = teacher[1];
        stringBuilder.append(teacherId);
        stringBuilder.append("<br>");*/

        //通过参数获取
        String studentId = req.getParameter("studentId");
        String teacherId = req.getParameter("teacherId");
        resp.getWriter().write("studentId" + "=" + studentId + " " + "teacherId" + "=" + teacherId);



    }
}

运行结果:

image.png

2.通过post方法,form表单来传递数据

image.png

@WebServlet("/postParameter")
public class PostParameter extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        StringBuilder stringBuilder = new StringBuilder();
        String studentId = req.getParameter("studentId");
        String teacherId = req.getParameter("teacherId");
        resp.getWriter().write("studentId" + "=" + studentId + " " + "teacherId" + "=" + teacherId);
    }
}

image.png

3.通过post方法,json格式来传递数据

json格式:

{ "classId":10, "teacherId":20 }

@WebServlet("/postParameter2")
public class PostParameter2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取到整个body的内容,并将其返回到页面
        //得到body中内容的长度
        int length = req.getContentLength();

        byte[] buffer = new byte[length];

        InputStream inputStream = req.getInputStream();
        inputStream.read(buffer);

        String string = new String(buffer,0,length,"utf8");
        resp.getWriter().write(string);


    }
}

通过postman发送数据:

image.png

通过ajax()发送:

image.png

运行结果:

image.png

刚才的代码得到的是整个json,并没有获得键值对,我们通过第三方库jackson来解析json数据:

1)引入依赖:

maven仓库中找到依赖

image.png

将其复制到porm.xml文件中:

image.png

修改代码:

image.png

类中的属性名必须和json中的键值对一一匹配,不一致时会报错:

image.png

image.png

HttpServletResponse介绍:

image.png

代码示例:服务器版的表白墙

创建新的maven项目,从maven仓库导入servlet,jackson,mysql依赖:

image.png

创建目录:

image.png

加入配置文件:

<!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>

添加服务器:

image.png

导入前端代码:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container{
            width: 600px;
            margin: 0 auto;
        }
        h1{
            margin-top: 10px;
            text-align: center;
        }
        p{
            margin: 10px 0;
            color: #666;
            text-align: center;
        }
        .row{
            display: flex;
            justify-content: center;
            align-items: center;
            height: 40px;
        }
        .row span{
            align-items: center;
            width: 80px;
            
        }
        .row input{
            width: 200px;
            height: 30px;
        }
        button{
            color: white;
            background-color: orange;
            width: 280px;
            height: 34px;
            border: none;
            border-radius: 5px;
        }
        button:active{
            background-color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>表白墙</h1>
        <p>输入内容后点击提交按钮,内容将显示在网页中</p>
        <div class="row">
            <span>谁:</span>
            <input type="text" class="input1">
        </div>
        <div class="row">
            <span>对谁:</span>
            <input type="text" class="input2">
        </div>
        <div class="row">
            <span>说什么:</span>
            <input type="text" class="input3">
        </div>
        <div class="row">
            <button id="submit">提交</button>
        </div>
        <div class="row">
            <button id="reverse">撤销</button>
        </div>
        
    </div>
    
    <script>
        let containerDiv = document.querySelector('.container');
        let button = document.querySelector('#submit');
        button.onclick = function(){
            //获取输入框的内容
            let inputs = document.querySelectorAll('input');
            let from = inputs[0].value;
            let to = inputs[1].value;
            let message = inputs[2].value;
            //输入框有一个为空直接结束
            if(from == '' || to == '' || message == ''){
                return;
            }
            //构造新输出
            let resultDiv = document.createElement('div');
            resultDiv.className = 'row message';
            resultDiv.innerHTML = from + ' 对 ' +  to + ' 说:' + message;
            containerDiv.appendChild(resultDiv);

            //清空输入框
            for(let elem of inputs){
                elem.value = '';
            }
        }

        //撤销
        let reverse = document.querySelector('#reverse');
        reverse.onclick = function(){
            let outputs = document.querySelectorAll('.message');
            containerDiv.removeChild(outputs[outputs.length - 1]);
        }

    </script>
</body>
</html>

前后端约定,以json字符串来发送数据,Post方法向后端发送数据并存储到数据库中,Get方法查询数据库,得到数据返回给前端。

1.修改前端代码:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>
    <style>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container{
            width: 600px;
            margin: 0 auto;
        }
        h1{
            margin-top: 10px;
            text-align: center;
        }
        p{
            margin: 10px 0;
            color: #666;
            text-align: center;
        }
        .row{
            display: flex;
            justify-content: center;
            align-items: center;
            height: 40px;
        }
        .row span{
            align-items: center;
            width: 80px;
            
        }
        .row input{
            width: 200px;
            height: 30px;
        }
        button{
            color: white;
            background-color: orange;
            width: 280px;
            height: 34px;
            border: none;
            border-radius: 5px;
        }
        button:active{
            background-color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>表白墙</h1>
        <p>输入内容后点击提交按钮,内容将显示在网页中</p>
        <div class="row">
            <span>谁:</span>
            <input type="text" class="input1">
        </div>
        <div class="row">
            <span>对谁:</span>
            <input type="text" class="input2">
        </div>
        <div class="row">
            <span>说什么:</span>
            <input type="text" class="input3">
        </div>
        <div class="row">
            <button id="submit">提交</button>
        </div>
        <div class="row">
            <button id="reverse">撤销</button>
        </div>
        
    </div>

    <!-- 引入jquery -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script>
        let containerDiv = document.querySelector('.container');
        let button = document.querySelector('#submit');
        button.onclick = function(){
            //获取输入框的内容
            let inputs = document.querySelectorAll('input');
            let from = inputs[0].value;
            let to = inputs[1].value;
            let message = inputs[2].value;
            //输入框有一个为空直接结束
            if(from == '' || to == '' || message == ''){
                return;
            }
            //构造新输出
            let resultDiv = document.createElement('div');
            resultDiv.className = 'row message';
            resultDiv.innerHTML = from + ' 对 ' +  to + ' 说:' + message;
            containerDiv.appendChild(resultDiv);

            // [新增部分]将数据传送给后端
            let body = {
                from:from,
                to:to,
                message:message
            }
            $.ajax({
                type:'post',
                url:"message",
                //将js对象转为json字符串
                contentType:'applocation/json;charset=utf8',
                data:JSON.stringify(body),
                success:function(body){

                }
            })

            //清空输入框
            for(let elem of inputs){
                elem.value = '';
            }
        }

        //撤销
        let reverse = document.querySelector('#reverse');
        reverse.onclick = function(){
            let outputs = document.querySelectorAll('.message');
            containerDiv.removeChild(outputs[outputs.length - 1]);
            $.ajax({
                type:'delete',
                url:'message',
                success:function(body){

                }
            })
        }


        //[新增部分]刷新页面时从服务器获取数据并显示
        $.ajax({
            type:'get',
            url:'message',
            success:function(body){
                //此处的body就是从服务器获得的json字符串,jquery的ajax可以自动将其转为js对象
                for(let message of body){
                    let containerDiv = document.querySelector('.container');
                    let resultDiv = document.createElement('div');
                    resultDiv.className = 'row message';
                    resultDiv.innerHTML = message.from + ' 对 ' +  message.to + ' 说:' + message.message;
                    containerDiv.appendChild(resultDiv);
                    }
            }
        })

    </script>
</body>
</html>

2.创建数据库并包装数据库

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

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ZWQ
 * Date: 2023-08-15
 * Time: 16:25
 */
public class DBUtil {
    //实现对数据库的封装
    private static DataSource dataSource = new MysqlDataSource();

    static{
        //数据库初始化
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java106?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
```
```

3. 后端代码


import com.fasterxml.jackson.databind.ObjectMapper;

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

/**

  • Created with IntelliJ IDEA.
  • Description:
  • User: ZWQ
  • Date: 2023-08-15
  • Time: 15:59 */

@WebServlet("/message") public class WallServlet extends HttpServlet { private ObjectMapper objectMapper = new ObjectMapper();

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //该方法主要是从数据库中查询数据并返回给前端页面
    resp.setContentType("application/json; charset=utf8");
    objectMapper.writeValue(resp.getWriter(),load());
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //该方法主要是向数据库存数据
    //将前端给的json字符串转为message对象
    Message message = objectMapper.readValue(req.getInputStream(),Message.class);
    save(message);
    resp.setStatus(200);
}

@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}

//数据库增加代码
private void save(Message message){
    Connection connection = null;
    PreparedStatement statement = null;

    try {
        connection = DBUtil.getConnection();
        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);
        statement.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        DBUtil.close(connection,statement,null);
    }
}

//数据库查询代码
private List<Message> load(){
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    List<Message> messageList = new ArrayList<>();

    try {
        connection = DBUtil.getConnection();
        String sql = "select * from message";
        statement = connection.prepareStatement(sql);
        resultSet = statement.executeQuery();
        while(resultSet.next()){
            Message message = new Message();
            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);
    }
    return messageList;
}

}

class Message{ public String from; public String to; public String message; }

Session

session是服务器的存储机制,专门用来存储用户的身份信息。

image.png

image.png

image.png