10. Spring MVC 程序开发

本文源码位置: Spring-MVC

1. Spring MVC 概要

摘自Spring官方: Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes from the name of its source module (spring-webmvc), but it is more commonly known as “Spring MVC”.

上面一大段话主要讲的是:Spring Web MVC是基于Servlet API构建的原始web框架,从它一诞生就包含在Spring Framework中,现在更多地被概括为Spring MVC

【经典问题】Spring/Spring Boot/Spring MVC 有什么区别?

发布的先后顺序:Spring -> Spring MVC -> Spring Boot

  • Spring指的是Spring Framework,是一个完整的框架,核心是IoC和AOP
  • Spring Boot是Spring Framework的一个子项目,它是作为Spring Framework的脚手架而存在的,旨在简化 Spring 应用和服务的创建、开发与部署,并且简化了配置,使得 Java 开发者可以快速启动、运行和测试一个简单的 Spring 应用;
  • Spring MVC 属于 Spring 的一个模块,在 Spring MVC 诞生前,开发Java web项目主流还是使用原生的Servlet框架,而 Spring MVC 则是基于Servlet API的 web 框架,目的是简化web开发的操作。

1.1 MVC的定义

MVC是软件工程中的一种架构模式,MVC三个字母分别代表Model(模型)、View(视图)、Controller(控制器),也就是说MVC是由这三个部分构成的。

以下单的业务为例:用户在页面点击下单,下单成功后在页面上通知用户下单成功以及显示相应的订单的信息

  1. 用户通过页面下单触发点击事件,发送HTTP请求到其路由映射的Controller(控制器),也就是后端的第一层,它相当于是一个安检口,用来检查前端传来的参数是否合法等;
  2. 通过Controller的检查后,将请求信息分发给Model(业务模型)对请求进行相应业务的处理,如将新的订单入库,以及查询订单的操作;
  3. Model层处理完相应业务后,将该订单的信息数据,从数据库中取出给Model(数据模型),以Model为原型分装成响应信息返回给Controller;
  4. Controller得到对应数据后,将返回数据View(视图)
  5. View(视图)通过返回的数据,通过JSP等方式将数据可视化在页面上,作为HTTP响应展现给用户,此时用户就能在页面中看到下单的信息了。

Untitled Diagram.drawio-2.png

该架构模式出现的很早,缺点是通过JSP将数据可视化的方式将前后端的代码混在一起了,不利于前后端工程师的分工(前端工程师不怎么熟悉java语法,java工程师不熟悉前端语法),已经不适用于如今的项目,为了弥补这方面带来的不便,才出现了老生常谈的前后端分离。

1.2 MVC 和 Spring MVC的关系

MVC是一种思想,而 Spring MVC 是对其的具体实现。

但是由于前后端的分离,把View(视图)的部分给淡化了,现在更多将Spring MVC 叫做 Spring Web。

从讲Spring Boot的第一篇文章开始,其实就在使用Spring Web,当时是在starter中引入的依赖:

image.png

项目启动后,就能在pom.xml中找到Spring Boot项目中对Spring Web的依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Spring MVC 主要功能

无论学习 Spring MVC 还是 Servlet 无非就是主要围绕下面三个功能学习:

  1. 连接的功能: 将用户(浏览器)和 Spring 程序通过路由关系连接起来,也就是访问一个地址能够调用 Spring 程序中的路由方法
  2. 获取参数: 用户访问的时候会携带一些参数,在程序中要想办法获取参数
  3. 返回数据: 执行业务逻辑之后,程序要将用户需要的数据返回给浏览器

2.1 Spring MVC 创建和连接

2.1.1 项目创建

Spring MVC 的项目创建这里就不赘述了,在starter中选择Spring Web 就相当于创建了Spring MVC的项目。

image.png

2.1.2 建立连接

接下来,创建一个UserController类,通过@RequestMapping注解配置路由,实现用户到Spring程序的连接:

@Controller// 让 Spring 框架启动时,加载
@ResponseBody//返回非页面数据
@RequestMapping("user")//路由注册
public class UserController {@RequestMapping("/hi")//路由注册public String doController() {return "<h1> Hello Spring MVC !<h1>";}
}

