黑马JavaWeb后端案例开发(包含所有知识点!!!)

目录

1.准备工作

环境搭建

开发规范 

 REST(REpresentation State Transfer),表述性状态转换,它是一种软件架构风格

注意事项

统一响应结果

2.部门管理功能

查询部门

 删除部门

新增部门

@RequestMapping 

 3.员工管理功能

分页查询

批量删除员工

​编辑新增员工 

文件上传

简介

本地存储

修改员工

查询回显

修改员工

参数配置化

配置格式

yml数据格式

4.用户登录功能

登录功能

登录校验

会话技术

会话跟踪方案对比

JWT令牌

JWT-生成

JWT-校验

登录-生成令牌

过滤器Filter

入门程序

FIlter执行流程

Filter拦截路径

过滤器链

登录校验Filter

 拦截器Interceptor

快速入门

拦截器-拦截路径

拦截器-执行流程

登录校验Interceptor

 异常处理

5.事务管理

Spring事务管理

事务属性-回滚

事务属性-传播行为

场景

6.AOP(面向切面编程)

AOP概述

AOP核心概念

通知类型 

@PointCut

通知顺序

切入点表达式

execution表达式

 @Annotation注解表达式

连接点

7.配置优先级

8.Bean管理

获取bean

bean作用域

第三方bean

9.SpringBoot原理

自动配置原理

@Conditional注解


1.准备工作

  • 环境搭建

  • 开发规范 

 REST(REpresentation State Transfer),表述性状态转换,它是一种软件架构风格

注意事项
  • REST是风格,是约定方式,约定不是规定,可以打破
  • 描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books
统一响应结果
  • 前后端交互统一响应结果Result
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {private Integer code;//响应码,1 代表成功; 0 代表失败private String msg;  //响应信息 描述字符串private Object data; //返回的数据//增删改 成功响应public static Result success(){return new Result(1,"success",null);}//查询 成功响应public static Result success(Object data){return new Result(1,"success",data);}//失败响应public static Result error(String msg){return new Result(0,msg,null);}
}

2.部门管理功能

查询部门

 

/*** 部门管理Controller*/
@Slf4j
@RestController
public class DeptController {//    private static Logger log = LoggerFactory.getLogger(DeptController.class);@Autowiredprivate DeptService deptService;//    @RequestMapping(value = "/depts",method = RequestMethod.GET) //指定请求方式为GET@GetMapping("/depts")public Result list(){log.info("查询全部部门数据");//调用service查询部门数据List deptList = deptService.list();return Result.success(deptList);}
}@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic List list() {return deptMapper.list();}
}@Mapper
public interface DeptMapper {/*** 查询全部部门* @return*/@Select("select * from dept")List list();
}

 删除部门

 /*** 删除部门数据*/@DeleteMapping("/depts/{id}")public Result delete(@PathVariable Integer id){log.info("根据id删除部门:{}",id);DeptService.delete(id);return Result.success();}@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);}/*** 根据id删除部门* @param id*/@Delete("delete  from dept where id = #{id}")void deleteById(Integer id);

新增部门

 /*** 新增部门数据*/@PostMapping("/depts")public Result add(@RequestBody Dept dept){log.info("新增部门:{}" , dept);deptService.add(dept);return Result.success();}@Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}@Insert("insert into mybatis.dept(name, create_time, update_time ) values (#{name},#{createTime},#{updateTime})")void insert(Dept dept);

@RequestMapping 


 3.员工管理功能

分页查询

