【JAVA】Servlet开发

目录

HttpServlet

HttpServletRequest

 HttpServletResponse

错误页面

设置网页自动刷新时间

构造重定向相应

js发起http请求 

服务器端对js发起的http请求进行处理

前端获取后端数据,添加到当前页面的末尾,代码示例: 

 前后端交互:引入数据库(存储数据)

1)引入数据库依赖

​编辑

​编辑2)建库建表

3)编写数据库代码

整体代码 

利用Cookie和Session实现登录逻辑

1.登录页面(html)

2.通过一个Servlet处理上述的登录请求

3.网站主页,通过另一个servlet生成的动态页面


掌握如下三个类,就可以完成Servlet的大部分开发了

  1. HttpServlet
  2. HttpServletRequest
  3. HttpServletResponse

URI:唯一资源标识符

URL:唯一资源定位/地址符

HttpServlet

HttpServlet继承这个类,重写里面的方法,目的就是为了把咱们子集定义的代码,“插入到”tomcat中,HttpServlet的常用方法如下:

方法名称
调用时机
init
HttpServlet 实例化之后被调用一次,初始化
destory
HttpServlet 实例不再使用的时候调用一次,释放资源
service
收到 HTTP 请求的时候调用
doGet
收到 GET 请求的时候调用 ( service 方法调用 )
doPost
收到 POST 请求的时候调用 ( service 方法调用 )
doPut/doDelete/doOptions/...
收到其他请求的时候调用 ( service 方法调用 )
我们实际开发的时候主要重写 doXXX 方法 , 很少会重写 init / destory / service
init还是比较有用的;service一般会doGet/doPost替代;destory一般用不上,说了不算,算了不说,因为一个Servlet不用了,说明Tomcat要关闭了,而Tomcat关闭有两种方式:
  1. 直接干掉Tomcat进程,完全来不及调用destory的;
  2. 通过8005管理端口,给Tomcat发送一个“停机”指令,这个时候是能够执行destory的。

init / destory / service 这三个方法都不需要手动调用,会被tomcat在合适的时机,自动调用,咱们写好代码,让别人来帮忙调用,这种方式就叫做 “框架” ,也就是一个程序的主体部分,都已经被其他大佬们写完了,有些细节内容,允许咱们插入咱们自己写的自定义的逻辑.

HttpServletRequest

Tomcat 通过 Socket API 读取 HTTP 请求 ( 字符串 ), 并且按照 HTTP 协议的格式把字符串解析成
HttpServletRequest 对象 .
核心方法
方法
描述
String getProtocol()
返回请求协议的名称和版本。
String getMethod()
返回请求的 HTTP 方法的名称,例如, GET POST PUT
String getRequestURI()
从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该
请求的 URL 的一部分。
String getContextPath()
返回指示请求上下文的请求 URI 部分。
String getQueryString()
返回包含在路径后的请求 URL 中的查询字符串。
InputStream
getInputStream()
用于读取请求的 body 内容 . 返回一个 InputStream 对象 .
Enumeration
getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名
称。
String getParameter(String
name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回
null
String[]
getParameterValues(String
name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,
如果参数不存在则返回 null
Enumeration
getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String
name)
以字符串形式返回指定的请求头的值。
String
getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
String getContentType()
返回请求主体的 MIME 类型,如果不知道类型则返回 null
int getContentLength()
以字节为单位返回请求主体的长度,并提供输入流,或者如果
长度未知则返回 -1

上述的方法都是get系列方法(都是读方法),没有set系列(没有写方法),当前拿到的HttpServletRequest,这些数据的内容已经确定下来了,程序员是不应该修改的.

前端将数据交给后端

除了query string之外,还可以通过http请求的body来传递参数(POST)。

(1)直接通过form表单

        (body的格式就是query string的格式)

        Content-Type:application/x-www-form-urlencoded

(2)直接使用json

        (body的格式就是json)

        Content-Type:application/json

这三种方式本质上是等价的,都是把键值对数据交给服务器,前两种方法servlet天然支持的,json这种方法需要引入第三方库。

在java中,json的第三方库是非常多的,这里我们使用jackson(jackson是spring官方推荐的库,也被spring集成起来了)

步骤如下:

1)下载导入jackson到项目中,通过maven