注意事项:

  1. 只能在@Controller的类中配置路由,否则路由不生效;
  2. @ResponseBody可以修饰类也可以修饰方法,作用是通过适当的转换器转换为指定的格式之后,写入到response对象的body区,使用此注解之后不会再走视图处理器,如果没有这个注解只能返回一个页面;
  3. 前面的篇章使用的@RestController是组合注解,注解中包含@Controller@ResponseBody
  4. 与Servlet的路由配置不同,@RequestMapping注解是可以精确到方法上的。

访问配置文件中配置的默认端口号8080,并通过相应路由访问到程序中的路由方法:
image.png

2.1.3 指定请求类型

可以通过Postman测试一下,当前的Spring版本下,@RequestMapping是否支持接收所有类型的请求,这里测试下POST和PATCH:
image.png

image.png

我当前的Spring版本为2.7.3,通过测试得知@RequestMapping是可以接收所有请求的。


但是如果有一个需求,要求是该路由只能接收Post请求。

1) 使用@RequestMapping

如果还是使用@RequestMapping注解就需要设置method参数了,参数的值需要结合枚举类RequestMethod进行设置:

@RestController
@RequestMapping("user")//路由注册
public class UserController {@RequestMapping(value = "/hi", method = RequestMethod.POST)//路由注册public String doController() {return "<h1> Hello Spring MVC !<h1>";}
}

观察@RequestMapping(value = "/hi", method = RequestMethod.POST):当添加了method参数后,我们发现"/hi"也需要添加value参数,当只有一个参数的时候,可以只设置"/hi",此时"/hi"为value的值。

这时再使用其他类型的请求,就会发现报了 “405” 的错误,表示请求方法不被允许:

image.png

2) 使用@PostMapping

除了设置method参数的方式,还可以使用请求类型相应的注解来制定请求类型(@PostMapping只支持post请求、@GetMapping只支持get请求):

image.png

@RestController
@RequestMapping("user")//路由注册
public class UserController {@PostMapping("/hi")public String doController() {return "<h1> Hello Spring MVC !<h1>";}
}

2.1.4 设置多个请求类型

此时@PostMapping等注解就不管用了,只能通过@RequestMappingmethod属性设置多个值:

@RestController
@RequestMapping("user")//路由注册
public class UserController {@RequestMapping(value = "/hi", method = {RequestMethod.POST, RequestMethod.GET})//路由注册public String doController() {return "<h1> Hello Spring MVC !<h1>";}
}

2.2 获取参数

Spring MVC是基于Servlet的框架,内置了两个隐藏的参数,HttpServletRequest和HttpServletResponse,如果想要使用这两个对象,只要在方法的参数中加入这两个类型,因此围绕HttpServletRequest对象获取参数的写法在这里也是适用的。

2.2.1 获取单个参数

方式一:使用request对象接收
@RequestMapping("/getOneParam1")
public String getOneParam1(HttpServletRequest request) {return "Hi," + request.getParameter("name");
}

image.png

这种方式既麻烦又不安全:通过这种方式获取的参数只能是String类型的,如果此时程序中需要的是一个Interger类型的年龄,那么只能通过Integer.valueOf()实现

@RequestMapping("/getOneParam1")
public String getOneParam1(HttpServletRequest request) {//return "Hi," + request.getParameter("name");Integer age = Integer.valueOf(request.getParameter("age"));return "value: " + age;
}

但如果前端没有传这个参数,在不额外做判断空指针的处理的话,就会抛java.lang.NumberFormatException的异常:

image.png


方式二:使用单个参数接收

注意:参数名必须和前端匹配

@RequestMapping("/getOneParam2")
public String getOneParam2(String name) {return "Hi," + name;
}

image.png
通过方式二,获取Integer类型的年龄

@RequestMapping("/getOneParam2")
public String getOneParam2(Integer age) {//return "Hi," + name;return "value: " + age;
}

即使前端不传参数,也不会出现异常:

image.png

2.2.2 获取多个参数

方式一:使用多个参数接收

Spring MVC 传递多个参数的时候,只要在方法中添加多个参数即可,获取参数时只需要保证参数名对应,获取参数的结果只和参数的名称有关,和顺序无关

@RequestMapping("/getMoreParam")
public String getMoreParam(String name, Integer age) {return "name: " + name + " | " + "age: " + age;
}

前端传参数的时候顺序与程序中获取参数的顺序不同,但还是顺利拿到结果:
image.png

如果参数少的时候还可以这样做,但如果有极端情况需要传成百上千个参数的话,用这种做法就显得太抽象了。