@Slf4j
@RestController
public class EmpController {@Autowiredprivate EmpService empService;@GetMapping("/emps")public Result page(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){log.info("分页查询,参数:{},{}",page,pageSize);//调用service分页查询PageBean pageBean = empService.page(page,pageSize);return Result.success(pageBean);}}@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;@Overridepublic PageBean page(Integer page, Integer pageSize) {//1.获取总记录数Long count = empMapper.count();//2.获取分页查询结果列表Integer start = (page - 1) * pageSize;List<Emp> empList = empMapper.page(start, pageSize);//3.封装PageBean对象PageBean pageBean = new PageBean(count, empList);return pageBean;}
}@Mapper
public interface EmpMapper {/*** 查询总记录数* @return*/@Select("select count(*) from emp")public Long count();/*** 分页查询,获取列表数据* @param start* @param pageSize* @return*/@Select("select * from emp limit #{start},#{pageSize}")public List<Emp> page(Integer start,Integer pageSize);
}

批量删除员工

新增员工 

文件上传

简介
  • 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程

前端页面三要素

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>上传文件</title>
</head>
<body><form action="/upload" method="post" enctype="multipart/form-data">姓名: <input type="text" name="username"><br>年龄: <input type="text" name="age"><br>头像: <input type="file" name="image"><br><input type="submit" value="提交"></form></body>
</html>

服务端接口 

  @PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image){log.info("文件上传:{},{},{}" ,username,age,image);return Result.success();}
本地存储
  • 在服务端,接收到上传来的文件之后,将文件存储在本地服务器磁盘中
 @PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image) throws IOException {log.info("文件上传:{},{},{}" ,username,age,image);//获取原始文件名String originalFilename = image.getOriginalFilename();//构造唯一的文件名 - uuid(通用唯一识别码)int index = originalFilename.lastIndexOf(".");String extname = originalFilename.substring(index);String newFileName = UUID.randomUUID().toString()+ extname;log.info("新的文件名: {}" ,newFileName);//将文件存储在服务器的磁盘目录中E:\imagesimage.transferTo(new File("E:\\images\\" + newFileName));return Result.success();}

在Springboot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以进行如下配置:

#配置单个文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大大小的限制(一次请求中是可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB

修改员工

  • 查询回显

  • 修改员工

参数配置化

配置格式

yml数据格式
#定义对象/Map集合
user:name:Tomage:20address:beijing#定义数组/List/Set
hobby:- java- C- game- sport

4.用户登录功能

  • 登录功能

@RestController
@Slf4j
public class loginController {private EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("员工登录:{}",emp);Emp e = empService.login(emp);return e != null ?Result.success():Result.error("用户名或密码错误");}
}@Overridepublic Emp login(Emp emp) {return empMapper.getByUsernameAndPassword(emp);}/*** 根据用户名和密码查询员工* @param emp* @return*/@Select("select * from emp where username = #{usernae} and password = #{password}")Emp getByUsernameAndPassword(Emp emp);
}

登录校验

会话技术
  • 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。
  • 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
  • 会话跟踪方案:
    • 客户端会话跟踪技术:Cookie
    • 服务端会话跟踪技术:Session
    • 令牌技术(企业主流)
会话跟踪方案对比

JWT令牌
  • 全称:JSON Web Token
  • 定义了一张简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息
  • 组成:
    • 第一部分:Header(头),记录令牌类型、签名算法
    • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息
    • 第三部分:Signature(签名),防止Token被篡改、确保安全性

  • 场景:登录认证
    • ①登录成功后,生成令牌
    • ②后续每个请求,都有携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理
JWT-生成

JWT-校验