Maven Repository: Search/Browse/Explore (mvnrepository.com)

(2)使用jackson

一个类两个方法

ObjectMapper

  • 把json字符串,映射成java的一个对象(read方法)
  • 把一个java对象,映射成json字符串(write方法)
Request request = objectMapper.readValue(req.getInputStream(),Request.class);

1.核心工作就是把json字符串,映射成java 对象,参数就是json字符串(json字符串是在http的body中的,就需要通过HttpServletRequest中的getInputStream来获取到)

此处把这个流对象直接传给readValue,readValue内部就会读取InputStream中的所有数据(http请求的body,也就是json字符串),进一步尝试解析

2.按照json的格式,进行解析,把json字符串,解析成map(键值对)

3.把map转换成对象,在方法的第二个参数

如下示例:

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.io.ObjectInputValidation;


class Request()
{
    public String username;
    public String password;
}
class Response{
    public boolean ok;
}

@WebServlet("/json")
public class JsonParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Request request = objectMapper.readValue(req.getInputStream(),Request.class);
        System.out.println("username="+request.username);
        System.out.println("password="+request.password);

        Response response=new Response();
        response.ok=true;
        //把响应对象转成json字符串
        String respJson=objectMapper.writeValueAsString(response);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

 HttpServletResponse

        Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应 , 然后把响应的数据设置到
HttpServletResponse 对象中 . 然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式 , 转成一个字符串 , 并通过 Socket 写回给浏览器 .

核心方法

方法
描述
void setStatus(int sc)
为该响应设置状态码
void setHeader(String name, String value)
设置一个带有给定的名称和值的 header. 如果 name 已经存在 , 则覆盖旧的值
void addHeader(String
name, String value)
添加一个带有给定的名称和值的 header. 如果 name 已经存在 , 不覆盖旧的值, 并列添加新的键值对
void setContentType(String type)
设置被发送到客户端的响应的内容类型。
void setCharacterEncoding(String
charset)
设置被发送到客户端的响应的字符编码( MIME 字符集)例如,UTF-8
void sendRedirect(String location)
使用指定的重定向位置 URL 发送临时重定向响应到客户端
PrintWriter getWriter()
用于往 body 中写入文本格式数据
OutputStream getOutputStream()
用于往 body 中写入二进制格式数据

错误页面

resp.sendError(404,"这个页面是一个错误页面")

设置网页自动刷新时间

resp.setHeader("refresh","1");

构造重定向相应

resp.setStatus(302);
resp.setHeader("Location","https://www.baidu.com");

header需要有一个Location属性,描述要跳转到哪里 ,除了这种写法外,还有如下另一种方法:

resp.sendRedirect("https://www.baidu.com");

使用ajax,需要先引入JQeury第三方库

jquery (v3.7.1) - jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单。 | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务icon-default.png?t=N7T8https://www.bootcdn.cn/jquery/

链接如上,选择如下链接

在script标签引入jquery

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

js发起http请求 

        // 把用户填写的内容,发送给服务器,让服务器来保存
        // $ 是jquery提供的全局变量,ajax是$的一个方法
        // ajax的参数是一个js对象,可以有很多属性
        let body={
            "from":from,
            "to":to,
            "message":message
        }
        //上述body是一个js对象,还需要转换成json字符串
        let jsonString = JSON.stringify(body)
        $.ajax({
            type:'post',
            url:'message',
            contentType:'application/json; charset=utf8',
            data:jsonString,
            //这里的body与上面的body不是同一个,是响应报文的正文
            success:function(body){
                // 这个回调就是收到响应之后要执行的代码了
            }

        });

此处success回调函数,不是立即执行的,而是在浏览器收到服务器返回的成功这样的响应的时候,才会执行function ,这个函数的第一个参数,是响应数据的body中的内容。

服务器端对js发起的http请求进行处理

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.util.ArrayList;