方式二:使用对象接收

编写一个实体类:

@Data
public class User {private Integer id;private String name;private Integer age;private String gender;
}

使用对象接收:

@RequestMapping("/getMoreParam2")
public String getMoreParam(User user) {return user.toString();
}

前端传参数给后端后,Spring MVC 检测到你是用一个对象来接收的,就会通过setter方法来将对应的参数注入到对象中,如果前端传的参数实体类中没定义该属性就不处理,如果对象中某些属性前端没有传参数,属性就为默认值null
image.png

2.2.3 获取JSON对象 —— @RequestBody

大部分情况下前面提到的获取参数的方式都能解决,但如果参数是一个JSON对象就得用特殊的方式获取了。

编写一个login的路由方法用于测试:

@RequestMapping("/login")
public String login(String name, String password) {return "name: " + name + " | " + "password: " + password;
}

前端传参方式介绍(简单了解)

前端将数据传递给后端大概有三种方式:

  • Url中携带QueryString直接访问路由
  • Form表单提交
  • Ajax提交

URL传参:前面所使用的都是通过URL直接携带QueryString访问的,这里就不过多赘述了。

From表单传参(下面的method参数可以填get/post):

<body><form method="xxx" action="/user/login"><h1>登录</h1><div>用户:<input id="name" name="name"/></div><div>密码:<input id="password" name="password"/></div><input type="submit" value="提交"></form>
</body>

页面的显示如下:

image.png

1. method=“get”

点击提交后抓包我们可以观察到From表单的get方法穿参其实就跟URL传参是一样的,因此我们的后端可以顺利的获取到数据

image.png


2. method=“post”

点击提交后抓包我们发现这次的QueryString不在url中了,而是在body(请求体)中,并且body中的参数的content-typeapplication/x-www-form-urlencoded,抓包数据如下:

image.png

image.png
此时虽然QueryString到了body中,但是格式还是和URL中的一样,因此我们的后端还是能顺利的拿到数据:
image.png


Ajax传参

1. 通过Ajax传一个js对象

<body><h1>登录</h1><div>用户:<input id="name" name="name"/></div><div>密码:<input id="password" name="password"/></div><input type="button" onclick="submit()" value="提交">
</body>
<script>function submit() {jQuery.ajax({url:"/user/login",type:"POST",data:{"name":jQuery("#name").val(),"password":jQuery("#password").val(),},success:function(body) {alert(body);console.dir(body);}})}
</script>

点击提交后抓包我们发现虽然此时是通过Ajax传参,但本质还是和Form表单的Post方法传参是一样的,body中的参数的content-typeapplication/x-www-form-urlencoded,抓包数据如下:

image.png

image.png

因此后端还是可以获取到参数并返回给前端:

image.png


2. 通过Ajax传一个JSON对象

当我尝试用Postman传一个JSON对象给前端时,奇怪的事发生了,这时候我们的后端无法再顺利拿到数据了

image.png

使用@RequestBody+对象接收

@RequestBody主要用来接收前端传递给后端的JSON对象的数据的,需要搭配实体类来使用,由于我们需要传password的参数,因此我们在实体类中加上password字段:

@Data
public class User {private Integer id;private String name;private Integer age;private String gender;private String password;
}

接下来我们就可以使用@RequestBody来获取JSON对象了,具体代码如下:

@RequestMapping("/login2")
public String loginAjax(@RequestBody User user) {return "name: " + user.getName() + " | " + "password" + user.getPassword();
}

通过Postman重新发送请求,这次我们终于成功获取到了JSON对象。
image.png

2.2.4 获取文件 —— @RequestPart

引入需求:如用户修改头像的业务,用户想要通过前端页面的上传头像功能将桌面上的一个可爱小猫图片上传给后端。

image.png

使用@RequestPart+MultipartFile对象接收

跟JSON一样,文件也是一个比较特殊的对象,Spring MVC 提供了一个简化上传操作的工具类 —— MultipartFile,当前端上传一个文件给后端时,后端需要使用@RequestPart注解来修饰MultipartFile对象来接收前端发来的文件。

注意事项:

  1. @RequestPart注解需要设置一个参数,与前端的参数的key值相对应;

  2. 服务器在用MultipartFile对象接收之后,应该保存到服务器本地上,不然程序执行完该对象就会被GC回收掉。MultipartFile对象有一个transferTo()方法,可以将该文件复制到本地的路径中