登录-生成令牌
 @Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){Emp e = empService.login(emp);//登录成功,生成令牌,下发令牌if(e != null){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);return  Result.success(jwt);}return Result.error("错误");}
过滤器Filter
  • 概念:是JavaWeb三大组件之一
  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
入门程序

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {@Override  //初始化方法,只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Override //拦截到请求之后调用,调用多次public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("拦截到了请求");//放行filterChain.doFilter(servletRequest, servletResponse);}@Override  //销毁方法,只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}
FIlter执行流程

Filter拦截路径

过滤器链
  • 介绍:一个Web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链
  • 顺序:注解配置的Filter,优先级是按照过滤器类名的自然排序
登录校验Filter

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;//1.获取请求urlString url = req.getRequestURI().toString();log.info("请求的url:{}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("login")){log.info("登录操作,放行...");filterChain.doFilter(servletRequest, servletResponse);return;}//3.获取请求头中的令牌(token)String jwt = req.getHeader("token");//4.判断令牌是否存在,如果不存在,返回错误结果if(!StringUtils.hasLength(jwt)){log.info("请求头token为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//5.解析token,如果解析失败,返回错误结果try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失败,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//6.放行log.info("令牌合法,放行");filterChain.doFilter(servletRequest, servletResponse);}
}
 拦截器Interceptor
  • 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架提供的,用来动态拦截控制器方法的执行
快速入门

拦截器-拦截路径

拦截器-执行流程

  • 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口
  • 拦截范围不同:过滤器会拦截所有的资源,而拦截器只会拦截Spring环境的资源 
登录校验Interceptor

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行,返回true:放行,返回false,不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {//1.获取请求urlString url = req.getRequestURI().toString();log.info("请求的url:{}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("login")){log.info("登录操作,放行...");return true;}//3.获取请求头中的令牌(token)String jwt = req.getHeader("token");//4.判断令牌是否存在,如果不存在,返回错误结果if(!StringUtils.hasLength(jwt)){log.info("请求头token为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);return false;}//5.解析token,如果解析失败,返回错误结果try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失败,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);return false;}//6.放行log.info("令牌合法,放行");return true;}@Override //目标资源方法运行后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}@Override //视图渲染完毕后运行,最后运行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
 异常处理

/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class) //捕获所有异常public Result ex(Exception ex){ex.printStackTrace();return Result.error("对不起,操作失败,请联系管理员");}
}

5.事务管理

Spring事务管理

  • 注解:@Transactional
  • 位置:业务层的方法上、类上、接口上
  • 作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
 @Transactional //spring事务管理@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);int i = 1/0;empMapper.deleteByDeptId(id);}

事务属性-回滚

rollbackFor:默认情况下,只有出现运行时异常RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务。

  @Transactional(rollbackFor = Exception.class) //spring事务管理@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);int i = 1/0;empMapper.deleteByDeptId(id);}

事务属性-传播行为

propagation:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制

场景
  • REQUIRED:大部分情况下都是用该传播行为
  • REQUIRED_NEW:当我们不希望事务之间相互影响时,可以使用。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功

6.AOP(面向切面编程)

AOP概述

  • AOP:Aspect Oriented Programing,其实就是面向特定方法编程
  • 场景:

  • 实现:
    • 动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程

AOP核心概念

  • 连接点:JoinPoint,可以被AOP控制的方法
  • 通知:Advice,指哪些重复的逻辑,也就是共性功能
  • 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
  • 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)

通知类型 

@PointCut

  • 该注解的作用是将公共的切入点表达式抽取出来,需要用到时引用该切点表达式即可

通知顺序

切入点表达式

  • 描述切入点方法的一种表达式
  • 作用:主要用来决定项目中的哪些方法需要加入通知
  • 常见形式:
    • 1.execution:根据方法的签名来匹配
    • 2.@annotation:根据注解匹配
execution表达式

 @Annotation注解表达式

连接点

  • 在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等
    • 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint
    • 对于其他四种通知,获取连接点只能使用JoinPoint,它是ProceedingJoinPoint的父类型


7.配置优先级


8.Bean管理

获取bean

  • 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象//获取bean对象@Testpublic void testGetBean(){//根据bean的名称获取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);//根据bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);//根据bean的名称 及 类型获取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);
}

bean作用域

第三方bean

@Bean

  • 如果要管理的bean对象来自第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解
  • 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类
@Configuration //配置类
public class CommonConfig {//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名public SAXReader reader(DeptService deptService){System.out.println(deptService);return new SAXReader();}}


9.SpringBoot原理

  • 起步依赖:依赖传递
  • 自动配置

Springboot的自动配置就是当spring容器启动后,一些配置类、bean对象IU自动存入到了IOC容器,不需要我们手动去声明,简化了开发

自动配置原理

@Conditional注解