class Message{
//    确保java代码中类的属性名字和json中的属性名字保持一致,才能够自动填充
    public String from;
    public String to;
    public String message;

    @Override
    public String toString() {
        return "Message{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", message='" + message + '\'' +
                '}';
    }
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    private List<Message> messageList = new ArrayList<>();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用jackson读取前端发来的数据,把这个数据保存到服务器这边
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        System.out.println("请求中收到的message:"+ message);
        //保存数据最简单的是直接内存中存储,使用集合类
        //但是这样做一旦重启服务器,一切数据都没有了,一般存储到数据库中
        messageList.add(message);
        //返回一个响应
        resp.setStatus(200);
        resp.getWriter().write("ok");
    }
}

这里启动服务器后,不能直接访问/message,需要访问.html路径

当浏览器要向服务器获取资源, 服务器方使用List类型的数组存储历史数据,转成的json字符串就是一个json数组,jackson自动遍历List里的每个元素,把每个元素分别转成json字符串。

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(200);
        resp.setContentType("application/json;charset=utf-8");
        String respJson = objectMapper.writeValueAsString(messageList);
        resp.getWriter().write(respJson);
    }

上述代码setStatus和setContentType必须在getWriter前面,否则不会生效 

    $.ajax{

        type:'get',

        url:'message',

        success:function(body){

            //处理服务器返回的响应数据。(json格式的数组)

        }

    }

//当响应中,header带有ContentType:"application/json",JQuery就会自动把json字符串解析成js对象了,如果没有带ContentType:"application/json"就需要通过js代码JSON.parse方法手动把json字符串转成js对象

前端获取后端数据,添加到当前页面的末尾,代码示例: 

    $.ajax{
        type:'get',
        url:'message',
        success:function(body){
            //处理服务器返回的响应数据。(json格式的数组)
            //由于响应中已经有ContentType:"application/json"了,就不需要使用parse方法手动转换了
            //body = JSON.parse(body);
            
            //拿到 container这个元素
            let containerDiv = document.querySelector('.container');
            //处理服务器返回的响应数据。(json格式的数组了)
            for(let i=0;i<body.length;i++)
            {
                //body是一个数组,此时的message也就是js对象了
                //这个message对象里有三个属性:from、to、message
                let message = body[i];
                
                //根据message对象构建html片段,把这个片段给显示到网页上
                //createElement 方法就能构造一个html标签
                //此时就得到了<div></div>
                let div = document.createElement('div');
                //还需要给这个div设置一个属性
                div.className = 'row';
                //设置内容
                div.innerHTML = message.from + " 对 " + message.to + " 说:" +message.message;
                //将这个div添加到containerDiv末尾
                containerDiv.appendChild(div);
            }
        }

 前后端交互:引入数据库(存储数据)

1)引入数据库依赖

Maven仓库链接

Maven Repository: Search/Browse/Explore (mvnrepository.com)

搜索MySQL,选择如下:

这里选择5.1.47版本

复制如下代码

复制到pom.xml里


2)建库建表

create database if not exists message_wall charset utf8;
use message_wall;
-- 删表的目的是为了防止之前数据库里有一样的表
drop table if exists message;
use message_wall;
create table message(`from` varchar(1024),`to` varchar(1024),message varchar(1024));

3)编写数据库代码

