web开发工具之:三、JWT的理论知识,java的支持,封装的工具类可以直接使用

news2025/1/18 8:22:32

文章目录

  • 前言
  • 一、JWT的理论知识
    • 1. 什么是 JWT(JSON Web Token)?
    • 2. **JWT 的组成**
    • 3. **JWT 的特点**
    • 4. **JWT 的使用场景**
    • 5. **JWT 的生命周期**
    • 6. **JWT 的优点**
    • 7. **JWT 的注意事项**
    • 5. **JWT 示例**
      • 总结
  • 二、java的springboot支持
    • 1. pom依赖
    • 2. application.yaml配置
    • 3. 加载application.yaml配置的配置类
    • 4. jwt工具类:JwtTokenUtil.java
    • 5. InitializerJwtPropertiesConfig.java:将配置类注入到工具类中
  • 三、总结

前言

本文详细介绍了在Java Spring Boot中实现JWT(JSON Web Token)的完整流程。通过依赖io.jsonwebtoken的jjwt库,我们可以方便地生成、解析和验证JWT。文章提供了配置文件、工具类和初始化配置的详细代码,涵盖了JWT的生成、过期时间设置、刷新机制以及从token中提取信息等功能。这些方法在用户认证、授权和单点登录等场景中具有重要应用,有助于提高Web应用的安全性和效率。

一、JWT的理论知识

1. 什么是 JWT(JSON Web Token)?

JWT(JSON Web Token)是一种基于 JSON 的开放标准 (RFC 7519) ,用于在各方之间作为紧凑且安全的方式传输信息。它常用于认证和授权场景,尤其是在 Web 开发中非常流行。

2. JWT 的组成

一个 JWT 通常由三部分组成,每部分通过 . 分隔:

  1. Header(头部)

    • 描述令牌的元信息,比如使用的签名算法。
    • 通常是一个简单的 JSON 对象,如:
      {
        "alg": "HS256",
        "typ": "JWT"
      }
      
    • alg 指定签名算法(如 HS256、RS256),typ 表示令牌的类型(一般为 “JWT”)。
  2. Payload(有效载荷)

    • 包含实际要传递的数据,例如用户信息或声明(claims)。
    • 这是一个 JSON 对象,可以包括:
      • 标准声明(预定义字段,如用户 ID、过期时间等)。
      • 自定义声明(开发者自定义的数据)。
    • 示例:
      {
        "sub": "1234567890",
        "name": "John Doe",
        "admin": true,
        "exp": 1672444800
      }
      
    • 注意:Payload 是可以被 解码和阅读 的,因此不要存储敏感信息。
  3. Signature(签名)

    • 用于验证 JWT 的完整性,确保它未被篡改。
    • 签名是通过以下方式生成的:
      HMACSHA256(
          base64UrlEncode(header) + "." + base64UrlEncode(payload),
          secret
      )
      
    • 如果签名验证失败,JWT 就会被判定为无效。

3. JWT 的特点

  1. 紧凑性

    • JWT 使用 Base64Url 编码,令牌是一个字符串,适合通过 URL 或 HTTP 请求头传输。
  2. 自包含性

    • JWT 内部可以包含必要的用户信息,减少了对服务器多次查询的需求。
  3. 无状态

    • JWT 是一种无状态认证方式,服务器不需要存储用户会话数据。
  4. 安全性

    • 签名确保令牌未被篡改。
    • 但注意:Payload 可以被解码,因此敏感信息需要加密或避免存储在 JWT 中。

4. JWT 的使用场景

  1. 用户认证

    • 用户登录成功后,服务器生成一个 JWT,返回给客户端。
    • 客户端每次请求时将 JWT 附带在请求头(通常是 Authorization: Bearer <token>)中。
    • 服务器通过验证 JWT 来确定用户身份。
  2. 授权

    • 用于控制用户对资源的访问权限。
    • JWT 中可以包含用户角色或权限信息。
  3. 单点登录(SSO)

    • JWT 是 SSO 的一种理想选择,因其跨平台的特点,可以在不同的服务间传递用户身份。