  • 作用:按照一定的条件进行判断,在满足条件后才会注册对应的bean对象到Spring IOC容器中
  • 位置:方法、类
  • @Conditional本身是一个父注解,派生出大量的子注解
    • @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器

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

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

相关文章

Android 10.0 Launcher 启动流程

在前面SystemUI启动流程中说到&#xff0c;在SystemServer中会去启动各种系统服务&#xff0c;这里的launcher也是启动的其中一个服务ActivityManagerService去启动的。在android10之前&#xff0c;系统四大组件的启动都是在ActivityManagerService中&#xff0c;在android10中…

最短路问题中的朴素版Dijkstra算法

最短路问题的朴素版Dijkstra算法 题目 最短路问题需要用到下面的算法&#xff08;n代表点的数量&#xff0c;m代表边的数量&#xff09; 朴素版和堆优化版的Dijkstra算法的区别是&#xff0c;朴素版比较适合稠密图&#xff0c;堆优化版适合稀疏图&#xff0c;稠密图代表它的边…

python | TypeError: list indices must be integers or slices, not tuple

python | TypeError: list indices must be integers or slices, not tuple 在Python编程中&#xff0c;TypeError: list indices must be integers or slices, not tuple 是一个常见的错误。此错误通常发生在尝试使用非整数&#xff08;如元组&#xff09;作为列表索引时。本…

RK3568笔记四十九:W25Q64驱动开发(硬件SPI1)

若该文为原创文章&#xff0c;转载请注明原文出处。 一、SPI介绍 串行外设接口 (Serial Peripheral interface) 简称 SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并 且在芯片的管脚上只占用四根线&#xff0c;节约了芯片的管脚。 …

Python写UI自动化--playwright(在UI元素上悬停)

要在UI元素上执行鼠标悬停&#xff08;hover&#xff09;动作&#xff0c;可以使用page.hover()方法。这个方法使鼠标指针移动到指定的元素上&#xff0c;就像用户将鼠标悬停在该元素上一样。这对于触发那些依赖于鼠标悬停事件的行为&#xff08;如显示下拉菜单、提示框或其他动…

[极客大挑战 2019]PHP1

打开题目 游戏界面 猜测php里面有文件&#xff0c;我们可以用dirsearch 扫描一下这个服务器 执行命令 dirsearch -u http://2999dfd5-1d43-4a81-a088-9e41c9dccab4.node4.buuoj.cn/ -e php > test.log 最后在log文件中找到一个 200 www.zip 浏览器输入payload下载下来 …

操作系统_内存管理学习心得

1. 操作系统结构 1.1 内核 计算机是由各种外部硬件设备组成的,比如内存、cpu、 硬盘等,如果每个应用都要和这些硬件设备对接通信协议&#xff0c;那这样太累了&#xff0c;所以这个中间人就由内核来负责,让内核作为应用连接硬件设备的桥梁,应用程序只需关心与内核交写&#x…

C++ | Leetcode C++题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size(), left 0, right 0;while (right < n) {if (nums[right]) {swap(nums[left], nums[right]);left;}right;}} };

SpringBoot集成GraalVM创建高性能原生镜像

1. GraalVM 原生镜像的介绍 GraalVM原生镜像为部署和运行Java应用程序提供了一种新的方式。与Java虚拟机相比&#xff0c;原生镜像可以以更小的内存占用和更快的启动时间运行。 它们非常适用于使用容器镜像部署的应用程序&#xff0c;当与 "功能即服务"&#xff08…

短剧系统源码分享,快速搭建部署上线教程

一、短剧系统是什么&#xff1f; 短剧制作平台&#xff0c;作为一站式综合解决方案&#xff0c;集剧本创作、角色设计、场景搭建、视频编辑、便捷发布及深度数据分析能力于一身。该平台精准定位于助力企业利用短剧形式强化品牌传播力并驱动商业价值增长&#xff0c;无论企业是…

什么是IO多路复用?其原理和用途是什么?

