Json Web Token(JWT) 快速入门

推荐视频:【从零开始掌握JWT】

目录

第一章 会话跟踪

01  使用Cookie和Session,jsessionid

02 使用token

例子一:自定义token

例子二:使用redis存储token


第一章 会话跟踪

应用背景 :浏览器访问web应用,基于HTTP协议发送报文,HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。 服务器不知道是谁发的请求。当用户在同一网站的多个页面之间转换时,需要知道用户是谁时,会话跟踪技术就可以解决这个问题。

会话跟踪主要使用的技术

URL重写,隐藏表单域,cookie,session
# 1、URL重写技术
就是在URL结尾添加一个附加数据以标识该会话,把会话ID通过URL的信息传递过去,以便在服务端进行识别不同的用户

# 2、隐藏表单域:
会话ID添加到HTML表单元素中提交到服务器,此表单不再客户端显示

# 3、cookie
Cookie是web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用。

# 4、session
在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户session是依赖Cookie的,如果cookie被禁用,那么session也将失效 ,session默认的会话时长为30分钟。

01  使用Cookie和Session,jsessionid

项目背景:进行一次请求转发,产生一次会话。 

项目场景:

  • @WebServlet 是Java Servlet规范中的注解,用于标识一个Servlet类,并指定该Servlet处理的URL模式等配置信息。
  • @ServletComponentScan 是Spring Boot提供的注解,用于扫描并注册使用@WebServlet、@WebFilter和@WebListener注解标记的Servlet、Filter和Listener类。
package com.demo.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.net.http.HttpRequest;

@WebServlet("myserlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //输出 sessionid
        System.out.println("session="+req.getSession().getId());
        // 转发到show.jsp
        req.getRequestDispatcher("/show.jsp").forward(req, resp);
    }
}
<html>
<body>
    <h2>Hello World!</h2>
</body>
<a herf="myservlet">访问servlet</a>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>show.jsp</h3>
</body>
</html>

会话id: 

 

02 使用token

token是什么?
token是什么:翻译是令牌,访问系统的凭证,令牌证明你是谁,你能做什么。


token是服务端生成的一串字符串,客户端首先请求一个令牌,当第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。


例子一:自定义token
1.创建springboot项目
2.加入依赖,spring-web依赖,jquery (webjar)
3.在static目录下创建htm1目录,新建login.html
4.login.html登录页面,获取token
5.新建Logincontroller,模拟登录业务逻辑,使用UUID生成一个token,返回给请求
6.新建main.html作为业务逻辑处理页面,定义一个查询按钮,发起ajax请求,参数有token
7.创建一个处理query的方法,使用token验证登录用户信息。根据验证结果处理其他业务。

1)加入依赖,spring-web依赖,jquery (webjar)

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.6.0</version>
        </dependency>

2)在static目录下创建html目录,新建login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <!--    从项目的 webjars 中加载了 jQuery 3.6.0 版本的库文件,通过该文件可以在页面中使用 jQuery 提供的功能和方法。-->
    <script src="/webjars/jquery/3.6.0/jquery.js"></script>
    <!--    从 BootCDN 加载了 jQuery Cookie 插件的压缩版本。该插件使得在客户端可以方便地操作和管理 cookie,比如设置、获取和删除 cookie 等操作。-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

</head>
<body>
    <div style="margin-left: 300px" >
        <h3>登录页面</h3>
        <form id="loginFrm" action="" method="post">
            用户名:<input type="text" name="name"> <br/>
            密&nbsp;码:<input type="text" name="pwd"> <br/>
            <input type="button" id="loginBtn" value="登录">
        </form>
    </div>

    <script type="text/javascript">
        $(function () {
            $("#loginBtn").on("click", function (){
                $.ajax({
                    url:"app/login",
                    type:"post",
                    data:$("#loginFrm").serialize(),
                    dataType:"json",
                    success:function (resp){
                        // 存放到cookie
                        $.cookie("accessToken",resp.data);
                        alert("resp="+resp.msg+", token="+resp.data);
                    }
                })
            })
        })
    </script>
</body>
</html>