5. JWT 的生命周期

  • 生成

    1. 用户向服务器发送登录请求。
    2. 服务器验证用户身份后生成 JWT,通常会设置过期时间(如 15 分钟)。
    3. JWT 返回给客户端。
  • 验证

    1. 客户端在后续请求中发送 JWT。
    2. 服务器通过签名验证 JWT 是否有效。
  • 刷新

    • JWT 的有效期一般较短,若用户需要长期登录,可以结合 Refresh Token 实现令牌刷新。

6. JWT 的优点

  1. 无状态性:服务器无需存储会话数据。
  2. 高效性:可以通过单个令牌传递多种信息。
  3. 跨语言支持:JWT 是一种标准,可以被多种编程语言支持。

7. JWT 的注意事项

  1. 不要存储敏感数据

    • Payload 是明文可解码的,敏感信息应避免放入 JWT。
  2. 使用 HTTPS

    • 确保 JWT 在传输过程中被加密,防止被中间人攻击。
  3. 设置有效期

    • 短生命周期的 JWT 可以减少被盗用的风险。
  4. 签名密钥管理

    • 确保签名密钥的安全,避免泄漏。

5. JWT 示例

一个完整的 JWT 示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

解码后:

  1. Header

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  2. Payload

    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
    
  3. Signature

    SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

总结

JWT 是一种高效的认证和授权工具,适合现代 Web 应用。学习 JWT 后,可以轻松实现用户登录、权限控制等功能,为 Web 开发打下坚实基础!

二、java的springboot支持

下面有3个类,这三个类都在同一个包里,构成了一个工具类。可以通过 JwtTokenUtil.java 类直接使用封装好的方法即可。

1. pom依赖

先直接上pom依赖

<!--JWT-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

从Maven的依赖官网搜索了一下,从截图中可以看到有以下四个。

jjwt 是一个包含多个依赖的聚合包,它包括了 jjwt-api、jjwt-impl 和 jjwt-jackson(或 jjwt-gson,取决于你选择的 JSON 处理库)。

  • jjwt-api 提供了 JWT 的基本接口和抽象类。
  • jjwt-impl 则提供了 JWT 的具体实现,它是运行时依赖。
  • jjwt-jackson(或 jjwt-gson)用于 JSON 处理,也是运行时依赖。

因此,当你导入 jjwt 依赖时,实际上是在项目中引入了这三个组件。这样做可以简化依赖管理,因为只需要引入一个依赖即可。

在这里插入图片描述

2. application.yaml配置

#JWT  自定义属性
jwt:
#  secretKey: 78944878877848fg)   # 秘钥
  secretKey: fengfanli            # 秘钥
  accessTokenExpireTime: PT2H     # 过期时间 两个小时
  refreshTokenExpireTime: PT8H    # 刷新token,
  refreshTokenExpireAppTime: P30D
  issuer: fengfanli.com           # 签名:

3. 加载application.yaml配置的配置类

package com.feng.companyframe.jwt;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
 * @ClassName: PropertityConfig
 * @Description: token 读取的配置属性
 * @createTime: 2020/2/4 11:04
 * @Author: 冯凡利
 * @UpdateUser: 冯凡利
 * @Version: 0.0.1
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "jwt")
public class JwtPropertiesConfig {
    private String secretKey;
    private Duration accessTokenExpireTime;  // java.time.Duration;
    private Duration refreshTokenExpireTime;
    private Duration refreshTokenExpireAppTime;
    private String issuer;
}

4. jwt工具类:JwtTokenUtil.java

package com.feng.companyframe.jwt;

import com.feng.companyframe.constant.Constant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.thymeleaf.util.StringUtils;

import javax.xml.bind.DatatypeConverter;
import java.time.Duration;
import java.util.Date;
import java.util.Map;

/**
 * @ClassName: JwtTokenUtil
 * @Description: JWT token 工具类
 * @createTime: 2020/2/3 23:24
 * @Author: 冯凡利
 * @UpdateUser: 冯凡利
 * @Version: 0.0.1
 */
@Slf4j
public class JwtTokenUtil {
    private static String secretKey;
    private static Duration accessTokenExpireTime;  // java.time.Duration;
    private static Duration refreshTokenExpireTime;
    private static Duration refreshTokenExpireAppTime;
    private static String issuer;