具体代码如下:

@RequestMapping("/upload")
public String upload(@RequestPart("myfile")MultipartFile file, ServletRequest request) throws IOException {String path = "/Users/chenshu/Code/classcode_java/blog-demo/Spring-MVC/src/main/resources/static/img";file.transferTo(new File(path+"/cat.jpg"));return "success";
}

使用Postman来模拟用户上传头像的HTTP请求:

image.png

成功保存到相应路径下:

image.png

2.2.5 获取Cookie/Session/Header

获取Header —— @RequestHeader

传统方法:

@RequestMapping("/header1")
public String getHeader1(HttpServletRequest request) {String header = request.getHeader("User-Agent");return "User-Agent: " + header;
}

image.png

通过@RequestHeader获取:

@RequestMapping("/header2")
public String getHeader2(@RequestHeader("User-Agent") String header) {return "User-Agent: " + header;
}

image.png


获取Cookie —— @CookieValue

通过该路由方法给浏览器设置一个Cookie值用于测试:

@RequestMapping("/setCookie")
public void setCookie(HttpServletResponse response) {Cookie cookie = new Cookie("status", "OK");response.addCookie(cookie);
}

传统方法:

@RequestMapping("/cookie1")
public String getCookie1(HttpServletRequest request) {String ret = "status: ";Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {if (cookie.getName().equals("status")) {ret += cookie.getValue();}}return ret;
}

image.png

通过@CookieValue获取:

@CookieValue中的参数设置的是Cookie的键,该注解的作用是在所有Cookie中找对应键的Cookie,并将该Cookie的值并赋给一个String

@RequestMapping("/cookie2")
public String cookie(@CookieValue("status") String status) {return "status: " + status;
}

image.png


获取Session —— @SessionAttribute

通过该路由方法给浏览器设置一个Session用于测试:

@RequestMapping("/setSession")
public String setSession(HttpServletRequest request) {HttpSession session = request.getSession(true);if (session!=null) {session.setAttribute("username", "zhangsan");}return "session 存储成功.";
}

传统方法:

@RequestMapping("/session1")
public String getSession1(HttpServletRequest request) {HttpSession session = request.getSession(false);String username = null;if (session != null && session.getAttribute("username") != null) {username = (String) session.getAttribute("username");}return  "username: " + username;
}

image.png

通过@SessionAttribute获取:

  • value参数代表的是Session里的键,作用是在Session的所有键值对中找到对应的键,并将该键所对应的值赋给一个String;
  • required参数默认为true,表示没有找到value参数指定的键就直接报错,设置为false的话则不报错。
@RequestMapping("/session2")
public String getSession2(@SessionAttribute(value = "username", required = false) String username) {return "username: " + username;
}

image.png

2.2.6 后端参数重命名 —— @RequestParam

某些特殊的情况下,前端传递的参数的key不满足后端的参数命名规范,比如前端传递了一个money表示用户的金额,你认为这个参数的命名模棱两可,想使用balance来接收,出现这种情况,我们就可以使用@RequestParam来重命名前端的参数。

@RequestMapping("/showBalance")
public String renameParam(@RequestParam("money") String balance){return "账户余额为: " + balance;
}

image.png

注意事项:当使用了这个注解后,前端一定得传键为"money"的参数,否则就会报400错误

image.png

2.2.7 设置参数必传 —— required参数

在Session中就经常使用这个参数,前面也提到过,这里还是单独拿出来一谈,required参数默认是true的,如果不想报错的话,需要设置required参数为false

@RequestMapping("/showBalance")
public String renameParam(@RequestParam(value = "money", required = false) String balance){return "账户余额为: " + balance;
}

这样就不会报错了:

image.png

2.2.8 获取URL中参数 —— @PathVariable

有些特殊的场景,需要将参数直接放在URL里,与放在"?"后面的QueryString中不同,它是直接将参数放在路径上的:

image.png

对于上面那种情况,我们需要在@RequestMapping中告知程序路由上的哪些玩意是参数,如"/login2/{username}/{password}",表示login2后面紧跟的两个子路径是作为参数传递的

然后使用@PathVariable注解修饰变量来接收参数

@RequestMapping("/login2/{username}/{password}")
public String login2(@PathVariable String username, @PathVariable String password) {return "username: " + username + " | " + "password: " + password;
}

成功取到URL中的参数:

image.png