// 1. 创建数据源
private DataSource dataSource = new MysqlDataSource();
((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3307/message_wall?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("root");
// 2. 建立连接
Connection connection = dataSource.getConnection();

// 3. 构造 SQL
String sql = "insert into message values(?, ?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, message.from);
statement.setString(2, message.to);
statement.setString(3, message.message);

// 3. 执行 SQL
statement.executeUpdate();

// 4. 回收资源
statement.close();
connection.close();

整体代码 

MessageServlet.java

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 javax.sql.DataSource;
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;

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

    @Override
    public String toString() {
        return "Message{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", message='" + message + '\'' +
                '}';
    }
}

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

    // 引入数据库, 此时 messageList 就不再需要了.
    // private List<Message> messageList = new ArrayList<>();

    private DataSource dataSource = new MysqlDataSource();

    @Override
    public void init() throws ServletException {
        // 1. 创建数据源
        ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3307/message_wall?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("root");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 读取前端发来的数据, 把这个数据保存到服务器这边.
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        System.out.println("请求中收到的 message: " + message);
        // 最简单的办法, 直接在内存中保存. 可以使用一个集合类, 把所有收到的 message 都存到内存中.
        // 很明显, 保存到内存, 并非是一个非常合理的办法. 后续一旦重启服务器, 数据丢失了.
        // 相比之下, 把这个数据持久化存储到数据库中, 更科学的.
        // messageList.add(message);
        // 插入数据库
        try {
            save(message);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        // 返回一个响应
        resp.setStatus(200);
        resp.getWriter().write("ok");
        // resp.setContentType("application/json");
        // resp.getWriter().write("{ ok: true }");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理当前获取消息列表的 get 请求. 不需要解析参数, 直接返回数据即可.
        resp.setStatus(200);
        resp.setContentType("application/json; charset=utf8");
        // 从数据库查询
        List<Message> messageList = null;
        try {
            messageList = load();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        String respJson = objectMapper.writeValueAsString(messageList);
        resp.getWriter().write(respJson);
    }

    private void save(Message message) throws SQLException {
        // 通过这个方法把 message 插入到数据库中

        // 1. 建立连接
        Connection connection = dataSource.getConnection();

        // 2. 构造 SQL
        String sql = "insert into message values(?, ?, ?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, message.from);
        statement.setString(2, message.to);
        statement.setString(3, message.message);

        // 3. 执行 SQL
        statement.executeUpdate();

        // 4. 回收资源
        statement.close();
        connection.close();
    }

    private List<Message> load() throws SQLException {
        // 通过这个方法从数据库读取到 message.

        // 1. 建立连接
        Connection connection = dataSource.getConnection();

        // 2. 构造 SQL
        String sql = "select * from message";
        PreparedStatement statement = connection.prepareStatement(sql);

        // 3. 执行 sql
        ResultSet resultSet = statement.executeQuery();

        // 4. 遍历结果集合
        List<Message> messageList = new ArrayList<>();
        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);
        }

        // 5. 回收资源
        resultSet.close();
        statement.close();
        connection.close();

        // 6. 返回 messageList
        return messageList;
    }
}

 message_wall.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <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: 20px auto;
        }

        h1 {
            text-align: center;
        }

        p {
            text-align: center;
            color: #666;
            margin: 20px 0;
        }

        .row {
            /* 开启弹性布局 */
            display: flex;
            height: 40px;
            /* 水平方向居中 */
            justify-content: center;
            /* 垂直方向居中 */
            align-items: center;
        }

        .row span {
            width: 80px;
        }

        .row input {
            width: 200px;
            height: 30px;
        }

        .row button {
            width: 280px;
            height: 30px;
            color: white;
            background-color: orange;
            /* 去掉边框 */
            border: none;
            border-radius: 5px;
        }

        /* 点击的时候有个反馈 */
        .row button:active {
            background-color: grey;
        }
    </style>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
    <h1>表白墙</h1>
    <p>输入内容后点击提交, 信息会显示到下方表格中</p>
    <div class="row">
        <span>谁: </span>
        <input type="text">
    </div>
    <div class="row">
        <span>对谁: </span>
        <input type="text">
    </div>
    <div class="row">
        <span>说: </span>
        <input type="text">
    </div>
    <div class="row">
        <button id="submit">提交</button>
    </div>
    <!-- <div class="row">
        xxx 对 xx 说 xxxx
    </div> -->
</div>