3)login.html登录页面,获取token

  • @RequestParam("name") String name 表示从请求中获取名为 "name" 的参数的值,并将其赋给名为 name 的 String 类型变量。
  • @RequestParam("pwd") String pwd 表示从请求中获取名为 "pwd" 的参数的值,并将其赋给名为 pwd 的 String 类型变量。
  • UUID.randomUUID()UUID 类是 Java 中用于表示统一唯一标识符的类。randomUUID() 方法会生成一个新的随机 UUID 对象。

package com.example.root.controller;


import com.example.root.vo.ResultObject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class LoginController {

    Map<String,String> tokenMap = new ConcurrentHashMap<>();

    //登录方法
    @PostMapping("/app/login")
    public ResultObject login(@RequestParam("name") String name, @RequestParam("pwd") String pwd){
        ResultObject ro = new ResultObject();
        if ("lisi".equals(name) && "123".equals(pwd)){
            // 登录成功,生成token
            String token = UUID.randomUUID().toString().replaceAll("-","");
            ro.setCode(0);
            ro.setMsg("登录成功,返回token");
            ro.setData(token);

            //存储token
            tokenMap.put(token, name);


        }else{
            ro.setCode(1000);
            ro.setMsg("登录失败,没有token");
            ro.setData("");
        }

        return ro;
    }

}

分别对应Code;Msg;Token;

 

4)带上token访问前端API

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    从项目的 webjars 中加载了 jQuery 3.6.0 版本的库文件,通过该文件可以在页面中使用 jQuery 提供的功能和方法。-->
    <script src="/webjars/jquery/3.6.0/jquery.js"></script>
    <!--    从 BootCDN 加载了 jQuery Cookie 插件的压缩版本。该插件使得在客户端可以方便地操作和管理 cookie,比如设置、获取和删除 cookie 等操作。-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

</head>
<body>
    <div>
        <input type="text" name="studentId" id="studentId" value="1001"><br/>
        <input type="button" name="queryBtn" id="queryBtn" value="访问api需要带上token"><br/>
    </div>

<script type="text/javascript">
    $(function(){
        $("#queryBtn").on("click", function (){
            $.ajax({
                url:"app/query",
                type:"post",
                data:{
                    "studentId":$("#studentId").val(),
                    "accessToken":$.cookie("accessToken")
                },
                dataType:"json",
                success:function (resp){
                    alert("resp="+resp.msg);
                }
            })
        })
    })
</script>

</body>
</html>
package com.example.root.controller;


import com.example.root.vo.ResultObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class LoginController {

    Map<String,String> tokenMap = new ConcurrentHashMap<>();

    //登录方法
    @PostMapping("/app/login")
    public ResultObject login(@RequestParam("name") String name, @RequestParam("pwd") String pwd){
        ResultObject ro = new ResultObject();

        if ("lisi".equals(name) && "123".equals(pwd)){
            // 登录成功,生成token
            String token = UUID.randomUUID().toString().replaceAll("-","");
            ro.setCode(0);
            ro.setMsg("登录成功,返回token");
            ro.setData(token);

            //存储token
            tokenMap.put(token, name);

        }else{
            ro.setCode(1000);
            ro.setMsg("登录失败,没有token");
            ro.setData("");
        }

        return ro;
    }

    @PostMapping("/app/query")
    public ResultObject query(Integer studentId, String accessToken){
        ResultObject ro = new ResultObject();
        // 判断token
        if(tokenMap.containsKey(accessToken)){
            //执行业务逻辑,查询学生
            ro.setCode(0);
            ro.setMsg("执行业务逻辑是成功的");
            ro.setData("学生是id"+studentId);
        }else {
            ro.setCode(1);
            ro.setMsg("不能访问系统");
            ro.setData("");
        }
        return ro;
    }

}

例子二:使用redis存储token
  • stringRedisTemplate:这是 Spring Data Redis 提供的用于操作 Redis 数据库的模板类。
  • opsForHash():这是 StringRedisTemplate 提供的用于操作哈希表数据结构的方法,返回一个 HashOperations 对象,通过这个对象可以进行哈希表的各种操作。
  • putAll(key, map):这是 HashOperations 接口中的一个方法,用于向指定哈希表 key 中批量 添加 字段和对应的值。参数 map 是一个 Java Map 对象,其中包含要添加到哈希表中的字段和值。
  • entries(key):这是 HashOperations 接口中的一个方法,用于 获取 指定哈希表 key 中的所有字段和对应的值,并以 Map 的形式返回结果。

