当前位置: 首页 > news >正文

SpringBoot实战项目第一天

环境搭建

后端部分需要准备:

sql数据库

创建SpringBoot工程,引入对应的依赖(web\mybatis\mysql驱动)

配置文件application.yml中引入mybatis的配置信息

创建包结构,并准备实体类

完成今日开发后项目部分内容如下图示

用户注册于登录部分相关内容

注册

谈到注册,首先就要看看数据库中用户表的构成:

然后对应的,完成User实体类的开发

@Data
//lombok  在编译阶段,为实体类自动生成setter  getter toString
// pom文件中引入依赖   在实体类上添加注解
public class User {private Integer id;//主键IDprivate String username;//用户名private String password;//密码private String nickname;//昵称private String email;//邮箱private String userPic;//用户头像地址private LocalDateTime createTime;//创建时间private LocalDateTime updateTime;//更新时间
}

此处用到了lombok技术,该技术可以在java文件编译时自动为变量生成getter、setter方法和tostring方法,后期实体类的开发也均会用到该技术。

        <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

接下来,就是要完成Mapper -> Service -> Controller这三层的对应开发。

在开发之前,我们要明确开发需求,即用户的注册。

而在用户注册时,会出现两种情况,注册成功与注册失败。此时我们粗略地将这两种情况对应为

 数据库中没有该用户名对应行 -> 该用户还尚不存在 ->允许注册 ->注册

 数据库中存在该用户名对应行 -> 该用户已经存在 -> 不允许注册 ->返回注册失败原因

理清逻辑后我们从Mapper层开始开发

        首先,我们要注意到,在用户注册时我们会首先对数据库中是否已经存在该用户进行检测,如果没有,再在数据库中录入新用户信息

        这就涉及到了sql中的两种操作,@select与@insert,所以,我们在Mapper层的接口中就要提供这两个操作

@Mapper
public interface UserMapper {@Select("select * from user where username = #{username}")User getByUserName(String username);@Insert("insert into user(username,password,create_time,update_time)"+"values (#{username},#{password},now(),now())")void add(String username, String password);
}

不要忘记使用@Mapper注册该类! 

 

再来看Service

service层开发较为简单,只需要将dao层的对应方法调用

service接口

public interface UserService {//用户名查询用户User getByUserName(String username);//新用户注册void register(String username, String password);
}

而impl文件中在实现这些方法之余,我们在service层会对用户输入的密码进行加密,这里使用到了MD5加密

@Service
public class SuerServiceImpl implements UserService {@AutowiredUserMapper userMapper;@Overridepublic User getByUserName(String username) {User u = userMapper.getByUserName(username);return u;}@Overridepublic void register(String username, String password) {//密码加密String p = Md5Util.getMD5String(password);userMapper.add(username,p);}
}

记得检查传入mapper层的密码,一定要是加密后的! 

MD5:

public class Md5Util {/*** 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合*/protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};protected static MessageDigest messagedigest = null;static {try {messagedigest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException nsaex) {System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");nsaex.printStackTrace();}}/*** 生成字符串的md5校验值** @param s* @return*/public static String getMD5String(String s) {return getMD5String(s.getBytes());}/*** 判断字符串的md5校验码是否与一个已知的md5码相匹配** @param password  要校验的字符串* @param md5PwdStr 已知的md5校验码* @return*/public static boolean checkPassword(String password, String md5PwdStr) {String s = getMD5String(password);return s.equals(md5PwdStr);}public static String getMD5String(byte[] bytes) {messagedigest.update(bytes);return bufferToHex(messagedigest.digest());}private static String bufferToHex(byte bytes[]) {return bufferToHex(bytes, 0, bytes.length);}private static String bufferToHex(byte bytes[], int m, int n) {StringBuffer stringbuffer = new StringBuffer(2 * n);int k = m + n;for (int l = m; l < k; l++) {appendHexPair(bytes[l], stringbuffer);}return stringbuffer.toString();}private static void appendHexPair(byte bt, StringBuffer stringbuffer) {char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>// 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换stringbuffer.append(c0);stringbuffer.append(c1);}}

 

最后一步,我们进行Controller层的开发 

在controller层中,我们需要进行相应的逻辑判断来验证该用户名是否已经被占用,具体操作如下:

@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(String username,String password){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}
}

Result实体类如下:

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {private Integer code;//业务状态码  0-成功  1-失败private String message;//提示信息private T data;//响应数据//快速返回操作成功响应结果(带响应数据)public static <E> Result<E> success(E data) {return new Result<>(0, "操作成功", data);}//快速返回操作成功响应结果public static Result success() {return new Result(0, "操作成功", null);}public static Result error(String message) {return new Result(1, message, null);}
}

最后的最后,我们使用测试软件对注册部分进行测试

先看新用户注册正常,注册成功情况