    /**
     *  读取配置文件类中属性,放到本文件中
     * @param jwtPropertiesConfig
     */
    public static void setTokenProperties(JwtPropertiesConfig jwtPropertiesConfig) {
        secretKey = jwtPropertiesConfig.getSecretKey();
        accessTokenExpireTime = jwtPropertiesConfig.getAccessTokenExpireTime();
        refreshTokenExpireTime = jwtPropertiesConfig.getRefreshTokenExpireTime();
        refreshTokenExpireAppTime = jwtPropertiesConfig.getRefreshTokenExpireAppTime();
        issuer = jwtPropertiesConfig.getIssuer();
    }

    /**
     * 生成 access_token
     *
     * @param subject 主题
     * @param claims  存储在JWT里面的信息 一般放些用户的权限/角色信息
     * @return
     */
    public static String getAccessToken(String subject, Map<String, Object> claims) {
        return generateToken(issuer, subject, claims, accessTokenExpireTime.toMillis(), secretKey);
    }

    /**
     * 生产 PC refresh_token(PC 端过期时间短一些)
     *
     * @param subject
     * @param claims
     * @return
     */
    public static String getRefreshToken(String subject, Map<String, Object> claims) {
        return generateToken(issuer, subject, claims, refreshTokenExpireTime.toMillis(), secretKey);
    }

    /**
     * 生产 App端 refresh_token
     *
     * @param subject
     * @param claims
     * @return
     */
    public static String getRefreshAppToken(String subject, Map<String, Object> claims) {
        return generateToken(issuer, subject, claims, refreshTokenExpireAppTime.toMillis(), secretKey);
    }

    /**
     * 生成token, 以上三个方法 都调用此方法
     *
     * @param issuer    签发人
     * @param subject   主题:令牌的主题,通常是用户信息或令牌的主要用途。一般可以使用用户ID作为主题
     * @param claims    存储在JWT里面的信息 一般放些用户的权限/角色信息
     * @param ttlMillis 有效时间(毫秒) --》配置文件获取
     * @param secret    秘钥  --》配置文件获取
     * @return 返回 token java.lang.String
     */
    public static String generateToken(String issuer, String subject, Map<String, Object> claims,
                                       long ttlMillis, String secret) {

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMills = System.currentTimeMillis();
        Date now = new Date(nowMills);

        // 对秘钥进行编码 成数组
        byte[] signingKey = DatatypeConverter.parseBase64Binary(secret);

        // 创建 jwt 构造器
        JwtBuilder builder = Jwts.builder();
        if (null != claims) {
            builder.setClaims(claims);
        }
        if (!StringUtils.isEmpty(subject)) {
            builder.setSubject(subject);
        }
        if (!StringUtils.isEmpty(issuer)) {
            builder.setIssuer(issuer);
        }
        // 主题在 此时 进行时间设定
        builder.setIssuedAt(now);
        if (nowMills >= 0) {
            long expMillis = nowMills + ttlMillis;
            Date exp = new Date(expMillis);
            // 设置过期时间
            builder.setExpiration(exp);
        }
        // 拿着 算法和 秘钥进行 签名
        builder.signWith(signatureAlgorithm, signingKey);
        // 返回 jwt
        return builder.compact();
    }

// 以下为 对token 的操作静态方法