<script>
    // 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示.
    // 点击的时候, 获取到三个输入框中的文本内容
    // 创建一个新的 div.row 把内容构造到这个 div 中即可.
    let containerDiv = document.querySelector('.container');
    let inputs = document.querySelectorAll('input');
    let button = document.querySelector('#submit');
    button.onclick = function() {
        // 1. 获取到三个输入框的内容
        let from = inputs[0].value;
        let to = inputs[1].value;
        let msg = inputs[2].value;
        if (from == '' || to == '' || msg == '') {
            return;
        }
        // 2. 构造新 div
        let rowDiv = document.createElement('div');
        rowDiv.className = 'row message';
        rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
        containerDiv.appendChild(rowDiv);
        // 3. 清空之前的输入框内容
        for (let input of inputs) {
            input.value = '';
        }
        // 4. 把用户填写的内容, 发送给服务器. 让服务器来保存.
        //    $ 是 jquery 提供的全局变量. ajax 就是 $ 的一个方法.
        //    ajax 的参数是一个 js 对象, 可以有很多属性
        let requestBody = {
            "from": from,   // from 变量里的值, 就是第一个输入框的内容, "张三"
            "to": to,       // to 变量的值, 就是第二个输入框的内容, "李四"
            "message": msg  // msg 变量的值, 就是第三个输入框的内容, "我喜欢你很久了"
        };
        // 上述 body 是一个 js 对象, 还需要转成 json 字符串.
        let jsonString = JSON.stringify(requestBody);
        $.ajax({
            type: 'post',
            url: 'message',
            contentType: 'application/json; charset=utf8',
            data: jsonString,
            success: function(responseBody) {
                // 这个回调就是收到响应之后要执行的代码了.
                // 前端使用 console.log 打印日志到控制台. (chrome 开发者工具的控制台)
                console.log("responseBody: " + responseBody);
            }
        });
    }

    // 直接在 script 里面写的 js 代码, 就是在页面加载时被执行到的.
    // 发起一个 get 请求, 从服务器获取到数据
    // get 请求不需要 body, 也就不需要上述 data 和 contentType 属性了.
    $.ajax({
        type: 'get',
        url: 'message',
        success: function(body) {
            // 由于响应中已经有 Content-Type: application/json 了, 就不需要使用 parse 方法手动转换了.
            // body = JSON.parse(body);

            // 拿到 container 这个元素
            let containerDiv = document.querySelector('.container');
            // 处理服务器返回的响应数据. (json 格式的数组了)
            for (let i = 0; i < body.length; i++) {
                // body 是一个数组, 此时 message 也就是 js 对象了.
                // 这个 message 对象里, 有三个属性, from, to, message
                let message = body[i];

                // 根据 message 对象构建 html 片段, 把这个片段给显示到网页上.
                // createElement 方法就能构造出一个 html 标签.
                // 此时就得到了 <div></div>
                let div = document.createElement('div');
                // 还需要往里面设置一个 属性 , class="row" (设置这个属性, 是为了让 css 能够给这个元素设置一些样式)
                // 此时就得到了 <div class="row"></div>
                div.className = 'row';
                // 给这个 div 里设置内容
                // 此时就得到了 <div class="row">张三 对 李四 说: 我喜欢你很久了</div>
                div.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
                // 把 div 添加到 containerDiv 的末尾
                containerDiv.appendChild(div);
            }
        }
    });
</script>
</body>
</html>

利用Cookie和Session实现登录逻辑

Cookie是客户端存储数据的机制

Session是服务器存储数据的机制(不算持久化存储)

1.登录页面(html)

2.通过一个Servlet处理上述的登录请求

通过这个Servlet读取用户名和密码,并且验证是否登录成功。

如果登陆成功,就会给当前用户,创建一个会话 ,并且把得到的sessionid,通过cooki返回给客户端,客户端就把cookie保存起来了。

3.网站主页,通过另一个servlet生成的动态页面

在这个页面中,就会把刚才这里的用户数据给显示到页面上。

getSession(true)

这个方法,就是根据请求的cookie中的sessionid,查询服务器的hash表,找到对应的session对象。如果cookie中没有sessionid(首次登录的时候,就是没有的)或者sessionid没有查找到对应的session对象,就可以创建出一个session对象出来。

参数为true,允许不存在时自动创建;false不能创建,直接返回null