 数据库存储情况

可以看到密码的加密工作也顺利完成

再来看看注册失败的情况,这里我们直接使用刚才的账密注册

注册失败,至此,我们的注册功能已完成最基本的开发与测试。 

当然,我们在日常生活中会发现,账户与密码会有一个基本的校验,即a-b位的非空字符,显然,我们还需要对账密进行进行长度检验。

账户密码长度参数校验

这里我预设的账户长度为4-16位

密码长度位11-16位

校验我们在controller层完成

@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(String username,String password){if(username != null && username.length()>=4 && username.length() <= 16 &&password != null && password.length() >= 11 && password.length() <=16){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}else{return Result.error("用户名或密码输入不合法!");}}
}

当然,我们会发现,仅仅校验账户与密码这两个参数就会导致我们的逻辑判断代码如此繁琐,Spring当然也为我们提供了简化方法——Spring Validation框架 

Spring Validation框架 :Spring提供的一个参数校验框架,使用预定义的注解完成参数校验 

Spring Validation框架使用流程

第一步、引入Spring Validation框架起步依赖
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
第二步、在参数前面添加@Pattren注解
 public Result register(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){
第三步、在Controller类上添加@Validated注解
@RestController
@RequestMapping("/user")
@Validated
public class UserController {@AutowiredUserService userService;@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询该用户名是否已经存在User u = userService.getByUserName(username);if (u==null){//用户名没有被占用,注册userService.register(username,password);return Result.success();} else {return Result.error("用户名被占用!");}}
}

当我们输入不合法的账密时,我们会发现,这里的报错不如我们之前手动返回的,所以我们要对其进行参数校验失败异常处理

 

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public Result handleExxception(Exception e){e.printStackTrace();return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败,");}
}

再次使用非法账密测试

 

 

可以看到异常处理功能正常运行 

 登录

在开发之前,我们要明确开发需求,即用户的登录(成功登录后需求返回一个 jwt token 令牌)。

而在用户登录时,会出现三种情况,账密正确,成功登录、账号错误,登陆失败与密码错误,登陆失败。此时我们粗略地将这三种情况对应为

 数据库中没有该用户名对应行 -> 该用户还尚不存在 ->登陆失败 ->返回登陆失败原因

 数据库中存在该用户名对应行,但密码不对应 -> 密码输入错误 -> 登陆失败 -> 返回登录失败原因

 数据库中存在该用户名对应行,且密码对应 -> 账户密码输入正确 -> 登陆成功

分析完需求,我们会发现我们在书写登录模块时需要对用户的帐户密码进行相应的逻辑判断,用到的sql语句为@select与@insert,这两个方法我们在注册模块已经完成了书写,所以我们直接在Controller层编写登录模块即可!

Controller层技术开发

@PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询用户是否存在User lUser = userService.getByUserName(username);if(lUser == null){return  Result.error("用户不存在!");}//查询密码是否正确(密码需要加密后再与数据库中密码比较)if (Md5Util.getMD5String(password).equals(lUser.getPassword())){return Result.success("jwt token 令牌");}return Result.error("密码错误!");}

可以看到,对于账密合法性判断我们采取了与注册时一样的操作, 逻辑判断部分也是简单的匹配,下面我们来对其进行测试

这是一组正确的账户密码测试,可以看到,此时我们暂时还没有编写jwt令牌的返回,暂时使用一个字符串代替

下面再进行一组错误账户名的测试

 

可以看到,错误信息如期。

最后在进行一组错误密码的测试

测试完毕,我们编辑的最最基础的登录部份功能正常运行!

 

登录认证

       当我们需要将某些界面设置为登陆后可见时,我们就需要对其加入登录认证的功能,接下来就进行该功能的开发

我们先建立一个chesscontroller,供下例使用:

@RestController
@RequestMapping("/article")
public class ChessController {@PostMapping("/chess")public Result<String> chess(){return Result.success("读取所有的棋子数据!");}
}

登陆验证需要一个令牌,该令牌就是一段字符串,需要满足下列要求

        承载业务数据,减少后续请求查询数据库次数

        防篡改,保证信息的合法性和有效性

在web开发中最常用的令牌便是JWT令牌

JWT

        全称:JSON Web Token

        定义了一种简洁的、自包含的格式,用于通信双方以json数据格式安全的传输信息

组成:

        第一部分:Header(头),记录令牌类型、签名算法等。例如:{"alg":"HS256","type":"JWT"}

        第二部分:PayLoad(有效载荷),携带一些自定义信息、默认信息等。例如:{"id":"1","us"1"}

        第三部分:Signature(签名),防止Token被篡改、切薄安全性。将header、payload加入指定密钥,通过指定签名算法计算而来

JWT-生成

首先导入对应依赖坐标
       <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
 接下来编写对应的程序
public class JwtTest {@Testpublic void testGen(){Map<String, Object> claims = new HashMap<>();claims.put("id",1);claims.put("username","zmx");//生成jwt代码String token = JWT.create().withClaim("user",claims)//添加载荷.withExpiresAt(new Date(System.currentTimeMillis()+1000*60*12))//添加过期时间.sign(Algorithm.HMAC256("cacb"));//指定算法,配置密钥System.out.println(token);}
}

如上,我输入了一组简单的数据来测试

运行结果:

 

JWT-验证

    @Testpublic void testParse(){//定义字符串,模拟用户传递的tokenString token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6InpteCJ9LCJleHAiOjE3MDY5NTUzNTN9.pZ0fYD5rRMPHXzAq_sLC6RKprPGwIiIHoimAuChTzdk";JWTVerifier jwtVerifier =  JWT.require(Algorithm.HMAC256("cacb")).build();DecodedJWT decodedJWT =  jwtVerifier.verify(token);//验证token,生成一个解析后的JWT对象Map<String, Claim> claims = decodedJWT.getClaims();System.out.println(claims.get("user"));}

使用上例生成的JWT进行验证

结果如下:

 

JWT校验时使用的签名密钥,必须和生成JWT令牌时使用的密钥是配套的

如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效了,令牌非法

登录认证书写

由于JWT生成与验证的代码过于繁琐,所以我们选择使用一个工具类来承载JWT生成与验证的方法

public class JwtUtil {private static final String KEY = "cacb";//接收业务数据,生成token并返回public static String genToken(Map<String, Object> claims) {return JWT.create().withClaim("claims", claims).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)).sign(Algorithm.HMAC256(KEY));}//接收token,验证token,并返回业务数据public static Map<String, Object> parseToken(String token) {return JWT.require(Algorithm.HMAC256(KEY)).build().verify(token).getClaim("claims").asMap();}}
第一步、在登录界时生成token
    @PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{4,16}$") String username, @Pattern(regexp = "^\\S{11,16}$")String password){//查询用户是否存在User lUser = userService.getByUserName(username);if(lUser == null){return  Result.error("用户不存在!");}//查询密码是否正确(密码需要加密后再与数据库中密码比较)if (Md5Util.getMD5String(password).equals(lUser.getPassword())){Map<String,Object> claims = new HashMap<>();claims.put("id",lUser.getId());claims.put("usernname",lUser.getUsername());String token = JwtUtil.genToken(claims);return Result.success(token);}return Result.error("密码错误!");}
第二步、在需要验证token界面对应的接口验证token(复杂) 

还是以list为例(token从请求头中的Authorization读取)

    @GetMapping("/list")public Result<String> chess(@RequestHeader(name = "Authorization")String token , HttpServletResponse response){//验证tokentry {Map<String,Object> claims =  JwtUtil.parseToken(token);return Result.success("读取所有的棋子数据!");} catch (Exception e){//设置HTTP响应状态码为401response.setStatus(401);return Result.error("请登录!");}}

测试结果如下:

 

验证token高效方法、使用拦截器统一验证token令牌
第一步、将验证token转移到拦截器中
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//令牌验证String token =  request.getHeader("Authorization");//验证tokentry {Map<String,Object> claims =  JwtUtil.parseToken(token);//放行return true;} catch (Exception e){//设置HTTP响应状态码为401response.setStatus(401);//不放行return false;}}
}
第二步、书写配置类,注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册拦截器,登录接口和注册接口不拦截registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");}
}

注意:如例中的login与register接口不需要拦截,可以直接放行

第三步、修改简化被拦截的接口内容
    @GetMapping("/list")public Result<String> chess(@RequestHeader(name = "Authorization") String token, HttpServletResponse response) {return Result.success("读取所有的棋子数据!");}

测试结果如下:

 

 

 

 

 

 

相关文章:

SpringBoot实战项目第一天

环境搭建 后端部分需要准备&#xff1a; sql数据库 创建SpringBoot工程&#xff0c;引入对应的依赖(web\mybatis\mysql驱动) 配置文件application.yml中引入mybatis的配置信息 创建包结构&#xff0c;并准备实体类 完成今日开发后项目部分内容如下图示 用户注册于登录部分…...

C# 信号量(Semaphore)详细使用案例

文章目录 简介信号量的工作原理使用场景使用示例其他使用实例1. 数据库连接池管理2. 文件读写同步3. 生产者消费者问题4. 打印任务队列同步5. Web服务器并发请求限制 简介 在C#中&#xff0c;信号量&#xff08;Semaphore&#xff09;是.NET框架提供的一个同步类&#xff0c;位…...

《Docker极简教程》--Docker基础--Docker的基本概念

在这篇文章中我们先大致的了解以下Docker的基本概念&#xff0c;在后续的文章中我们会详细的讲解这些概念以及使用。 一、容器(Container) 1.1 容器的定义和特点 容器的定义 容器是一种轻量级、可移植的软件打包技术&#xff0c;用于打包应用及其依赖项和运行环境&#xff0c…...

【AIGC核心技术剖析】DreamCraft3D一种层次化的3D内容生成方法

DreamCraft3D是一种用于生成高保真、连贯3D对象的层次化3D内容生成方法。它利用2D参考图像引导几何塑造和纹理增强阶段&#xff0c;通过视角相关扩散模型执行得分蒸馏采样&#xff0c;解决了现有方法中存在的一致性问题。使用Bootstrapped Score Distillation来提高纹理&#x…...

新版MQL语言程序设计:外观模式的原理、应用及代码实现

文章目录 一、什么是外观模式二、外观模式的实现原理三、外观模式的应用范围四、外观模式应用实例银行系统的设计量化交易系统的设计 五、外观模式的代码实现 一、什么是外观模式 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供了一个…...

Docker 搭建mysql 集群(二)

PXC方案 很明显 PXC方案在任何一个节点写入的数据都会同步到其他节点&#xff0c;数据双向同步的&#xff08;在任何节点上都可以同时读写&#xff09; 创建MySQL PXC集群 1 安装PXC镜像 docker pull percona/percona-xtradb-cluster:5.7.21 2 为PXC镜像改名 docker tag pe…...

L1-018 大笨钟-java

输入样例1&#xff1a; 19:05输出样例1&#xff1a; DangDangDangDangDangDangDangDang输入样例2&#xff1a; 07:05输出样例2&#xff1a; Only 07:05. Too early to Dang. java import java.awt.desktop.SystemEventListener; import java.util.Scanner;public class M…...

monaco-editor布局篇(二)-自动换行

monaco-editor的换行方式&#xff0c;主要分为3种情况&#xff1a; 不换行按照编辑器宽度换行按照制定列数换行 主要受wordwrap和wordwrapcolumn控制&#xff0c;具体如下&#xff1a; 取值含义off不换行&#xff0c;会一直滚动on换行&#xff0c;文本将在视区宽度内自动换行…...

08-常用集合(容器)

上一篇&#xff1a; 07-使用Package、Crates、Modules管理项目 Rust 的标准库包含许多非常有用的数据结构&#xff0c;称为集合。大多数其他数据类型表示一个特定值&#xff0c;但集合可以包含多个值。与内置的数组和元组类型不同&#xff0c;这些集合指向的数据存储在堆上&…...

CentOS 中文乱码

CentOS 中文乱码 1、 查看自己系统有没有安装中文语言包&#xff0c;可使用 locale -a 命令列出所有可用的语言环境 如果有中文&#xff0c;则不用安装&#xff0c;如果没有&#xff0c;需要重新安装&#xff0c;使用 yum install kde-l10n-Chinese 2、 修改 i18n 和 locale…...

Java List中对象根据id去重,并处理重复对象的某个字段

List中对象根据id去重 一、需求二、解决 一、需求 参考文章:https://blog.csdn.net/A_Gui_Code/article/details/106978867 对在list集合中对象根据主键id去重&#xff0c;同时需要对重复对象的某个字段进行单独处理。 例如&#xff0c;对象包含字段如下, 当某个对象重复时&a…...

小周学JAVA—八股六

自动装箱和拆箱 Java中基础数据类型与它们对应的包装类见下表&#xff1a; 原始类型包装类型booleanBooleanbyteBytecharCharacterfloatFloatintIntegerlongLongshortShortdoubleDouble 装箱&#xff1a;将基础类型转化为包装类型。 拆箱&#xff1a;将包装类型转化为基础类…...

【深度学习】从0完整讲透深度学习第2篇:TensorFlow介绍和基本操作(代码文档已分享)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论深度学习相关知识。可以让大家熟练掌握机器学习基础,如分类、回归&#xff08;含代码&#xff09;&#xff0c;熟练掌握numpy,pandas,sklearn等框架使用。在算法上&#xff0c;掌握神经网络的数学原理&#xff0c;手动实…...

题目: 有1234个数字, 组成多个互不相同且无重复数字的三位数? 都是多少?

lua脚本如下 最原始的解题方法 local str{} local i, j, k0, 0, 0 for i1, 4 do for j1, 4 do for k1, 4 do if i~j and i~k and j~k then str[#str1]i..j..k end end end end print("组成的数有"..#str) print(table.unpack(str)) 运行的结果如下 组成的数有24 1…...

由亚马逊云科技 Graviton4 驱动的全新内存优化型实例 Amazon EC2 实例(R8g),现已开放预览

下一代 Amazon Elastic Compute CloudAmazon EC2) 实例的预览版现已公开 提供。全新的 R8g 实例 搭载新式 Graviton4 处理器&#xff0c;其性价比远超任何现有的内存优化实例。对于要求较高的内存密集型工作负载&#xff0c;R8g 实例是不二之选&#xff1a;大数据分析、高性能数…...

sqlserver alwayson部署文档手册

1、ALWAYSON概述 详细介绍参照官网详细文档,我就不在这里赘述了&#xff1a; https://learn.microsoft.com/zh-cn/sql/database-engine/availability-groups/windows/overview-of-always-on-availability-groups-sql-server?viewsql-server-ver16 下图显示的是一个包含一个…...

【FFmpeg】ffplay 命令行参数 ① ( 设置播放分辨率 | 禁用 音频 / 视频 / 字幕 选项 )

文章目录 一、ffplay 命令行参数 - 设置播放分辨率1、强制设置通用播放分辨率 -x -y 参数2、命令行示例 - 正常播放视频3、命令行示例 - 强制设置播放分辨率4、设置 YUV 播放分辨率 -video_size 和 像素设置 -pixel_format5、全屏播放 -fs 参数 二、ffplay 命令行参数 - 禁用 音…...

CSS写渐变边框线条

box-sizing: border-box; border-top: 1px solid; border-image: linear-gradient(to right, red, blue) 1;...

【Linux网络编程三】Udp套接字编程网络应用场景

【Linux网络编程三】Udp套接字编程网络应用场景 应用场景一&#xff1a;远程命令执行应用场景二&#xff1a;与Windos端相互通信应用场景三&#xff1a;简单聊天1.多线程化2.输入输出分开 应用场景一&#xff1a;远程命令执行 简单的服务器上一篇已经完成&#xff0c;接下来我…...

计算机网络实验二

目录 实验二 交换机的基本配置 1、实验目的 2、实验设备 &#xff08;1&#xff09;实验内容&#xff1a; &#xff08;2&#xff09;练习&#xff1a; 1.实验内容一&#xff1a;&#xff08;交换机的配置方式&#xff09; 2.实验内容二&#xff1a;&#xff08;交换机…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...