    /**
     * 从令牌中获取 数据声明 Claims
     *
     * @param token 传入的 jwt
     * @return io.jsonwebtoken.Claims
     */
    public static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secretKey))
                    .parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
     * 获取用户id
     *
     * @param token
     * @return io.jsonwebtoken.Claims
     */
    public static String getUserId(String token) {
        String userId = null;
        try {
            Claims claims = getClaimsFromToken(token);
            userId = claims.getSubject();
        } catch (Exception e) {
            log.error("eror={}", e.getLocalizedMessage());
        }
        return userId;
    }

    /**
     * 获取用户名
     *
     * @param token
     * @return username String
     */
    public static String getUserName(String token) {
        String username = null;
        try {
            Claims claims = getClaimsFromToken(token);
            username = (String) claims.get(Constant.JWT_USER_NAME);
        } catch (Exception e) {
            log.error("eror={}", e);
        }
        return username;
    }

    /**
     * 验证token 是否过期(true:已过期 false:未过期)
     *
     * @param token
     * @return java.lang.Boolean
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            // token的过期时间 与 当前时间比较,如果小于,则为 true,为过期
            return expiration.before(new Date());
        } catch (Exception e) {
            log.error("error={}", e.getLocalizedMessage());
            return true;
        }
    }

    /**
     * 校验令牌(true:验证通过 false:验证失败)
     *
     * @param token
     * @return Boolean
     */
    public static Boolean validateToken(String token) {
        Claims claimsFromToken = getClaimsFromToken(token);
        //
        return (null != claimsFromToken && !isTokenExpired(token)); //  && :and 都为true
    }

    /**
     * 刷新token
     *
     * @param refreshToken
     * @param claims       主动去刷新的时候 改变JWT payload 内的信息
     * @return String
     */
    public static String refreshToken(String refreshToken, Map<String, Object> claims) {
        String refreshedToken;
        try {
            Claims parserclaims = getClaimsFromToken(refreshToken);
            /**
             * 刷新token的时候如果为空说明原先的 用户信息不变 所以就引用上个token里的内容
             */
            if (null == claims) {
                claims = parserclaims;
            }
            refreshedToken = generateToken(parserclaims.getIssuer(),
                    parserclaims.getSubject(), claims, accessTokenExpireTime.toMillis(), secretKey);
        } catch (Exception e) {
            refreshedToken = null;
            log.error("error={}", e.getLocalizedMessage());
        }
        return refreshedToken;
    }


    /**
     * 获取token的剩余过期时间
     *
     * @param token
     * @return
     */
    public static long getRemainingTime(String token){
        long result=0;
        try {
            long nowMillis = System.currentTimeMillis();
            result= getClaimsFromToken(token).getExpiration().getTime()-nowMillis;
        } catch (Exception e) {
            log.error("error={}",e.getLocalizedMessage());
        }
        return result;
    }

}

生成 accessToken 的核心函数是:generateToken(String issuer, String subject, Map<String, Object> claims,long ttlMillis, String secret),简单介绍一下:

这段代码使用 JJWT 库生成 JSON Web Token (JWT),用于身份验证和信息传递。以下是简要说明:

  1. 功能:生成一个带签名的 JWT,包括发布者、主题、自定义数据(claims)、过期时间和签名。

  2. 主要步骤

    • 指定签名算法(HS256)。
    • 使用 Base64 解码密钥。
    • 设置令牌信息(如发布者、主题、自定义声明、签发时间等)。
    • 如果指定了有效期,计算过期时间并设置。
    • 使用密钥和算法对令牌进行签名。
    • 返回最终的 JWT 字符串。
  3. 主要用途

    • 身份认证:生成令牌用于验证用户身份。
    • 数据传递:通过 claims 携带额外信息。
    • 过期控制:ttlMillis 设置令牌有效期。

这是生成 JWT 的基础方法,适用于各种 Web 开发场景,灵活且易用。

5. InitializerJwtPropertiesConfig.java:将配置类注入到工具类中

package com.feng.companyframe.jwt;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName: InitializerJwtPropertiesConfig
 * @Description: 将yml配置文件中的数据注入到 JwtTokenUtil 工具类中
 * @createTime: 2020/2/5 10:42
 * @Author: 冯凡利
 * @UpdateUser: 冯凡利
 * @Version: 0.0.1
 */
@Configuration
public class InitializerJwtPropertiesConfig {

//    @Autowired
    private JwtPropertiesConfig jwtPropertiesConfig;

    public InitializerJwtPropertiesConfig(JwtPropertiesConfig jwtPropertiesConfig) {
        JwtTokenUtil.setTokenProperties(jwtPropertiesConfig);
    }
}


三、总结

JwtTokenUtil.java 从该类中可以看出:

  1. 配置文件中配置了秘钥、token过期时间、刷新token过期时间、APP刷新token过期时间(这是APP端的)、签名。这是SHA-256算法的一些配置。
  2. getAccessToken(String subject, Map<String, Object> claims)函数根据 主题和主体(放到jwt的载体中) 生成token。
  3. 其他函数:getClaimsFromToken()等,都是从token中获取claims主体的信息。claims是一个map,可以放一些用户常用信息的,一般放置:用户名称、用户的角色、用户的权限 等。

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

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