//可以给会话中保存一些自定义的数据,通过Attribute的方式来保存
HttpSession session = req.getSession(true);
//此处Atrribute也是键值对,这里的内容存储什么都可以
session.setAttribute("username",username);
session.setAttribute("loginTime",System.currentTimeMillis());
//此处相当于登录成功,让页面跳转网站首页
resp.sendRedirect("index");

此处的getSession会创建新会话

1)生成sessionid和HttpSession对象

2)把上述sessionid和HttpSession对象保存到内存hash表中

3)把sessionid设置到响应报文的header中的 Set-Cookie字段

浏览器拿到响应,就会把这个Set-Cookie的内容保存到浏览器的Cookie中 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/467069.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

24计算机考研调剂 | 【官方】山东师范大学(22自命题)

山东师范大学2024年拟接收调剂 考研调剂信息 调剂专业目录如下&#xff1a; 计算机技术&#xff08;085404&#xff09;、软件工程&#xff08;085405&#xff09; 补充内容 我校2024年硕士研究生调剂工作将于4月8日教育部“中国研究生招生信息网”&#xff08;https://yz.ch…

如何使用代理IP进行口子查和渠道查:代理IP使用方法

在进行问卷调查时&#xff0c;为了避免被限制访问或被封禁IP&#xff0c;使用代理IP已经成为了必要的选择。 其中&#xff0c;口子查和渠道查也不例外。 使用代理IP可以隐藏本机IP地址&#xff0c;模拟不同的IP地址&#xff0c;从而规避被封禁的风险。但是&#xff0c;对于很…

3.Gen<I>Cam文件配置

Gen<I>Cam踩坑指南 我使用的是大恒usb相机&#xff0c;第一步到其官网下载大恒软件安装包,安装完成后图标如图所示&#xff0c;之后连接相机&#xff0c;打开软件&#xff0c;相机显示一切正常。之后查看软件的安装目录如图&#xff0c;发现有GenICam和GenTL两个文件&am…

2024全新红娘交友系统定制版源码 | 相亲交友小程序源码 全开源可二开

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 全新红娘交友系统定制版源码 | 相亲交友小程序源码 全开源可二开 定制版红娘交友平台小程序源码&#xff0c;很牛逼的东西&#xff0c;虽然是小程序&#xff0c;但是有700多M大&…

【办公类-22-11】周计划系列(5-3)“周计划-03 周计划内容循环修改“ (2024年调整版本)

背景需求&#xff1a; 前文从原来的“新模版”文件夹里提取了周计划主要内容和教案内容。 【办公类-22-10】周计划系列&#xff08;5-2&#xff09;“周计划-02源文件docx读取5天“ &#xff08;2024年调整版本&#xff09;-CSDN博客文章浏览阅读1.1k次&#xff0c;点赞29次&…

苍穹外卖-day10:Spring Task、订单状态定时处理、来单提醒(WebSocket的应用)、客户催单(WebSocket的应用)

苍穹外卖-day10 课程内容 Spring Task订单状态定时处理WebSocket来单提醒客户催单 功能实现&#xff1a;订单状态定时处理、来单提醒和客户催单 订单状态定时处理&#xff1a; 来单提醒&#xff1a; 客户催单&#xff1a; 1. Spring Task 1.1 介绍 Spring Task 是Spring框…

el-form 的表单校验,如何验证某一项或者多项;validateField 的使用

通常对form表单的校验都是整体校验&#xff1a; this.$refs.form.validate( valid > {if (valid) {// 校验通过&#xff0c;业务逻辑代码...} }); 如果需要对表单里的特定一项或几项进行校验&#xff0c;应该如何实现&#xff1f; 业务场景&#xff1a;下图点探测按钮时…

高精度计算

主页&#xff1a;(*∇&#xff40;*) 咦,又好了~ xiaocr_blog &#xff08;1&#xff09;数据的接收方法和存储方法: 当输入的数据很长的时候&#xff0c;可采取字符串方式输入&#xff0c;这样可以输入位数很长的数&#xff0c;利用字符串函数和操作运算&#xff0c;将每一位…

复杂网络——半局部中心法