1)向redis存储token

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

application.properties:

# 设置redis
spring.data.redis.host=localhost
spring.data.redis.port=6379

 login2.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <!--    从项目的 webjars 中加载了 jQuery 3.6.0 版本的库文件,通过该文件可以在页面中使用 jQuery 提供的功能和方法。-->
    <script src="/webjars/jquery/3.6.0/jquery.js"></script>
    <!--    从 BootCDN 加载了 jQuery Cookie 插件的压缩版本。该插件使得在客户端可以方便地操作和管理 cookie,比如设置、获取和删除 cookie 等操作。-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

</head>
<body>
    <div style="margin-left: 300px" >
        <h3>登录页面redis</h3>
        <form id="loginFrm" action="" method="post">
            用户名:<input type="text" name="name"> <br/>
            密&nbsp;码:<input type="text" name="pwd"> <br/>
            <input type="button" id="loginBtn" value="登录">
        </form>
    </div>

    <script type="text/javascript">
        $(function () {
            $("#loginBtn").on("click", function (){
                $.ajax({
                    url:"app/redis/login",
                    type:"post",
                    data:$("#loginFrm").serialize(),
                    dataType:"json",
                    success:function (resp){
                        // 消息框
                        alert("redis resp="+resp.msg+", token="+resp.data);
                        // 存放到cookie
                        $.cookie("accessRedisToken", resp.data);
                    }
                })
            })
        })
    </script>
</body>
</html>

 LoginController2.java:

package com.example.root.controller;

import com.example.root.vo.ResultObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
public class LoginController2 {

    private String TOKEN_KEY = "TOKEN:";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    //获取token,redis存储token
    @PostMapping("/app/redis/login")
    public ResultObject loginAccessToken(@RequestParam("name") String name,
                                         @RequestParam("pwd") String pwd) {
        ResultObject ro = new ResultObject();

        // 登录处理,返回token
        if ("lisi".equals(name) && "123".equals(pwd)){
            // 登录成功,生成token
            String token = UUID.randomUUID().toString().replaceAll("-","").toUpperCase();
            // 准备数据
            Map<String,String> map = new HashMap<>();
            map.put("userId","1001");
            map.put("name","lisi");
            map.put("role","admin");
            // 其他数据


            // 存储数据到redis
            String key = TOKEN_KEY + token;
            stringRedisTemplate.opsForHash().putAll(key, map);

            // 有效会话时间 20min
            stringRedisTemplate.expire(key, 20, TimeUnit.MINUTES);

            // 返回结果
            ro.setCode(0);
            ro.setMsg("登录成功");
            ro.setData(token);
        }else {
            ro.setCode(1);
            ro.setMsg("认证失败");
            ro.setData("");
        }

        return ro;
    }

}

redis安装和配置:Window下Redis的安装和部署详细图文教程(Redis的安装和可视化工具的使用)_redis安装-CSDN博客 

注意访问:localhost:8080/login2.html

2) 从redis取数据访问前端API

main2.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--    从项目的 webjars 中加载了 jQuery 3.6.0 版本的库文件,通过该文件可以在页面中使用 jQuery 提供的功能和方法。-->
    <script src="/webjars/jquery/3.6.0/jquery.js"></script>
    <!--    从 BootCDN 加载了 jQuery Cookie 插件的压缩版本。该插件使得在客户端可以方便地操作和管理 cookie,比如设置、获取和删除 cookie 等操作。-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

</head>
<body>
    <div>
        <input type="text" name="studentId" id="studentId" value="1001"><br/>
        <input type="button" name="queryBtn" id="queryBtn" value="访问api需要带上token(redis)"><br/>
    </div>

<script type="text/javascript">
    $(function(){
        $("#queryBtn").on("click", function (){
            $.ajax({
                // 指定了AJAX请求的目标 URL到 controller类
                url:"app/redis/query",
                type:"post",
                data:{
                    "studentId":$("#studentId").val(),
                    //获取 cookie
                    "accessToken":$.cookie("accessRedisToken")
                },
                dataType:"json",
                // 设置请求成功后的处理函数
                success:function (resp){
                    alert("resp="+resp.msg);
                }
            })
        })
    })
</script>

</body>
</html>

LoginController.java:

package com.example.root.controller;