相关文章

电路笔记(信号):Python 滤波器设计分析工具pyfda

目录 滤波器设置(3步实现滤波器设计)数据分析与使用pyfda功能界面数字滤波器数学表示线性相位线性相位的定义线性相位的特性 冲击响应quartus数据加载 CG 滤波器设置(3步实现滤波器设计) pip install pyfda #安装python依赖&#xff0c;详见https://pyfda.readthedocs.io/en/la…

【15】Word:互联网发展状况❗

目录 题目​ NO2 NO3 NO4 NO5 NO6 NO7.8.9 NO7 NO8 NO9 NO10 题目 NO2 布局→页面设置→纸张&#xff1a;A4→页边距&#xff1a;上下左右→版式&#xff1a;页眉/页脚页码范围&#xff1a;多页&#xff1a;对称页边距→内侧/外侧→装订线 NO3 首先为文档应用内置…

Web前端开发技术之HTMLCSS知识点总结

学习路线 一、新闻网界面1. 代码示例2. 效果展示3. 知识点总结3.1 HTML标签和字符实体3.2 超链接、颜色描述与标题元素3.3 关于图片和视频标签&#xff1a;3.4 CSS引入方式3.5 CSS选择器优先级 二、flex布局1. 代码示例2. 效果展示3. 知识点总结3.1 span标签和flex容器的区别3.…

BUUCTF Web

[极客大挑战 2019]LoveSQL union注入 是sql注入类型 输入1 发现不是数字型注入&#xff0c;那就是字符型注入。判断字段数&#xff0c;输入order by 4 #发现错误&#xff0c;就存在三个字段数 判断回显点&#xff1a;1 union select 1,2,3 # 判断回显点为2,3 判断数据库名 …

Kinova仿生机械臂Gen3搭载BOTA 力矩传感器SeneOne:彰显机器人触觉 AI 与六维力传感的融合力量

随着工业4.0时代的到来&#xff0c;自动化和智能化成为制造业的趋势。机器人作为实现这一趋势的重要工具&#xff0c;其性能和智能水平直接影响到生产效率和产品质量。然而&#xff0c;传统的机器人系统在应对复杂任务时往往缺乏足够的灵活性和适应性。为了解决这一问题&#x…

【数据库】MySQL数据库SQL语句汇总

目录 1.SQL 通用语法 2.SQL 分类 2.1.DDL 2.2.DML 2.3.DQL 2.4.DCL 3.DDL 3.1.数据库操作 3.1.1.查询 3.1.2.创建 3.1.3.删除 3.1.4.使用 3.2.表操作 3.2.1.查询 3.2.2.创建 3.2.3.数据类型 3.2.3.1.数值类型 3.2.3.2.字符串类型 3.2.3.3.日期时间类型 3.2…

《汽车与驾驶维修》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车与驾驶维修》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第二批认定学术期刊。 问&#xff1a;《汽车与驾驶维修》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;中国机械工业联合会…

鸿蒙UI(ArkUI-方舟UI框架)-开发布局

文章目录 开发布局1、布局概述1&#xff09;布局结构2&#xff09;布局元素组成3&#xff09;如何选择布局4&#xff09;布局位置5&#xff09;对子元素的约束 2、构建布局1&#xff09;线性布局 (Row/Column)概述布局子元素在排列方向上的间距布局子元素在交叉轴上的对齐方式(…

数据结构——概述

1、什么是数据结构&#xff1f; 数据结构是计算机存储和管理数据的方式。数据必须依据某种逻辑联系组织在一起存储在计算机内&#xff0c;数据结构研究的就是这种数据的逻辑结构和数据的存储结构 2、逻辑结构——数据本身之间的关系 逻辑结构在计算机中的实现 &#xff08;1…

业务架构、数据架构、应用架构和技术架构

