[Java]SpringBoot登录认证流程详解
登录认证
登录接口
1.查看原型
2.查看接口
3.思路分析
登录核心就是根据用户名和密码查询用户信息,存在则登录成功, 不存在则登录失败
4.Controller
@Slf4j
@RestController
public class LoginController {@Autowiredprivate EmpService empService;/*** 登录的方法** @param emp* @return*/@PostMapping("/login")public Result login(@RequestBody Emp emp) {log.info("员工登录:{}", emp);Emp e = empService.login(emp);return e != null ? Result.sucess():Result.error("用户名或密码错误");}
}
5.Server
/*** 员工管理*/
public interface EmpService {/*** 员工登录* @param emp*/Emp login(Emp emp);
}
@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;/*** 员工登录* @param emp* @return*/@Overridepublic Emp login(Emp emp) {return empMapper.getByUsernameAndPassword(emp);}
}
6.Mapper
/*** 员工管理*/
@Mapper
public interface EmpMapper {/*** 根据用户名和密码查询账户信息* @param emp* @return*/@Select("select * from emp where username = #{username} and password = #{password}")Emp getByUsernameAndPassword(Emp emp);}
7.接口测试
登录校验
前端的所有请求, 都需要经过登录判断, 登录了进行正常操作, 没登录则返回错误信息, 让用户去登录页
会话跟踪
会话: 用户打开浏览器,访问web服务器的资源,会话建立,直到一方断开连接,会话结束, 在一次会话中, 可以包含多次请求和响应
会话跟踪: 一种维护浏览器状态的方法, 服务器需要识别多次请求是否来自同一浏览器, 以便在同一次会话的多次请求间共享数据
Cookie
客户端会话跟踪技术
- 优点:
- HTTP协议支持的技术
- 服务器返回Cookie / 浏览器保存Cookie / 客户端携带Cookie 都是自动完成的
- 缺点:
- 移动端APP无法使用Cookie
- 不安全, 用户可以自己禁用Cookie
- Cookie不能跨域
- 当前地址和请求地址的 协议, 域名和端口 出现不同, 就形成了跨域
示例
@Slf4j
@RestController
public class SessionController {//设置Cookie@GetMapping("/c1") public Result cookie(HttpServletResponse response){//通过HttpServletResponse获取响应对象//设置Cookit的name和valueresponse.addCookie(new Cookie("login_username","itheima")); return Result.success();}//获取Cookie@GetMapping("/c2")public Result cookie2(HttpServletRequest request){//获取所有的CookieCookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) {if(cookie.getName().equals("login_username")) { //找到name为login_username的CookieSystem.out.println("login_username:" + cookie.getValue());}}return Result.success();}
}
- 后端只要设置了cookie, hppt就会自动在响应头的Set-Cookie属性中携带cookie信息
- 浏览器解析http时, 如果发现了Set-Cookie信息, 就会把信息自动储存在本地
- 当下次请求时, 就会在请求头的Cookie属性中自动携带该cookie信息
Session
服务端会话跟踪技术
- Session是基于Cookie实现的
- Cooike直接把数据存储在浏览器, 不安全
- Session是把Seeion ID存在在浏览器, 数据存储在服务器
- 优点: 数据存储在服务端, 安全
- 缺点:
- Session基于Cookie实现,也继承了其缺点
- 服务器集群环境下无法直接使用Session
示例
@Slf4j
@RestController
public class SessionController {// 往HttpSession中存储值@GetMapping("/s1")public Result session1(HttpSession session) {log.info("HttpSession-s1:{}", session.hashCode());//往session中存储值session.setAttribute("loginUser", "tom"); return Result.success();}// 从HttpSession中获取值@GetMapping("/s2")public Result session2(HttpServletRequest request) {HttpSession session = request.getSession();log.info("HttpSession-s2:{}", session.hashCode());//从session中获取数据Object loginUser = session.getAttribute("loginUser"); log.info("loginUser:{}", loginUser);return Result.success(loginUser);}
}
- 后端只要设置了Session, hppt就会自动在响应头的Set-Cookie属性中携带Session ID信息
- 浏览器解析http时, 如果发现了Set-Cookie信息, 就会把信息自动储存在本地
- 当下次请求时, 就会在请求头的Cookie属性中自动携带该Session ID信息
JWT令牌
介绍
全称 JSON Web Token, 定义了一种简洁的, 自包含的格式, 用于在通信双方以JSON数据格式安全的传输信息, 由于数字签名的存在, 这些信息是可靠的
- 官网: JSON Web Tokens - jwt.io
- 执行流程
- 登录成功后, 生成令牌, 响应给前端, 前端保存起来
- 前端的后续请求, 都携带JWT令牌
- 后端在处理请求之前, 先校验令牌, 再处理业务
- 优缺点
- 支持PC/移动端/小程序
- 解决集群环境下的认证问题
- 减轻服务器存储压力
- 需要自己实现
JWT令牌本质是JSON对象, JSON对象储存数据, 经过Base64编码后, 在拼接上数字签名就形成了JWT令牌
- Base64: 是一种基于64个可打印字符(A-Z a-z 0-9 + /) 来表示二进制数据的编码方式
生成与校验
// JWT依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
@Test
public void testGenJwt(){Map<String,Object> claims = new HashMap<>();claims.put("id",1);claims.put("name","tom");// 生成JWT令牌String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256,"itheima") //指定签名算法.setClaims(claims) //自定义内容(载荷).setExpiration(new Date(System.currentTimeMillis()+3600*1000)) //设置有效期为1H.compact();System.out.println(jwt);
}
@Test
public void testParseJWT(){// 解析JWT令牌Claims claims = Jwts.parser().setSigningKey("itheima").parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5NjE0OTc2Nn0.7-rlCqZQ1XssTdNOM2os0s-mpuKHzUkwFWtsvMOlalY").getBody();System.out.println(claims);
}
- JWT校验时使用的签名秘钥, 必须和生成JWT令牌时使用的秘钥配套
- 如果JWT令牌解析时报错, 说明JWT令牌被篡改 或者 失效了
登录校验-下发令牌
引入jwt依赖
// JWT依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
引入jwt工具类
public class JwtUtils {//指定签名秘钥private static String signKey = "itheima";//指定过期时间(12h)private static Long expire = 43200000L;/*** 生成JWT令牌* @param claims JWT第二部分负载 payload 中存储的内容* @return*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return jwt;}/*** 解析JWT令牌* @param jwt JWT令牌* @return JWT第二部分负载 payload 中存储的内容*/public static Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
}
生成jwt令牌, 并返回给前端
@Slf4j
@RestController
public class LoginController {@Autowiredprivate EmpService empService;/*** 登录的方法** @param emp* @return*/@PostMapping("/login")public Result login(@RequestBody Emp emp) {log.info("员工登录:{}", emp);Emp e = empService.login(emp);//登录成功,生成jwt令牌,并下发令牌if(e!=null) {//把用户信息存入Map集合Map<String,Object> claims = new HashMap<>();claims.put("id",e.getId());claims.put("name",e.getName());claims.put("username",e.getUsername());//生成jwt令牌String jwt = JwtUtils.generateJwt(claims); //jwt令牌包含了用户信息// 下发令牌return Result.success(jwt);}//登录失败,返回错误信息return Result.error("用户名或密码错误");}
}
接口测试
过滤器
快速入门
filter过滤器是 javaWeb 三大组件( Servler / Filter / Listener )之一
- 过滤器可以拦截请求, 从而实现特殊功能
- 过滤器一般完成一些通用操作, 比如登录校验, 统一编码处理, 敏感字处理等
定义过滤器: 定义一个类, 实现Filter接口, 重写其所有方法
// 设置拦截请求的路径
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {@Override public void init(FilterConfig filterConfig) throws ServletException {//初始化的方法,服务器启动时只调用一次System.out.println("服务器启动了");Filter.super.init(filterConfig);}@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 拦截到请求之后调用,调用多次System.out.println("拦截到请求了");// 设置放行, 不放行前端拿不到响应结果filterChain.doFilter(servletRequest,servletResponse);// 放行后的代码执行完, 还会回到拦截器System.out.println("放行后的逻辑");}@Override public void destroy() {//销毁的方法,服务器关闭时只调用一次System.out.println("服务器关闭了");Filter.super.destroy();}
}
- 注意Filter是 javax.servlet 下的包
- 实际业务中, init 方法和 destroy方法不需要重写, 使用默认实现即可
配置过滤器: 过滤器是JavaWeb组件, 不是Springboot组件, 所以需在再启动类进行配置, 才能生效
//开启对servlet组件的支持
@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {public static void main(String[] args) {SpringApplication.run(TliasWebManagementApplication.class, args);}}
详解
拦截器的执行流程
- 请求被拦截后, 先执行放行前的逻辑, 符合条件放行
- 方形后访问资源, 资源访问完成后还会回到过滤器中
- 回到过滤器后, 会执行过滤器放行后的逻辑
根据需求, 设置过滤器器的拦截路径
过滤器链: 一个web应用中, 可以配置多个过滤器,多个过滤器形成过滤器链
- 顺序: 定义多个过滤器之后, 过滤器生效的优先级, 是按照过滤器类名(字符串)的自然排序
登录校验-Filter
使用过滤器完成前端请求的登录校验
- 除了登录请求, 所有的请求都要进行令牌校验
- 拦截请求之后, token存在并且通过校验, 才能继续访问资源, 否则返回登录错误
登录校验实现的步骤
// 登录校验过滤器
@Slf4j
@WebFilter(urlPatterns = "/*")
public class loginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;// 1,获取urlString url = req.getRequestURI().toString();log.info("请求到的url: {}", url);// 2,判断url是否包含'login'if (url.contains("login")) {log.info("登录操作, 放行...");chain.doFilter(request, response);return;}// 3, 获取请求头中的tokenString jwt = req.getHeader("token");// 4, 判断令牌是否存在// 使用springframework提供的工具类if (!StringUtils.hasLength(jwt)) {log.info("请求头token为空");Result error = Result.error("NOT_LOGIN");// 手动转换 把 对象-> JSON ------->使用阿里巴巴fastJSON插件String notLogin = JSON.toJSONString(error);resp.getWriter().write(notLogin);return;}// 5, 解析tokentry {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();// 解释失败log.info("解释令牌失败");Result error = Result.error("NOT_LOGIN");String notLogin = JSON.toJSONString(error);resp.getWriter().write(notLogin);return;}// 6, 放行log.info("令牌合法, 放行");chain.doFilter(request, response);}
}
- 在springbott中, 响应的数据会被自动封装为JSON对象
- 在过滤器中, 我们要手动把数据转成JSON, 才能响应给前端
// fastjson依赖
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version>
</dependency>
接口测试
拦截器
快速入门
定义拦截器: 实现HandlerIntereptor接口, 并重写其所有方法
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行, 返回true放行,反回false不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {System.out.println("目标资源方法运行前运行");return true;}@Override //目标资源方法运行后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("目标资源方法运行后");}@Override //视图渲染完毕后运行,最后运行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("视图渲染完毕后");}
}
- 拦截器的所有方法都有默认实现, 定义拦截器时按需实现接口的方法即可
注册拦截器
@Configuration //标明配置类
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册拦截器,并指定监听路径registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**")}
}
详解
配置拦截路径: 拦截器可以根据需求, 配置不同的拦截路径
拦截器的执行流程
过滤器和拦截器的区别
登录校验-Interceptor
使用拦截器完成登录校验, 登录校验的代码的逻辑是不变的, 只是放行方式不同
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行, 返回true放行,反回false不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {//1,获取请求URLString url = req.getRequestURL().toString();log.info("请求的URL:{}", url);//2,判断是否包含login,登录操作直接放行if (url.contains("login")) {log.info("登录操作,放行");return true;}//3,获取请求头的令牌String jwt = req.getHeader("token");//4,判断令牌是否存在,如果不存在返回错误信息if (!StringUtils.hasLength(jwt)) {log.info("请求头token信息为空");// 创建错误对象Result error = Result.error("NOT_LOGIN");// 手动转换 对象->JSONString notLogin = JSONObject.toJSONString(error);// 响应数据resp.getWriter().write(notLogin);// 阻止代码继续往下执行return false;}//5,解析token,如果解析失败则token无效try {JwtUtils.parseJWT(jwt);} catch (Exception e) {// 输出错误日志e.printStackTrace();log.info("解析令牌失败,返回错误信息");// 创建错误对象Result error = Result.error("NOT_LOGIN");// 手动转换 对象->JSONString notLogin = JSONObject.toJSONString(error);// 响应数据resp.getWriter().write(notLogin);// 阻止代码继续往下执行return false;}//6,token合法,放行log.info("token合法,放行");return true;}
}
@Configuration //标明配置类
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册拦截器,并指定监听路径,排除监听路径registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");}
}
相关文章:

[Java]SpringBoot登录认证流程详解
登录认证 登录接口 1.查看原型 2.查看接口 3.思路分析 登录核心就是根据用户名和密码查询用户信息,存在则登录成功, 不存在则登录失败 4.Controller Slf4j RestController public class LoginController {Autowiredprivate EmpService empService;/*** 登录的方法** param …...

【Day08】
目录 MySQL-多表查询-概述 MySQL-多表查询-内连接 MySQL-多表查询-外连接 MySQL-多表查询-[标量、列]子查询 MySQL-多表查询-[行、表]子查询 MySQL-多表查询-案例 MySQL-事务-介绍与操作 MySQL-事务-四大特性 MySQL-索引-介绍 MySQL-索引-结构 MySQL-索引-操作语法 …...

mongodb在Java中条件分组聚合查询并且分页(时间戳,按日期分组,年月日...)
废话不多说,先看效果图: SQL查询结果示例: 多种查询结果示例: 原SQL: db.getCollection("hbdd_order").aggregate([{// 把时间戳格式化$addFields: {orderDate: {"$dateToString": {"for…...

怎么样处理浮毛快捷又高效?霍尼韦尔、希喂、米家宠物空气净化器实测对比
掉毛多?掉毛快?猫毛满天飞对身体有危害吗?多猫家庭经验分享篇: 一个很有趣的现象,很多人在养猫、养狗后耐心都变得更好了。养狗每天得遛,养猫出门前得除毛,日复一日的重复磨练了极好的耐心。我家…...
什么是WebGL技术?有什么特点?应用领域有哪些?
WebGL(Web Graphics Library)技术是一种在Web浏览器中渲染交互式3D和2D图形的JavaScript API。以下是对WebGL技术的详细解析: 一、定义与起源 定义: WebGL全称Web Graphics Library,即网络图形库,它允许…...

500W逆变器(一)
EG8015_24V_500W 这款逆变器是基于 EG8015 SPWM 专用芯片而设计的方案。其额定的输出功率为 500 瓦, 最大输出功率为 600 瓦,输出电压为 220V10%,输出频率为 50Hz0.1Hz,额定输出电流为 2.3 安培。 穿越机降落的时候不要垂直降落,要…...

ubuntu 22.04 编译安装新内核
1、普通用户登录系统 查看当前内核版本 $ uname -r 5.15.0-118-generic 2、下载内核源码 www.kernel.org 用户home目录新建子目录linux,下载并解压 linux-5.15.165.tar.xz 3、创建起始的配置文件.config Configuration targets (见linux kernel i…...
Linux 文件权限与属性管理
概述 Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux 对不同用户访问同一文件(包括目录文件)的权限做了详细的规定。 文件属性查看 在 Linux 中࿰…...

Django学习实战篇三(适合略有基础的新手小白学习)(从0开发项目)
前言: 在上一章中,我们对Django的Model层有了比较全面的认识,本章就来配置Django自带的admin。这里需要认识到,Django的Model层是很重要的一环,无论是对于框架本身还是对于基于Django框架开发的大多数系统而言。因为一…...

【SPIE独立出版,连续2届稳定EI检索!】2024年第三届信息学,网络与计算技术国际学术会议(ICINC2024,10月25-27)
2024年第三届信息学,网络与计算技术国际学术会议(ICINC2024)将于2024年10月25-27日于中国郑州召开。 会议将围绕信息技术与通信,网络与计算技术等在相关领域中的最新研究成果,为来自国内外高等院校、科学研究所、企事业单位的专家、教授、学者…...
.NET/C#⾯试题汇总系列:基础语法
1. 字符串中string strnull和string str""和string strstring.Empty的区别? string str null;:这种方式声明了一个字符串变量str,并将其初始化为null。这意味着str不指向任何实际的字符串对象。如果你试图访问str的属性或方法&…...

【论文阅读】SwiftTheft: A Time-Efficient Model Extraction Attack Framework(2024)
完整标题 SwiftTheft: A Time-Efficient Model Extraction Attack Framework Against Cloud-Based Deep Neural Networks 摘要 With the rise of artificial intelligence(人工智能) and cloud computing(云计算), machine-learning-as-a-service platforms(机器学习即…...
springcloud间通信的方式
在 Spring Cloud 中,主要有以下几种通信方式: 一、基于 HTTP 的 RESTful API 工作原理: 这是一种常见的通信方式,各个微服务通过发送 HTTP 请求来相互调用。服务提供者暴露 RESTful API 接口,服务消费者通过 HTTP 客户…...

【C++ Qt day9】
2、将day1做的登录界面升级优化【资源文件的添加】 3、 使用手动连接,将登录框中的取消按钮使用第2种方式的连接到自定义的槽函数中,在自定义的槽函数中调用关闭函数 将登录按钮使用qt4版本的连接到自定义的槽函数中,在槽函数中判断ui界面上…...

中国传媒业人工智能应用发展图谱2024
易观分析:传媒产业是指以传播各类信息、知识为核心,通过多种媒介形式进行内容生产、发布和分发的综合性产业。技术的进步和应用对于传媒产业发展变革起到了核心驱动力的作用,2022年生成式AI进入应用爆发期,不仅带动了人工智能产业…...
RTX3060 FP64测试与猜想
RTX3060 FP64测试与猜想 一.小结二.查看FP64的峰值性能三.打满FP64、FP32的利用率,对比差异四.进一步证明pipe_fp64_cycles_active并不是2个fp64 core的metrics RTX3060 FP64测试与猜想 一.小结 RTX3060 compute capability为8.6,每个SM有2个FP64 core。每个cycle可输出2个fp…...
uniapp写移动端常见问题汇总
1. 手机顶部状态栏遮挡 写在需要的地方 <view class"status_bar" style"height: var(--status-bar-height); width: 100%;">2. 手机顶部状态栏字体颜色 // pages.json "statusBarStyle": "light",3. 背景覆盖全屏 page{widt…...

Linux运维排查常见故障_在tmp目录下有大量包含picture_ 的临时文件,每天晚上2 30需要对一天前的文件进行
echo“”>>/etc/security/limits.conf echo“*softnproc65535″>>/etc/security/limits.conf echo“*hardnproc65535″>>/etc/security/limits.conf echo“*softnofile65535″>>/etc/security/limits.conf echo“*hardnofile65535″>>/etc/secur…...

基于SpringBoot的智能制造云平台系统的设计与实现计算机毕设
一、选题背景与意义(300字左右) 根据工业4.0智能制造生态链中云工厂在实际生产当中的工作流程进行充分调研和整理出来的,描述最终用户在本系统中对于生产订单的处理、排产、以及生产的完整在线处理流程和业务需求的文档。 针对制造业而言&a…...

论文翻译:arxiv-2024 Benchmarking Benchmark Leakage in Large Language Models
Benchmarking Benchmark Leakage in Large Language Models https://arxiv.org/abs/2404.18824 在大型语言模型中基准测试泄露的基准测试 文章目录 在大型语言模型中基准测试泄露的基准测试摘要1 引言 图1:不同模型在基准测试的训练集上进行逐字训练相对于测试集以…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...