import com.example.root.vo.ResultObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
public class LoginController2 {

    private String TOKEN_KEY = "TOKEN:";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    //获取token,redis存储token
    @PostMapping("/app/redis/login")
    public ResultObject loginAccessToken(@RequestParam("name") String name,
                                         @RequestParam("pwd") String pwd) {
        ResultObject ro = new ResultObject();

        // 登录处理,返回token
        if ("lisi".equals(name) && "123".equals(pwd)){
            // 登录成功,生成token
            String token = UUID.randomUUID().toString().replaceAll("-","").toUpperCase();
            // 准备数据
            Map<String,String> map = new HashMap<>();
            map.put("userId","1001");
            map.put("name","lisi");
            map.put("role","admin");
            // 其他数据

            // 存储数据到redis
            String key = TOKEN_KEY + token;
            stringRedisTemplate.opsForHash().putAll(key, map);
            // 有效会话时间 20min
            stringRedisTemplate.expire(key, 20, TimeUnit.MINUTES);
            // 返回结果
            ro.setCode(0);
            ro.setMsg("登录成功");
            ro.setData(token);
        }else {
            ro.setCode(1);
            ro.setMsg("认证失败");
            ro.setData("");
        }

        return ro;
    }


    //模拟业务处理方法
    @PostMapping("app/redis/query")
    public ResultObject query(Integer studentId, String accessToken){
        ResultObject ro = new ResultObject();

        // 检查token
        String key = TOKEN_KEY + accessToken;
        if(stringRedisTemplate.hasKey(key)){
            // 获取redis存储数据,userId,role等
            Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(key);
            String userId = (String) map.get("userId");
            String role = (String) map.get("role");
            String name = (String) map.get("name");
            // 处理业务逻辑
            if("admin".equals(role)){
                ro.setCode(0);
                ro.setMsg("可以执行admin的操作");
                ro.setData("执行查询学生是"+studentId+"姓名是:"+name);
            }

        }
        return ro;


    }

}

第二章 会用JWT

TOKEN的特点 :

1. 无状态,可扩展。无需session,可以把token数据从一个服务传递到其他服务,从网关发送到其他服务也很容易。
2. 安全性,token是可以进行加密处理,不存储敏感数据,而且token有实效的,有过期的,过期后需要重写验证。
3. 可扩展,token能实现不同应用之间的通信。 比如使用token访问第三方应用。
4. 跨平台,现代化的应用可能接入不同的设备和其他应用。使用一个有效 token可以在手机app,web应用等访问应用。

JWT规范,允许我们使用JWT在两个组织之间传递安全可靠的信息。 

 JWT是一个凭证

JWT的工作原理

用户先到服务器认证身份,认证后服务器返回一个json,就像这个样子。

以后用户再发起请求,就是带着这个ison数据,服务器拿这个ison对象确定用户身份,判断用户能执行操作,获取数据。为了防止用户篡改数据,服务器在生成这个json对象的时候,会加上签名

服务器就不保存任何 session 数据了,也无需使用redis存储,服务器变成无状态了,从而比较容易实现扩展。

什么时候使用JWT:

1)授权Authorization:这是使用WT的最常见方案。用户登录后,每个后续请求都将包含JWT,从而允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用IWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用。
2)信息交换(Information Exchange):JSON Web令牌是在各方之间安全地传输信息的一种好方法。因为可以对]WT进行签名(例如,使用公钥/私钥对),所以您可以确保发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被算改。
3)客户端会话(无Session)。

  • HttpServlet 是Java Servlet API 的一个抽象类,用于处理来自客户端的HTTP请求并生成HTTP响应。开发人员可以通过继承HttpServlet类并重写其中的doGet()、doPost()等方法来处理特定的HTTP请求。
    • doGet(HttpServletRequest request, HttpServletResponse response): 处理HTTP GET请求的方法。开发人员可以重写这个方法来处理GET请求,并生成相应的响应。
    • doPost(HttpServletRequest request, HttpServletResponse response): 处理HTTP POST请求的方法。开发人员可以重写这个方法来处理POST请求,并生成相应的响应。
    • doPut(HttpServletRequest request, HttpServletResponse response): 处理HTTP PUT请求的方法。
    • doDelete(HttpServletRequest request, HttpServletResponse response): 处理HTTP DELETE请求的方法。
      • HttpServletRequest常用方法:

        • getParameter(String name): 获取HTTP请求中的参数值。
        • getMethod(): 获取HTTP请求的方法,如GET、POST等。
        • getRequestURL(): 获取请求的URL。
        • getSession(): 获取与该请求关联的会话,如果没有会话存在,则创建一个新的会话。
        • getHeader(String name): 获取指定名称的请求头的值。
        • getCookies(): 获取包含该请求的所有Cookie的数组。
      • HttpServletResponse常用方法:

        • setContentType(String type): 设置响应的内容类型。
        • setStatus(int sc): 设置响应的状态码(如200、404等)。
        • getWriter(): 返回一个PrintWriter对象,用于向客户端发送文本数据。
        • sendRedirect(String location): 发送一个重定向响应到指定的URL。
        • addHeader(String name, String value): 添加一个响应头。
        • setCookie(Cookie cookie): 将Cookie添加到响应中。

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

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