TOGAF(The Open Group Architecture Framework)是一个广泛应用的企业架构框架&#xff0c;旨在帮助组织高效地进行架构设计和管理。 TOGAF 的核心就是由我们熟知的四大架构领域组成:业务架构、数据架构、应用架构和技术架构。 企业数字化架构设计中的最常见要素是4A 架构。 4…

python爬虫入门(实践)

python爬虫入门&#xff08;实践&#xff09; 一、对目标网站进行分析 二、博客爬取 获取博客所有h2标题的路由 确定目标&#xff0c;查看源码 代码实现 """ 获取博客所有h2标题的路由 """url "http://www.crazyant.net"import re…

简历_使用优化的Redis自增ID策略生成分布式环境下全局唯一ID,用于用户上传数据的命名以及多种ID的生成

系列博客目录 文章目录 系列博客目录WhyRedis自增ID策略 Why 我们需要设置全局唯一ID。原因&#xff1a;当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题。 问题&#xff1a;id的规律性太明显、…

win32汇编环境,窗口程序中对多行编辑框的操作

;运行效果 ;win32汇编环境,窗口程序中对多行编辑框的操作 ;比如生成多行编辑框&#xff0c;显示文本、获取文本、设置滚动条、捕获超出文本长度消息等。 ;直接抄进RadAsm可编译运行。重点部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>&g…

【Flink系列】5. DataStream API

5. DataStream API DataStream API是Flink的核心层API。一个Flink程序&#xff0c;其实就是对DataStream的各种转换。具体来说&#xff0c;代码基本上都由以下几部分构成&#xff1a; 5.1 执行环境&#xff08;Execution Environment&#xff09; Flink程序可以在各种上下文…

探索未来:Leap Motion JavaScript框架——开启VR与手势控制的无限可能

探索未来&#xff1a;Leap Motion JavaScript框架——开启VR与手势控制的无限可能 leapjs JavaScript client for the Leap Motion Controller 项目地址: https://gitcode.com/gh_mirrors/le/leapjs 项目介绍 欢迎来到Leap Motion JavaScript框架的世界&#xff01;Lea…

PCM5142集成32位384kHz PCM音频立体声114dB差分输出DAC编解码芯片

目录 PCM5142 简介PCM5142功能框图PCM5142特性 参考原理图 PCM5142 简介 PCM514x 属于单片 CMOS 集成电路系列&#xff0c;由立体声数模转换器 (DAC) 和采用薄型小外形尺寸 (TSSOP) 封装的附加支持电路组成。PCM514x 使用 TI 最新一代高级分段 DAC 架构产品&#xff0c;可实现…

技术领衔 互学互鉴|ZASM召开2024年度技术交流会

1月16日&#xff0c;ZASM组织召开了“2024年度企业员工技术交流活动”。公司总经理&#xff0c;技术部门负责人及项目经理参加本次会议。 会上&#xff0c;公司所属各项目技术负责人围绕“三维模型切割模块的基础操作与模型发布缓存的技术演示”、“J18微型智能空中作业平台的…

UI自动化测试:异常截图和page_source

自动化测试过程中&#xff0c;是否遇到过脚本执行中途出错却不知道原因的情况&#xff1f;测试人员面临的不仅是问题的复现&#xff0c;还有对错误的快速定位和分析。而异常截图与页面源码&#xff08;Page Source&#xff09;的结合&#xff0c;正是解决这一难题的利器。 在实…

OSI七层协议——分层网络协议

OSI七层协议&#xff0c;顾名思义&#xff0c;分为七层&#xff0c;实际上七层是不存在的&#xff0c;是人为的进行划分,让人更好的理解 七层协议包括&#xff0c;物理层(我),数据链路层(据),网络层(网),传输层(传输),会话层(会),表示层(表),应用层(用)(记忆口诀->我会用表…

浅谈计算机网络04 | 现代网络需求与技术支撑

现代网络需求与技术支撑 一、网络和因特网流量的类型剖析1.1 弹性流量的自适应特征1.2 非弹性流量的刚性特征1.3 实时流量特性 二、特定领域的网络需求解析2.1 大数据环境下的网络需求分析2.2 云计算环境下的网络需求分析2.3 移动数据环境下的网络需求分析 三、QoS和QoE&#x…