一、概述 由于最近写论文需要使用复杂网络知识中的半局部中心法&#xff0c;但是截止目前来说&#xff0c;网上几乎搜索不到有关的MATLAB程序代码&#xff0c;只有一篇用Python编写的程序&#xff0c;我的电脑中没有python&#xff0c;所以我花费一些时间&#xff0c;利用matla…

Excel数据可视化

饼图 1、选中数据----点击插入----点击饼图 2、更改数据标签&#xff08;修改标题名直接改就行&#xff09; 柱形图 1、选中数据、点击插入二维柱形图 坐标轴问题----切换行和列 如何将横轴变成想要的4、5、6、7月&#xff1f; &#xff08;1&#xff09;右键----选择数据 -…

计算机二级(Python)真题讲解每日一题:《十字叉》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ ‪‬‪‬‪‬‪‬‪‬‮‬‪…

Java解决完全二叉树的节点个数

Java解决完全二叉树的节点个数 01 题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的…

202303 CSP认证 | LDAP

LDAP 好好好&#xff0c;难度直线上升&#xff0c;是一道又有了字符串处理味道的第三题 第一把写官网40分&#xff0c;acwing TLE且只通过了一道数据…本文是自己这题奋斗过程 的一个记录 先贴个40分的代码&#xff1a; #include<bits/stdc.h> using namespace std; t…

计算机网络:性能指标

计算机网络&#xff1a;性能指标 速率带宽吞吐量时延时延带宽积往返时间利用率丢包率 本博客介绍计算机网络的性能指标&#xff0c;我们可以从不同的方面来度量计算机网络的性能。常用的计算机网络性能指标有以下 8 个&#xff0c;他们是&#xff1a;速率、带宽、吞吐量、时延、…

Android弹出通知

发现把Android通知渠道的重要性设置为最高时&#xff0c;当发送通知时&#xff0c;通知能直接弹出来显示&#xff0c;以前一直搞不明白为什么别的app的通知可以弹出来&#xff0c;我的不行&#xff0c;搞了半天原来是这个属性在作怪&#xff0c;示例如下&#xff1a; class Ma…

Flink源码解析(1)TM启动

网络传输模型 首先在看之前,回顾一下akka模型: Flink通讯模型—Akka与Actor模型-CSDN博客 注:ActorRef就是actor的引用,封装好了actor 下面是jm和tm在通讯上的概念图: RpcGateway 不理解网关的作用,可以先移步看这里:网关_百度百科 (baidu.com) 用于定义RPC协议,是…

CMake学习(上)

1. CMake概述 CMake 是一个项目构建工具&#xff0c;并且是跨平台的。关于项目构建我们所熟知的还有Makefile&#xff08;通过 make 命令进行项目的构建&#xff09;&#xff0c;大多是IDE软件都集成了make&#xff0c;比如&#xff1a;VS 的 nmake、linux 下的 GNU make、Qt …

论文解读之Attention-based Deep Multiple Instance Learning

前言 多实例学习是由监督学习演变而来的&#xff0c;我们都知道&#xff0c;监督学习在训练的时候是一个实例&#xff08;或者说一个样本、一条训练数据&#xff09;对应一个确定的标签。而多实例的特点就是&#xff0c;我们在训练的时候的输入是多个实例对应一个确定的标签&a…

STM32使用常见错误合集(正在更新版)

本文章记录一些学习STM32的一些错误问题 一、编译、烧录类问题 1、烧录不成功&#xff0c;Keil提示RDDI-DAP Error【场景&#xff1a;PWM驱动直流电机】 解决方案&#xff1a;将电机断开再进行烧录&#xff0c;断开后就可以美美烧录不报错啦~ 二、Keil使用问题 1、打开一个…

【设计模式】-工厂模式

工厂模式是一种创建型设计模式&#xff0c;它提供了一种在不指定具体类的情况下创建对象的方法。工厂模式的核心思想是将对象的创建与使用分离&#xff0c;降低系统的耦合度&#xff0c;使系统更加灵活、可扩展。 工厂模式主要分为三种类型&#xff1a;简单工厂模式、工厂方法…