相关文章

Android 13 源码编译及报错修复

下载AOSP指定分支 repo init -u git://aosp../platform/manifest -b android-13.0.0_r83 同步代码到本地 repo sync -c 初始化编译环境, 选择构建目标 source build/envsetup.sh lunch 选择需要构建的目标&#xff0c;此处以aosp_arm64-eng为例 进行固件编译 make -j12 期间编译…

【C++庖丁解牛】继承的概念及定义 | 继承中的作用域 | 继承与友元继承与静态成员 | 复杂的菱形继承及菱形虚拟继承

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.继承的概念及定义1.1继…

Ubuntu双系统/home分区扩容

一、Windows系统中利用磁盘管理分出空闲区域&#xff0c;如果多就多分一些 二、插入安装Ubuntu的U盘启动盘&#xff0c;lenovo电脑F12&#xff08;其他电脑可选择其他类似方式&#xff09;选择U盘启动项&#xff0c;然后选择ubuntu&#xff0c;出现安装界面&#xff0c;再选择t…

clipboard好用的复制剪切库

clipboard是现代复制到剪贴板的工具&#xff0c;其 gzip 压缩后只有 3kb&#xff0c;能够减少选择文本的重复操作&#xff0c;点击按钮就可以复制指定内容&#xff0c;支持原生HTMLjs&#xff0c;vue3和vue2。使用方法参照官方文档&#xff0c;so easy&#xff01;&#xff01;…

springcloud gateway

一、 predicate : 就是你定义一些规则&#xff0c;如果满足了这些规则&#xff0c;就去找到对应的路由。 对于strip 二、自定义过略器和全局过滤器 约定大于配置&#xff0c;后缀不变&#xff0c;只改前缀 sentinel持久化 三、sentinel quick-start | Sentinel 信号量虽然简…

RPC 和 序列化

RPC 1 RPC调用流程 1.1 clerk客户端调用远程服务 Clerk::PutAppend() raftServerRpcUtil::PutAppend() raftServerRpcUtil是client与kvserver通信的入口&#xff0c; 包含kvserver功能的一对一映射&#xff1a;Get/PutAppend&#xff0c;通过stub对象——raftKVRpcProctoc:…

【系统架构师】-第19章-大数据架构设计理论与实践

四个特点&#xff1a; 大规模&#xff08;Volume&#xff09;、高速度&#xff08;Velocity&#xff09;和多样化&#xff08;Variety&#xff09;&#xff0c;价值&#xff08;Value&#xff09;。 五个问题&#xff1a; 异构性&#xff08;Heterogeneity&#xff09;、规模…

STP环路避免实验(思科)

华为设备参考&#xff1a;STP环路避免实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 Spanning Tree Protocol&#xff08;STP&#xff09;&#xff0c;即生成树协议&#xff0c;是一种数据链路层协议。主要作用是防止二层环路&#xff0c;并自适应网络变化和故障…

代码随想录day20(2)二叉树:完全二叉树节点个数(leetcode222)

题目要求&#xff1a;求一个完全二叉树的节点个数 思路&#xff1a;首先完全二叉树可以用普通二叉树的方法来求&#xff0c;但是需要遍历所有的节点。 但是对于完全二叉树来说&#xff0c;只有最底层右侧的节点可能没满&#xff0c;其余每层节点都达到了最大值。所以我们可以…

