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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//输出 sessionidSystem.out.println("session="+req.getSession().getId());// 转发到show.jspreq.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)){// 登录成功,生成tokenString token = UUID.randomUUID().toString().replaceAll("-","");ro.setCode(0);ro.setMsg("登录成功,返回token");ro.setData(token);//存储tokentokenMap.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)){// 登录成功,生成tokenString token = UUID.randomUUID().toString().replaceAll("-","");ro.setCode(0);ro.setMsg("登录成功,返回token");ro.setData(token);//存储tokentokenMap.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();// 判断tokenif(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:";@Autowiredprivate StringRedisTemplate stringRedisTemplate;//获取token,redis存储token@PostMapping("/app/redis/login")public ResultObject loginAccessToken(@RequestParam("name") String name,@RequestParam("pwd") String pwd) {ResultObject ro = new ResultObject();// 登录处理,返回tokenif ("lisi".equals(name) && "123".equals(pwd)){// 登录成功,生成tokenString token = UUID.randomUUID().toString().replaceAll("-","").toUpperCase();// 准备数据Map<String,String> map = new HashMap<>();map.put("userId","1001");map.put("name","lisi");map.put("role","admin");// 其他数据// 存储数据到redisString key = TOKEN_KEY + token;stringRedisTemplate.opsForHash().putAll(key, map);// 有效会话时间 20minstringRedisTemplate.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:";@Autowiredprivate StringRedisTemplate stringRedisTemplate;//获取token,redis存储token@PostMapping("/app/redis/login")public ResultObject loginAccessToken(@RequestParam("name") String name,@RequestParam("pwd") String pwd) {ResultObject ro = new ResultObject();// 登录处理,返回tokenif ("lisi".equals(name) && "123".equals(pwd)){// 登录成功,生成tokenString token = UUID.randomUUID().toString().replaceAll("-","").toUpperCase();// 准备数据Map<String,String> map = new HashMap<>();map.put("userId","1001");map.put("name","lisi");map.put("role","admin");// 其他数据// 存储数据到redisString key = TOKEN_KEY + token;stringRedisTemplate.opsForHash().putAll(key, map);// 有效会话时间 20minstringRedisTemplate.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();// 检查tokenString 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.mzph.cn/news/755954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下拉树级带搜索功能

可以直接复制粘贴到自己的项目里,方法处把接口替换一下 <template><div><el-popoverplacement"bottom"width"200"trigger"click"><el-inputslot"reference"class"mrInput":placeholder"placehol…

天锐绿盾 | 公司内部文件数据 \ 资料加密系统,数据防泄密软件

#防止设计图纸、各种类型文件、各种类型软件、财务数据、客户资料、源代码&#xff0c;数据存储服务器、SVN、Git等商业核心文件数据外泄# 天锐绿盾是一款专业的企业级文件数据及资料加密系统&#xff0c;旨在为企业内部数据安全提供强有力的支持。 德人合科技 | ——天锐绿盾…

生成式人工智能如何改变商业和社会

生成式人工智能是否将带来生产力黄金时代,或在全球经济中摧毁数以百万计的生计?它是否将带人们步入个人充实的新成长道路,或引导他们一步步走入孤独和隔离的死胡同?它是否将 引领人类 走向新的高处,或播下我们集体毁灭的种子? 自ChatGPT上线以来14个月来,人们还没有完全弄清…

B站python爬虫课程笔记(Q11-15)

下面是学习的网址&#xff1a; ​​​​​​【Python爬虫】 目录 11、class定义类别的一些问题 1&#xff09;定义init初始化函数的一些问题 2&#xff09;定义两个不同函数之间要有空行 3&#xff09;print的技巧 12、class定义类别的一些问题2 13、class_inheritance类…

MySQL数据库的基本概念与安装

目录 引言 一、数据库的基本概念 &#xff08;一&#xff09;数据、表与数据库 1.数据(Data) 2.表 3.数据库 &#xff08;二&#xff09;数据库管理系统 &#xff08;三&#xff09;数据库系统 二、数据库的发展 三、主流数据库的介绍 &#xff08;一&#xff09;关…

地理数据表达方式学习——KML与SHP

一、KML-Keyhole Markup Language Keyhole Markup Language (KML)是一种XML符号&#xff0c;用于浏览器中二维地图和三维地球的地理注释和地理可视化&#xff08;地理数据包括点、线、面、多边形、多面体以及模型等&#xff09;。KML是伴随着Google Earth的使用而开发的&#x…

word的第六课笔记

1.排版的六大特点&#xff08;留白、对齐、亲密、对比、重复、可自动更新&#xff09; 先设置页边距为2厘米&#xff0c;左侧装订线考虑2.75厘米。段落间距段前段后设置一个就可以了&#xff0c;如段前0.5行 &#xff08;留白&#xff1a;让文字更加容易阅读&#xff0c;调大页…

AMRT 3D 数字孪生引擎(轻量化图形引擎、GIS/BIM/3D融合引擎):智慧城市、智慧工厂、智慧建筑、智慧校园。。。