2.3 返回数据

Spring MVC 中可以通过 Controller 返回数据给前端

如果没加@RequestBody注解的话,Spring MVC就会根据return的值去找view(视图)的路径,在HTTP响应报文中返回text/html类型的HTML源码从而展示在页面上。

如果加了@RequestBody注解,SpringSpring MVC会根据你在Java中返回的类型来自动设置HTTP响应包中的的Content-Type(包含数据类型和编码方式),并且根据Content-Type中的数据类型和编码方案,自动转化为相应的数据并返回。

2.3.1 添加@RequestBody返回String

前面我们所用的方式都是返回一个String给前端,通过抓包我们可以看到,响应的Content-Typetext/html类型,浏览器会将返回的数据当作HTML页面解析,本质上就跟没有添加@RequestBody返回视图是一样的。

但是有一点不一样,并且由于Idea中的默认编码方式是UTF-8,因此 Spring MVC 设置HTTP响应报文中的Content-Type会携带charset=UTF-8,浏览器也会以UTF-8的格式来解码,看2.3.2 到返回静态页面的时候会更直观地看出差别。
image.png

2.3.2 返回JSON对象

一个json对象其实就是大括号中包含一个个键值对,原生的Servlet想要返回JSON对象,通常是使用一个外部的JSON框架如jackson,将一个对象或者对象列表转化成Json格式的字符串,并通过设置HTTP响应报文中的Content-Type字段,从而告知浏览器要把数据以Json的格式解析。

String jsonString = objectMapper.writeValueAsString(obj);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(jsonString);

在Spring MVC中内置了jackson框架,如果你在类上或者方法上添加了@RequestBody注解,当你返回一个对象、Map、列表时,会自动将它们转化成json格式发送给前端

@RequestMapping("/userinfo1")
public User getUserInfo1() {User user = new User();user.setId(1);user.setName("zhangsan");user.setPassword("123");user.setGender("male");user.setAge(20);return user;
}

返回对象:
一个普通对象可以映射一个Json对象,对象中有哪些属性,Json对象就对应拥有哪些键。

@RequestMapping("/userinfo1")
public User getUserInfo1() {User user = new User();user.setId(1);user.setName("zhangsan");user.setPassword("123");user.setGender("male");user.setAge(20);return user;
}

image.png

返回Map: 由于Map是键值对的形式,一个Map对象也可以映射一个Json对象,Map中有哪些键,Json对象就对应拥有哪些键。

@RequestMapping("/userinfo2")
public Map<String, Object> getUserInfo2() {HashMap<String, Object> user = new HashMap<>();user.put("name", "zhangsan");user.put("password", "123");return user;
}

image.png

返回List: 一个List对应多个Json对象,多个Json对象用[ ]来包裹起来,List里面可以有普通对象,也可以有Map对象。

@RequestMapping("/userinfo3")
public List<User> getUserInfo3() {List<User> userList = new ArrayList<>();User user1 = new User();user1.setName("zhangsan");User user2 = new User();user2.setName("lisi");userList.add(user1);userList.add(user2);return userList;
}

image.png

2.3.2 返回静态页面

去掉@ResponseBody注解,Spring MVC就知道你要返回的是一个静态页面:

@Controller
@RequestMapping("/test")
public class TestController {@RequestMapping("/index")public String index() {return "/index.html";}
}

index.html如下:

<html>
<header><meta charset="UTF-8">
</header>
<body>
<h1>hello word!!!</h1>
<p>this is a html page</p>
<p>返回静态页面的测试</p>
</body>
</html>

访问对应路由后确实展示出了我们所编写的页面:

image.png

注意事项: 由于浏览器是按HTML中的<header>标签中设置的charset进行解码,因此抓包数据中的Content-Type没有设置charset类型:

image.png

我们必须在<header>设置默认的字符编码,否则浏览器会以默认的解码方案来解码,如果我把<header>中配置的UTF-8的字符编码删除,显示的页面出现的中文就是乱码:

image.png

2.3.4 请求转发和请求重定向

除了返回一个静态页面,还可以实现跳转,跳转的方式有两种

  • redirect:请求重定向
  • forward:请求转发

请求重定向: 你发送一个请求给后端,请求成功到达路由后,HTTP请求报文中的状态码为302请求重定向,后端在HTTP响应报文中添加Location字段中告诉你重定向的位置,然后浏览器会自动完成页面的跳转,也就相当于重新发起了一次HTTP请求