Spring启动“--”设置参数没生效

现象 在idea中启动SpringBoot项目时&#xff0c;使用“--”设置的启动参数没有生效&#xff0c;如修改端口号“--server.port8082” 原因 排查发现是因为在使用SpringApplication.run启动项目时&#xff0c;没有将args参数传入run方法。 修复方案 SpringApplication.run参数中…

想要通过湖北建筑安全员ABC考试?这5个技巧助你一臂之力!

想要通过湖北建筑安全员ABC考试&#xff1f;这5个技巧助你一臂之力&#xff01; 2024年湖北建筑安全员ABC报名考试通过率 关于湖北省建筑安管人员考核管理系统考核通过率不是很固定&#xff0c;或高或低。安全员ABC测试有合格分数线&#xff0c;交卷后30分钟即可查询你的成绩…

RSA加密解密签名加签验签RsaUtils工具类

RSA加密解密RsaUtils工具类题 引言一、RsaUtils工具类代码二、优点三、缺点四、声明 引言 RSA算法基于大数因子分解难题&#xff0c;提供了公钥加密和私钥解密的能力。公钥用于加密&#xff0c;私钥则负责解密。这种特性使得RSA成为保证数据传输安全的理想选择。 公钥加密私钥…

106 基于消息队列来做 mysql 大数据表数据的遍历处理

前言 最近有这样的一个需求, 我们存在一张 很大的 mysql 数据表, 数据量大概是在 六百万左右 然后 需要获取所有的记录, 将数据传输到 es 中 然后 当时 我就写了一个脚本来读取 这张大表, 然后 分页获取数据, 然后 按页进行数据处理 转换到 es 但是存在的问题是, 前面 还…

尚硅谷SpringBoot3笔记 (二) Web开发

Spring Boot Web开发&#xff1a;24.Web开发-自动配置原理_哔哩哔哩_bilibili 1. Web场景 1.1 自动配置 整合web场景&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId&g…

php便民超市管理系统flask-django-nodejs-python

随着时代的变迁&#xff0c;超市管理系统软件使用的普及【1】&#xff0c;以上所有的问题&#xff0c;都是为它而打造的&#xff0c;现在不仅是开一家店容易管理&#xff0c;开多家店页变得容易很多&#xff0c;同时它的出现也可以为本店起到宣传的作用。 21世纪的今天&#…

cc-uploadSomePic图片上传组件:快速开发与用户体验的提升

cc-uploadSomePic图片上传组件&#xff1a;快速开发与用户体验的提升 摘要&#xff1a; 在前端开发中&#xff0c;图片上传功能是一个常见的需求。为了提高开发效率和用户体验&#xff0c;我们开发了一个名为cc-uploadSomePic的图片上传组件。该组件支持单个或多个文件上传&am…

计算机网络——物理层(物理传输介质和物理层的设备)

计算机网络——物理层&#xff08;物理传输介质和物理层的设备 物理传输介质导向性传输介质双绞线同轴电缆光纤 非导向性传输介质无线电波多径效应 微波地面微波通信ISM 频段 卫星通信 物理层设备中继器集线器中继器和集线器的区别 我们今天进入物理层的物理传输介质和物理层的…

阿里云部署MySQL、Redis、RocketMQ、Nacos集群

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容MySQL集群配置云服务器选购CPU选择内存选择云盘选择ESSD AutoPL云盘块存储性能&#xff08;ESSD&#xff09; 镜像选择带宽选择密码配置注意事项 搭建宝塔面板方便管理云服务器云服务器的安全组安装docker和docker-compose…

使用IDEA2023创建传统的JavaWeb项目并运行与调试

日期:2024-0312 作者:dusuanyun 文档环境说明: OS:Deepin 20.9(Linux) JDK: OpenJDK21 Tomcat:10.1.19 IDEA: 2023.3.4 (Ultimate Edition) 本文档默认已经安装JDK及环境变量的配置。 关键词…

openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结:SQL语句改写规则

文章目录 openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结&#xff1a;SQL语句改写规则246.1 使用union all代替union246.2 join列增加非空过滤条件246.3 not in转not exists246.4 选择hashagg246.5 尝试将函数替换为case语句246.6 避免对索引使用函数或表达式运算2…
最新文章