AMRT3D 一、概述 1、提供强大完整的工具链 AMRT3D包含开发引擎、资源管理、场景编辑、UI搭建、项目预览和发布等项目开发所需的全套功能&#xff0c;并整合了动画路径、精准测量、动态天气、视角切换和动画特效等工具。 2、轻量化技术应用与个性化定制 AMRT3D适用于快速开…

体验函数式组件简单实现Loading 加载(造轮子篇)

一、前言 最近想着优化一下网站&#xff0c;在文章列表页加一个Loading操作&#xff0c;于是就想到了函数式组件&#xff0c;于是本章就来和大家一起简单探讨下实现思路。 二、Loading设计 这里我想实现的效果是&#xff1a;当我们刷新页面的时候&#xff0c;前端请求接口&…

【MySQL】中位数巧解之给定数字的频率查询中位数

力扣题 1、题目地址 571. 给定数字的频率查询中位数 2、模拟表 Numbers 表&#xff1a; Column NameTypenumintfrequencyint num 是这张表的主键(具有唯一值的列)。这张表的每一行表示某个数字在该数据库中的出现频率。 3、要求 中位数 是将数据样本中半数较高值和半数…

扭矩测量仪行业研究:规模不断扩大市场需求旺盛

一、市场趋势 扭矩测量仪是用于精确测量旋转力矩的精密仪器&#xff0c;广泛应用于汽车、航空航天、机械制造和电子产品等领域。随着工业自动化程度的提升和精密制造的需求增加&#xff0c;扭矩测量仪的市场呈现出稳步增长的趋势。 二、主要竞争者 市场上的主要竞争企业包括德国…

华为OD机试 - 求字符串中所有整数的最小和(Java JS Python C C++)

题目描述 输入字符串s&#xff0c;输出s中包含所有整数的最小和。 说明&#xff1a; 字符串s&#xff0c;只包含 a-z A-Z 合法的整数包括 1&#xff09;正整数&#xff1a;一个或者多个0-9组成&#xff0c;如 0 2 3 002 102 2&#xff09;负整数&#xff1a;负号 – 开头…

Python爬虫之Scrapy框架系列(24)——分布式爬虫scrapy_redis完整实战【XXTop250完整爬取】

目录&#xff1a; 每篇前言&#xff1a;1.使用分布式爬取豆瓣电影信息&#xff08;1&#xff09;settings.py文件中的配置&#xff1a;&#xff08;2&#xff09;spider文件的更改&#xff1a;&#xff08;3&#xff09;items.py文件&#xff08;两个项目一致&#xff01;&…

Vue el-table 合并单元格

一般常见的就是下图这种的单列&#xff0c;上下重复进行合并。 有时候可能也会需要多行多列的合并。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content&qu…

MySQL TRIM函数

TRIM函数通常用于去除字符串的开头和结尾的空格或其他指定字符。在不同的数据库系统中&#xff0c;TRIM函数的语法可能略有不同&#xff0c;以下是一些常见数据库系统中TRIM函数的用法示例&#xff1a; ### 1. MySQL 在MySQL中&#xff0c;TRIM函数的语法如下&#xff1a; sql …

3.19网络编程

select实现的TCP并发服务器 #include <myhead.h> #define SER_IP "192.168.141.134" #define SER_PORT 8888 int main(int argc, const char *argv[]) {// 1、创建一个套接字int sfd -1;sfd socket(AF_INET, SOCK_STREAM, 0);if (sfd -1){perr…

Division by Invariant Integers using Multiplication

在处理器中&#xff0c;整数除法的成本通常是整数乘法的几倍&#xff1a; 流水线式的组合乘法器通常在不到10个周期内完成操作&#xff1b;而对于整数除法则没有硬件支持&#xff0c;或者使用的迭代除法器比乘法器慢几倍。 表 1.1 比较了一些处理器上乘法和除法的时间。这张表…

php 页面中下载文件|图片

一、需求 页面中点击下载图片 二、实现 protected function pageLoad(){$filePath $_GET[file];$host $_SERVER[HTTP_HOST];$file http://.$host.$filePath;$fileName basename($filePath);$content file_get_contents($file);ob_clean();$suffixArr explode(., $file…

ceph删除坏的磁盘

在Ceph集群中&#xff0c;查看和处理坏掉的磁盘主要涉及到以下几个步骤&#xff1a;检查磁盘状态、从集群中删除坏磁盘、最后是物理或逻辑地替换坏掉的磁盘。请注意&#xff0c;处理Ceph集群的操作需要谨慎执行&#xff0c;并确保在操作前你有足够的备份和恢复计划 1. 查看集群…

数据库系统概论-练手题集合【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下数据库系统概论中的练手题&#xff0c;以供大家期末复习和考研复习的时候使用。 数据库系统概论系列文章传送门&#xff1a; 第一章 绪论 第二/三章 关系数据库和标准语言SQL 第四/五章 数据库安全性和完整性…