@RequestMapping("/redirect")
public String index2() {return "redirect:/index.html";
}

下面我通过抓包演示请求重定向

在浏览器中输入重定向的路由:

image.png

在用户的视角下:输入上面的URL后,直接跳转到下面的页面:
image.png

抓包看到HTTP请求的状态码为302 Found

image.png

HTTP响应中多了一个Location字段,浏览器就是通过该字段进行重新跳转到新页面:
image.png


请求转发: 当你发送一个请求给后端,后端会携带者你的HTTP请求,转发到新的路由,你会发现浏览器上的地址不会变,然后将新的路由返回的信息展现在你的页面上,HTTP请求报文的状态码为200,对用户来说是透明的。

@RequestMapping("/forward")
public String index3() {return "forward:/index.html";
}

下面我通过抓包演示请求转发

用户视角:输入URL按下回车键后即使路由没发生变化,还是将index.html页面展现给你
image.png

抓包看到HTTP请求的状态码为200 OK:

image.png

通过在HTTP响应报文中返回页面的text/html,将页面显示在用户视角中:

image.png

在index.html中引入了外部css样式如下:

image.png

再次访问test/forward路由,发现由于请求转发给后端是将页面通过HTTP响应报文以test/html的形式返回给前端从而显示到页面上,因此访问不到外部的css样式:

image.png

forward和redirect具体区别总结:

  1. 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发
  2. 请求重定向地址发生变化,请求转发地址不发生变化。
  3. 请求重定向相当于前端发送了两次HTTP请求,而请求重定向只发送一次HTTP请求
  4. 由于请求转发给后端是将页面通过HTTP响应报文以test/html的形式返回给前端从而显示到页面上,因此如果引用了外部css/js等,可能造成外部资源访问不到

3. 总结

所谓 Spring MVC 就是基于 Servlet API 的框架,所谓 Spring MVC 程序开发讲的就是三件事情:建立连接、获取参数以及返回数据,本文对这三件事进行了详细的讲解,足以在开发中应对绝大多数需求。

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

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

相关文章

Adobe AE(After Effects)2015下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

大创项目推荐 深度学习YOLOv5车辆颜色识别检测 - python opencv

文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0…

嵌入式学习55-ARM4(ADC和I²C)

1、什么是ADC,模拟量和数字量有什么特点&#xff1f; ADC&#xff1a; …

Ubuntu Vs code配置ROS开发环境

文章目录 1.开发环境2.集成开发环境搭建2.1 安装Ros2.2 安装 Vs code2.3 安装vs code 插件 3.Vs code 配置ROS3.1 创建ROS工作空间3.2 从文件夹启动Vs code3.3 使用Vscode 编译ROS 空间3.4 使用Vs code 创建功能包 4.编写简单Demo实例4.1编写代码4.2编译与执行 1.开发环境 系统…

【行为型模式】观察者模式

一、观察者模式概述​ 软件系统其实有点类似观察者模式&#xff0c;目的&#xff1a;一个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变&#xff0c;他们之间将产生联动。 观察者模式属于对象行为型&#xff1a; 1.定义了对象之间一种一对多的依赖关系&#xff…

MyBatisPlus自定义SQL

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:MyBatisPlus自定义SQL 📚个人知识库: Leo知识库,欢迎大家访问 目录 1.前言☕…

Kafka、RabbitMQ、Pulsar、RocketMQ基本原理和选型

Kafka、RabbitMQ、Pulsar、RocketMQ基本原理和选型 1. 消息队列1.1 消息队列使用场景1.2. 消息队列模式1.2.1 点对点模式&#xff0c;不可重复消费1.2.2 发布/订阅模式 2. 选型参考2.1. Kafka2.1.1 基本术语2.1.2. 系统框架2.1.3. Consumer Group2.1.4. 存储结构2.1.5. Rebalan…

Langchain入门到实战-第三弹

Langchain入门到实战 Langchain中RAG入门官网地址Langchain概述代码演示调用RAG功能更新计划 Langchain中RAG入门 Retrieval Augmented Generation 翻译成中文是“检索增强生成” 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息…

AB5 点击消除

原题链接&#xff1a;点击消除_牛客题霸_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 栈。 遍历字符串。如果栈为空或者当前字符与栈顶元素不等&#xff0c;就压栈。否则如果当前字符与堆顶元素相同&#xff0c;就出栈。 遍历完字符串…