什么是IO&#xff1f; IO&#xff1a;Input/Output&#xff0c;即数据的读取&#xff08;接收&#xff09;/写入&#xff08;发送&#xff09;操作&#xff0c;针对不同的数据存储媒介&#xff0c;大致可以分为网络 IO 和磁盘 IO 两种。在 Linux 系统中&#xff0c;为了保证系…

关于Excel表格隔行取列的方法

关于Excel表格隔行取列的方法 1、场景显示2、参考文章 1、场景显示 ①处的公式&#xff1a; INDEX($B3:$G3,(COLUMN(A1)*2)) $B与$G可以限制列不变&#xff1b; COLUMN(A1)返回1&#xff1b; 含义&#xff1a; 在选定区域选择偶数列的数据&#xff1b; 如果是奇数列的话是(COL…

查看RAM和Flash

0 Preface/Foreword 1 查看方法 1.1 map文件中查看 1.1.1 RAM可用情况 在map文件中&#xff0c;搜索字符串&#xff1a;free_ramcp 该字段表示剩余可用的RAM大小&#xff0c;前面对应的是hexadecimal的数值&#xff08;单位Byte&#xff09;&#xff0c;就是剩余可用的RA…

乱弹篇(39)请珍惜懂你的人

今日清晨&#xff0c;笔者照常去到古镇味江河畔垂钓&#xff0c;呼吸着凉爽晨风轻轻吹拂而来的大自然氧吧生产出的优质氧气......忽地&#xff0c;记起已经许久未履行义务了&#xff0c;所以本“人民体验官”今天要推广人民日报官方微博文化产品《有个真朋友是一生的福气》。 截…

Redis:十大数据类型

键&#xff08;key&#xff09; 常用命令 1. 字符串&#xff08;String&#xff09; 1.1 基本命令 set key value 如下&#xff1a;设置kv键值对&#xff0c;存货时长为30秒 get key mset key value [key value ...]mget key [key ...] 同时设置或者获取多个键值对 getrange…

实验21.实现 printf

已完成实验 已完成实验链接 简介 实验 21. 实现 printf 总结 简化系统调用和中断&#xff0c;用 eax 代表调用号参数&#xff0c;ebx,ecx,edx 来代表参数(syscall.c kernel.s) 添加 write 的系统调用接口(syscall.c, syscall-init.c, print.s) 注意&#xff1a;要更改 p…

基于N32L406MB EasyFlash参数(key-value)记录库移植

EasyFlash 感谢作者的分享https://github.com/armink/EasyFlash EasyFlash是一款开源的轻量级嵌入式Flash存储器库&#xff0c;方便开发者更加轻松的实现基于Flash存储器的常见应用开发 三大实用功能 ENV快速保存产品参数(key-value)&#xff0c;支持 写平衡&#xff08;磨…

最小例程上加OLED显示

最小例程上加OLED显示 本工程代码链接: https://ww0.lanzoul.com/i8lNa265gj7g 失效联系:qq2958360390 我们其实就加上这几个文件, 然后会调用就可以了, 具体的就看江协科技的OLED, 讲的很清楚, 我们这里只说应用, 我们的重点在使用. 下面跟着我来, 复制黏贴: 更详细请看哔哩…

从零开始学习机器学习,掌握AI未来的关键!

从零开始学习机器学习 1. 介绍1.1 人工智能&#xff08;AI&#xff09;概述1.2 机器学习在人工智能中的应用1.3 机器学习基础概念 2. 监督学习2.1 什么是监督学习2.2 回归分析2.3 分类问题2.4 模型评估和选择 3. 无监督学习3.1 什么是无监督学习3.2 聚类算法3.3 降维技术 4. 深…

(39)智能电池

文章目录 前言 1 通过任务规划器进行设置 2 补充信息 3 限制条件 4 参数说明 前言 虽然还不是很普遍&#xff0c;但智能电池更容易从飞行器上安装和拆卸&#xff0c;并且能够提供更多关于电池状态的信息&#xff0c;包括容量、单个电池电压、温度等。 ArduPilot 支持几种…