SiLM5350系列带米勒钳位的单通道隔离驱动器 助力汽车与工业应用实现稳定与高效的解决方案

带米勒钳位的隔离驱动SiLM5350系列 单通道 30V&#xff0c;10A 带米勒钳位的隔离驱动 具有驱动电流更大、传输延时更低、抗干扰能力更强、封装体积更小等优势, 为提高电源转换效率、安全性和可靠性提供理想之选。 SiLM5350系列产品描述&#xff1a; SiLM5350系列是单通道隔离驱…

大数据平台搭建2024(三)

三&#xff1a;HBase安装 提前上传hbase安装包至虚拟机 1 上传、解压 tar -zxvf hbase-2.0.0-alpha2-bin.tar.gz -C /hadoop2 修改配置文件 在/hadoop/hbase-2.0.0-alpha2-bin/conf文件夹里 vi /hadoop/hbase-2.0.0-alpha2/conf/hbase-env.sh修改hbase-env.sh文件 export…

如何用JAVA如何实现Word、Excel、PPT在线前端预览编辑的功能?

背景 随着信息化的发展&#xff0c;在线办公也日益成为了企业办公和个人学习不可或缺的一部分&#xff0c;作为微软Office的三大组成部分&#xff1a;Word、Excel和PPT也广泛应用于各种在线办公场景&#xff0c;但是由于浏览器限制及微软Office的不开源等特性&#xff0c;导致…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别 一、简单介绍 二、简单人脸识别实现原理 三、简单人脸识别案例实现简…

数据密集型应用系统设计 PDF 电子书(Martin Kleppmann 著)

简介 《数据密集型应用系统设计》全书分为三大部分&#xff1a; 第一部分&#xff0c;主要讨论有关增强数据密集型应用系统所需的若干基本原则。首先开篇第 1 章即瞄准目标&#xff1a;可靠性、可扩展性与可维护性&#xff0c;如何认识这些问题以及如何达成目标。第 2 章我们比…

MongoDB的安装配置及使用

文章目录 前言一、MongoDB的下载、安装、配置二、检验MongoDB是否安装成功三、Navicat 操作MongoDB四、创建一个集合&#xff0c;存放三个文档总结 前言 本文内容&#xff1a; &#x1f4ab; MongoDB的下载、安装、配置 &#x1f4ab; 检验MongoDB是否安装成功 ❤️ Navicat 操…

【单例模式】饿汉式、懒汉式、静态内部类--简单例子

单例模式是⼀个单例类在任何情况下都只存在⼀个实例&#xff0c;构造⽅法必须是私有的、由⾃⼰创建⼀个静态变量存储实例&#xff0c;对外提供⼀个静态公有⽅法获取实例。 目录 一、单例模式 饿汉式 静态内部类 懒汉式 反射可以破坏单例 道高一尺魔高一丈 枚举 一、单例…

[html]一个动态js倒计时小组件

先看效果 代码 <style>.alert-sec-circle {stroke-dasharray: 735;transition: stroke-dashoffset 1s linear;} </style><div style"width: 110px; height: 110px; float: left;"><svg style"width:110px;height:110px;"><cir…

【GD32】_时钟架构及系统时钟频率配置

文章目录 一、有关时钟源二、系统时钟架构三、时钟树分析四、修改参数步骤1、设置外部晶振2、选择外部时钟源。3、 设置系统主频率大小4、修改PLL分频倍频系数 学习系统时钟架构和时钟树&#xff0c;验证及学习笔记如下&#xff0c;如有错误&#xff0c;欢迎指正。主要记录了总…

力扣152. 乘积最大子数组

Problem: 152. 乘积最大子数组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化&#xff1a;首先&#xff0c;我们创建两个数组maxNum和minNum&#xff0c;并将它们初始化为输入数组nums。这两个数组用于存储到当前位置的最大和最小乘积。我们还需要一个变量maxProduc…

python 一个点运算符操作的字典库:DottedDict

DottedDict 是一种特殊的数据结构&#xff0c;它结合了字典&#xff08;Dictionary&#xff09;和点符号&#xff08;Dot Notation&#xff09;访问的优点&#xff0c;为用户提供了一种更加直观和方便的方式来处理和访问嵌套的数据。在这篇文章中&#xff0c;我们将深入探讨 Do…