Spring实战(开发Web应用)

news/2024/5/6 3:52:12/文章来源:https://blog.csdn.net/weixin_40540957/article/details/125095579

开发Web应用

  • 展现信息
    • 构建领域类
    • 创建控制器类
    • 设计视图
  • 处理表单提交
  • 校验表单输入
    • 声明校验规则
    • 在表单绑定的时候执行校验
    • 展现校验错误
  • 视图控制器
  • 选择视图模板库
  • 小结

展现信息

Taco Cloud是一个可以在线订购taco的地方。 Taco Cloud允许客户展现其创意, 能够让他们通过丰富
的配料(ingredient) 设计自己的taco。Taco Cloud需要有一个页面为taco艺术家展现都可以选择哪
些配料。

在Spring Web应用中, 获取和处理数据是控制器的任务, 而将数据渲染到HTML中并在浏览器中展现则是视图的任务。
为了支撑taco的创建页面, 我们需要构建如下组件。

  • 用来定义taco配料属性的领域类。
  • 用来获取配料信息并将其传递至视图的Spring MVC控制器类。
  • 用来在用户的浏览器中渲染配料列表的视图模板。
    在这里插入图片描述
    本章主要关注Spring的Web框架,会将数据库相关的内容放到第3章中进行讲解。现在的控制器只负责向视图提供配料。

构建领域类

taco配料是非常简单的对象。 每种配料都有一个名称和类型, 以便于对其进行可视化的分类(蛋白质、 奶酪、 酱汁等) 。 每种配料还有一个ID, 这样的话对它的引用就能非常容易和明确。

定义Ingredient类,Ingredient类为配料类。
@Data注解就是由Lombok提供的, 它会告诉Lombok生成所有缺失的方法, 同时还会生成所有以
final属性作为参数的构造器。 通过使用Lombok, 我们能够让Ingredient的代码简洁明了。

在pom文件中添加对Lombox的依赖。

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
import lombok.Data;
import lombok.RequiredArgsConstructor;@Data
@RequiredArgsConstructor
public class Ingredient {private final String id;private final String name;private final Type type;public static enum Type {WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE}
}

创建控制器类

在Spring MVC框架中, 控制器是重要的参与者。 它们的主要职责是处理HTTP请求, 要么将请求传递给视图以便于渲染HTML(浏览器展现) , 要么直接将数据写入响应体(RESTful)。

对于Taco Cloud应用来说, 我们需要一个简单的控制器, 它要完成如下功能:

  • 处理路径为“/design”的HTTP GET请求。
  • 构建配料的列表。
  • 处理请求, 并将配料数据传递给要渲染为HTML的视图模板, 发送给发起请求的Web浏览器

在程序中创建 DesignTacoController控制器,处理 “/design” 请求。

@Slf4j
@Controller
@RequestMapping("/design")
public class DesignTacoController {@GetMappingpublic String showDesignForm(Model model) {List<Ingredient> ingredients = Arrays.asList(new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),new Ingredient("COTO", "Corn Tortilla", Type.WRAP),new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),new Ingredient("CARN", "Carnitas", Type.PROTEIN),new Ingredient("TMTO", "Diced Tomatoes", Type.VEGGIES),new Ingredient("LETC", "Lettuce", Type.VEGGIES),new Ingredient("CHED", "Cheddar", Type.CHEESE),new Ingredient("JACK", "Monterrey Jack", Type.CHEESE),new Ingredient("SLSA", "Salsa", Type.SAUCE),new Ingredient("SRCR", "Sour Cream", Type.SAUCE));Type[] types = Ingredient.Type.values();for (Type type : types) {model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type));}model.addAttribute("design", new Taco());return "design";}private List<Ingredient> filterByType(List<Ingredient> ingredients, Type type) {return ingredients.stream().filter(x -> x.getType().equals(type)).collect(Collectors.toList());}
}

@Slf4j,Lombok所提供的注解, 在运行时,它会在这个类中自动生成一个SLF4J(Simple Logging Facade for Java) Logger。

@Controller,这个注解会将这个类识别为控制器,并且将其作为组件扫描的候选者,Spring会发现它并自动创建一个DesignTacoController实例, 并将该实例作为Spring应用上下文中的bean。

@RequestMapping注解用到类级别的时候, 它能够指定该控制器所处理的请求类型。

@GetMapping对类级别的@RequestMapping进行了细化。@GetMapping结合类级别的@RequestMapping,指明当接收到对“/design”的HTTP GET请求时, 将会调用showDesignForm()来处理请求

Spring MVC的请求映射注解表

注解描述
@RequestMapping通用的请求处理
@GetMapping处理HTTP GET请求
@PostMapping处理HTTP POST请求
@DeleteMapping处理HTTP DELETE请求
@PatchMapping处理HTTP PATCH请求

推荐在类级别上使用@RequestMapping, 以便于指定基本路径。 在每个处理器方法上,使用更具体的注解。

showDesignForm()方法处理请求,构建了一个Ingredient对象的列表。showDesignForm()方法接下来的几行代码会根据配料类型过滤列表。 配料类型的列表会作为属性添加到Model对象上。Model对象负责在控制器和展现数据的视图之间传递数据。 showDesignForm()方法最后返回“design”, 这是视图的逻辑名称, 会用来将模型渲染到视图上。

设计视图

在视图中将Model中的数据取出,展现在页面中。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org">
<head><title>Taco Cloud</title><link rel="stylesheet" th:href="@{/styles.css}" />
</head>
<body>
<h1>Design your taco!</h1>
<img th:src="@{/images/TacoCloud.png}"/>
<form method="POST" th:object="${design}"><div class="grid"><div class="ingredient-group" id="wraps"><h3>Designate your wrap:</h3><div th:each="ingredient : ${wrap}"><input name="ingredients" type="checkbox" th:value="${ingredient.id}"/><span th:text="${ingredient.name}">INGREDIENT</span><br/></div></div><div class="ingredient-group" id="proteins"><h3>Pick your protein:</h3><div th:each="ingredient : ${protein}"><input name="ingredients" type="checkbox" th:value="${ingredient.id}"/><span th:text="${ingredient.name}">INGREDIENT</span><br/></div></div><div class="ingredient-group" id="cheeses"><h3>Choose your cheese:</h3><div th:each="ingredient : ${cheese}"><input name="ingredients" type="checkbox" th:value="${ingredient.id}"/><span th:text="${ingredient.name}">INGREDIENT</span><br/></div></div><div class="ingredient-group" id="veggies"><h3>Determine your veggies:</h3><div th:each="ingredient : ${veggies}"><input name="ingredients" type="checkbox" th:value="${ingredient.id}"/><span th:text="${ingredient.name}">INGREDIENT</span><br/></div></div><div class="ingredient-group" id="sauces"><h3>Select your sauce:</h3><div th:each="ingredient : ${sauce}"><input name="ingredients" type="checkbox" th:value="${ingredient.id}"/><span th:text="${ingredient.name}">INGREDIENT</span><br/></div></div></div><div><h3>Name your taco creation:</h3><input type="text" th:field="*{name}"/><br/><button>Submit your taco</button></div>
</form>
</body>
</html>

运行程序,访问http://localhost:8080/design,就可以查看到页面。

处理表单提交

在视图中的标签,它的method属性被设置成了POST,并没有声明action属性。当表单提交的时候, 浏览器会收集表单中的所有数据,以HTTP POST请求的形式将其发送至服务器端, 发送路径与渲染表单的GET请求路径相同, 也就是“/design”。
需要在DesignTacoController控制器中,编写对 “/design” 的POST请求。

@PostMapping
public String processDesign(Taco design) {// Save the taco design...// We'll do this in chapter 3log.info("Processing design: " + design);return "redirect:/orders/current";
}

在提交表单的时候,数据会和Taco类中的属性对应的绑定起来,需要先定义Taco类。

import java.util.List;
import lombok.Data;
@Data
public class Taco {private String name;private List<String> ingredients;
}

processDesign()的方法最后也返回了一个String类型的值,同样与showDesignForm()相似, 返回的这个值代表了一个要展现给用户的视图。 区别在于processDesign()返回的值带有“redirect:”前缀, 表明这是一个重定向视图。 表明在processDesign()完成之后, 用户的浏览器将会重定向到相对路径“/order/current”

下面编写处理“/orders/current”请求的控制器。
orderForm这个方法,只是返回了一个名为orderForm的逻辑视图名。

@Slf4j
@Controller
@RequestMapping("/orders")
public class OrderController {@GetMapping("/current")public String orderForm(Model model) {model.addAttribute("order", new Order());return "orderForm";}
}

下面将编写orderForm.html这个文件。
在页面中将订单的信息展示出来。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org">
<head><title>Taco Cloud</title><link rel="stylesheet" th:href="@{/styles.css}" />
</head>
<body>
<form method="POST" th:action="@{/orders}" th:object="${order}"><h1>Order your taco creations!</h1><img th:src="@{/images/TacoCloud.png}"/><a th:href="@{/design}" id="another">Design another taco</a><br/><div th:if="${#fields.hasErrors()}">
<span class="validationError">
Please correct the problems below and resubmit.
</span></div><h3>Deliver my taco masterpieces to...</h3><label for="name">Name: </label><input type="text" th:field="*{name}"/><br/><label for="street">Street address: </label><input type="text" th:field="*{street}"/><br/><label for="city">City: </label><input type="text" th:field="*{city}"/><br/><label for="state">State: </label><input type="text" th:field="*{state}"/><br/><label for="zip">Zip code: </label><input type="text" th:field="*{zip}"/><br/><h3>Here's how I'll pay...</h3><label for="ccNumber">Credit Card #: </label><input type="text" th:field="*{ccNumber}"/><br/><label for="ccExpiration">Expiration: </label><input type="text" th:field="*{ccExpiration}"/><br/><label for="ccCVV">CVV: </label><input type="text" th:field="*{ccCVV}"/><br/><input type="submit" value="Submit order"/>
</form>
</body>
</html>

页面中form标签指定了一个表单的action,指定了method。明确指明表单要POST提交到“/orders”上。需要在OrderController中添加另外一个方法, 以便于处理针对“/orders”的POST请求。

@PostMapping
public String processOrder(Order order) {log.info("Order submitted: " + order);return "redirect:/";
}

当调用processOrder()方法处理所提交的订单时, 我们会得到一个Order对象, 它的属性绑定了所提交的表单域。
下面创建Order类。

@Data
public class Order {private String name;	private String street;private String city;private String state;private String zip;private String ccNumber;private String ccExpiration;private String ccCVV;
}

现在可以运行一下程序,访问http://localhost:8080/design,选择配料,点击提交,将会来到订单页面,填写订单信息,点击提交,会在控制台中输出填写完成的订单信息。表单中的大多数输入域包含的可能都是不正确的信息。 应该添加一些校验, 确保所提交的数据至少与所需的信息比较接近。

校验表单输入

Spring支持Java的Bean校验API(Bean ValidationAPI, 也被称为JSR-303)。
要在Spring MVC中应用校验, 我们需要。

  • 在要被校验的类上声明校验规则: 具体到我们的场景中, 也就是Taco类。
  • 在控制器方法中声明要进行校验: 就是DesignTacoController的processDesign()方法和OrderController的processOrder()方法。
  • 修改表单视图以展现校验错误。

声明校验规则

对于Taco类来说, 我们想要确保name属性不能为空或null, 同时希望选中的配料至少要包含一项。
可以声明以下的校验规则。
name属性不为null之外,还声明了它的值在长度上至少要有5个字符。

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
public class Taco {@NotNull@Size(min=5, message="Name must be at least 5 characters long")private String name;@Size(min=1, message="You must choose at least 1 ingredient")private List<String> ingredients;
}

对提交的订单进行校验时,我们必须要给Order类添加注解。
对于地址相关的属性,保证没有提交空白字段。可以使用Hibernate Validator的@NotBlank注解。
确保ccNumber属性不为空,还要保证它所包含的值是一个合法的信用卡号码。@CreditCardNumber注解。 这个注解声明该属性的值必须是合法的信用卡号。
ccExpiration属性必须符合MM/YY格式(两位的月份和年份),@Pattern注解并为其提供了一个正则
表达式,确保属性值符合预期的格式。
ccCVV属性需要是一个3位的数字,@Digits注解, 能够确保它的值包含3位数字。
所有的校验注解都包含了一个message属性,该属性定义了当输入的信息不满足声明的校验规则时要给用户展现的消息。

import javax.validation.constraints.Digits;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import javax.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class Order {@NotBlank(message="Name is required")private String name;@NotBlank(message="Street is required")private String street;@NotBlank(message="City is required")private String city;@NotBlank(message="State is required")private String state;@NotBlank(message="Zip code is required")private String zip;@CreditCardNumber(message="Not a valid credit card number")private String ccNumber;@Pattern(regexp="^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",message="Must be formatted MM/YY")private String ccExpiration;@Digits(integer=3, fraction=0, message="Invalid CVV")private String ccCVV;
}

在表单绑定的时候执行校验

修改每个控制器, 让表单在POST提交至对应的控制器方法时执行对应的校验。
要校验提交的Taco,需要为DesignTacoController中processDesign()方法的Taco参数添加一个Java Bean Validation API的@Valid注解。

@Valid注解会告诉Spring MVC要对提交的Taco对象进行校验, 而校验时机是在它绑定完表单数据之后、 调用processDesign()之前。 如果存在校验错误, 那么这些错误的细节将会捕获到一个Errors对象中并传递给processDesign()。 processDesign()方法的前几行会查阅Errors对象,调用其hasErrors()方法判断是否有校验错误。

@PostMapping
public String processDesign(@Valid Taco design, Errors errors) {if (errors.hasErrors()) {return "design";} // Save the taco design...// We'll do this in chapter 3log.info("Processing design: " + design);return "redirect:/orders/current";
}

对提交的Order对象进行校验, OrderController的processOrder()方法做类似变更。

@PostMapping
public String processOrder(@Valid Order order, Errors errors) {if (errors.hasErrors()) {return "orderForm";} log.info("Order submitted: " + order);return "redirect:/";
}   

展现校验错误

为了在页面显示校验错误,需要对页面进行改造,如下所示:

orderForm.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org">
<head><title>Taco Cloud</title><link rel="stylesheet" th:href="@{/styles.css}" />
</head>
<body><form method="POST" th:action="@{/orders}" th:object="${order}"><h1>Order your taco creations!</h1><img th:src="@{/images/TacoCloud.png}"/><a th:href="@{/design}" id="another">Design another taco</a><br/><div th:if="${#fields.hasErrors()}"><span class="validationError">Please correct the problems below and resubmit.</span></div><h3>Deliver my taco masterpieces to...</h3><label for="name">Name: </label><input type="text" th:field="*{name}"/><span class="validationError"th:if="${#fields.hasErrors('name')}"th:errors="*{name}">Name Error</span><br/><label for="street">Street address: </label><input type="text" th:field="*{street}"/><span class="validationError"th:if="${#fields.hasErrors('street')}"th:errors="*{street}">Street Error</span><br/><label for="city">City: </label><input type="text" th:field="*{city}"/><span class="validationError"th:if="${#fields.hasErrors('city')}"th:errors="*{city}">City Error</span><br/><label for="state">State: </label><input type="text" th:field="*{state}"/><span class="validationError"th:if="${#fields.hasErrors('state')}"th:errors="*{state}">State Error</span><br/><label for="zip">Zip code: </label><input type="text" th:field="*{zip}"/><span class="validationError"th:if="${#fields.hasErrors('zip')}"th:errors="*{zip}">Zip Error</span><br/><h3>Here's how I'll pay...</h3><label for="ccNumber">Credit Card #: </label><input type="text" th:field="*{ccNumber}"/><span class="validationError"th:if="${#fields.hasErrors('ccNumber')}"th:errors="*{ccNumber}">CC Num Error</span><br/><label for="ccExpiration">Expiration: </label><input type="text" th:field="*{ccExpiration}"/><span class="validationError"th:if="${#fields.hasErrors('ccExpiration')}"th:errors="*{ccExpiration}">CC Num Error</span><br/><label for="ccCVV">CVV: </label><input type="text" th:field="*{ccCVV}"/><span class="validationError"th:if="${#fields.hasErrors('ccCVV')}"th:errors="*{ccCVV}">CC Num Error</span><br/><input type="submit" value="Submit order"/>
</form>
</body>
</html>

design.html

 <div><h3>Name your taco creation:</h3><input type="text" th:field="*{name}"/><br/><span th:text="${#fields.hasErrors('name')}">XXX</span><span class="validationError"th:if="${#fields.hasErrors('name')}"th:errors="*{name}">Name Error</span><br/><button>Submit your taco</button>
</div>

视图控制器

视图控制器是只将请求转发到视图而不做其他事情的控制器。

声明一个配置类,继承WebMvcConfigurer 接口,addViewControllers()方法会接收一个ViewControllerRegistry对象,我们可以使用它注册一个或多个视图控制器。
在这里将“/”传递了进去, 视图控制器将会针对该路径执行GET请求。 这个方法会返回ViewControllerRegistration对象, 基于该对象调用了setViewName()方法, 用它指明当请求“/”的时
候要转发到“home”视图上。

为每种配置(Web、 数据、 安全等)创建新的配置类, 这样能够保持应用的引导配置类尽可能地整洁和简单。

@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("home");}
}

选择视图模板库

Spring非常灵活, 能够支持很多常见的模板方案。
支持的模板方案

模板Spring Boot starter依赖
FreeMarkerspring-boot-starter-freemarker
GroovyTemplates spring-boot-starter-groovy-templates
Java Server Pages(JSP)无(由Tomcat或Jetty提供)
Mustachespring-boot-starter-mustache
Thymeleafspring-boot-starter-thymeleaf

选择想要的视图模板库, 将其作为依赖项添加到构建文件中, 然后就可以在“/templates”目录下 编写模板了。Spring Boot会探测到你所选择的模板库, 并自动配置为Spring MVC控制器生成视图所需的各种组件。

缓存模板

默认情况下, 模板只有在第一次使用的时候解析一次, 解析的结果会被后续的请求所使用。 能防止每次请求时多余的模板解析过程, 因此有助于提升性能。在开发期, 这个特性就不太友好了。 假设我们启动完应用之后访问taco的设计页面, 然后决定对它做一些修改, 但是当我们刷新Web浏览器的时候显示的依然是原始的版本。 要想看到变更效果, 就必须重新启动应用, 这当然是非常不方便的。

可以禁用缓存。就是将相关的缓存属性设置为false。如要禁用Thymeleaf缓存, 我们只需要在application.properties中添加如下这行代码:spring.thymeleaf.cache=false
唯一需要注意的是,在应用部署到生产环境之前,一定要删除这一行代码(或者将其设置为true)。

小结

  • Spring提供了一个强大的Web框架, 名为Spring MVC, 能够用来为Spring应用开发Web前端。
  • Spring MVC是基于注解的, 通过像@RequestMapping、@GetMapping和@PostMapping这样的注解来启用请求处理方法的声明。大多数的请求处理方法最终会返回一个视图的逻辑名称。
  • Spring MVC支持校验, 这是通过Java Bean Validation API和Validation API的实现(如Hibernate Validator) 完成的。
  • 对于没有模型数据和逻辑处理的HTTP GET请求, 可以使用视图控制器。
  • 除了Thymeleaf之外, Spring支持各种视图方案, 包括FreeMarker、Groovy Templates和Mustache。

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

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

相关文章

单点登录的认证过程,我拿到票据了, 可以卖肉了吗?

我拿到票据了, 可以卖肉了吗? SSO: 只能买一两, 不能再多了 单点登录的认证过程是如何的, 比方说单点登录服务D, 子系统A和B, A B D和浏览器之间是如何通信的 以下是单点登录&#xff08;SSO&#xff09;过程的详细步骤&#xff1a; 用户尝试访问子系统A。子系统A检查用户是否…

洛谷B2037奇偶数判断

洛谷B2037 题目描述 给定一个整数&#xff0c;判断该数是奇数还是偶数。如果 n 是奇数&#xff0c;输出 odd&#xff1b;如果 n 是偶数&#xff0c;输出 even。 输入格式 输入仅一行&#xff0c;一个整数 n。 输出格式 输出仅一行&#xff0c;如果n 是奇数&#xff0c;输出 o…

二分查找(二)

2.练习题 3&#xff09; 力扣https://leetcode.cn/problems/search-in-rotated-sorted-array-ii/这题需要分三种情况&#xff0c;第一种是区间有序&#xff0c;正常二分查找&#xff0c;第二种是区间 被旋转&#xff0c;左区间的值大于右区间&#xff0c;需要比较目标值和左区…

如何计算和提高客户生命周期价值 (LTV)

客户生命周期价值&#xff08;LTV或 CLV&#xff09;是衡量客户在其生命周期内为企业带来的总价值的关键指标。在电子商务中&#xff0c;LTV在决定企业的健康和成功方面起着至关重要的作用。LTV越高&#xff0c;业务的盈利能力和可持续性就越高。最常见的 LTV公式&#xff1a;L…

iphone distribution

未受信任的企业级开发者 通用 - VPN与设备管理 显示你下载的APP列表&#xff0c;点击进入 点击【信任xxxxx】

codeblocks20.3配置wxWidget3.2.2.1

codeblocks20.3 # 英文版自带gcc810&#xff0c;不汉化 wxWidget3.2.2.1 github下载源码 win11专业版 1.下载wxWidget3.2.2.1 源码 2.下载后解压到一个目录中&#xff0c;不要含中文和空格。我放在&#xff1a;d:\wxWidget3.2.2.1 3.打开终端cd build/msw 4.编译wxWidgets 为 …

多重背包问题 二进制优化 java 路径记录

多重背包---二进制拆分---java小知识_java多重背包问题_m78星云杰克的博客-CSDN博客 应该可以使用完全背包问题的记录路径的方法&#xff0c;例如&#xff0c;使用二维数组记录&#xff0c;记录当前硬币需要多少个

音视频骚操作,FFmpeg 如何播放带「图片」的 M3U8 视频,IJKPlyaer 适配非标 TS 文件

如果看到一个需要播放的视频链接显示是一张图片&#xff0c;你会不会感觉有点懵&#xff1f;如果这张图片写着 png&#xff0c;然后实际格式是 bmp &#xff0c;你会不会更懵了&#xff1f;如果这个 bmp 还做了加密篡改呢&#xff1f;今天我们要聊的就是这样一个充满骚操作的音…

css三角和css 用户见面样式,vertical-align 属性应用,溢出的文字省略号显示,常见布局技巧

目录 3.CSS三角 4.CSS 用户界面样式 4.1什么是界面样式 4.2轮廓线 outline 4.3 防止拖拽文本域 resize 5.vertical-align 属性 5.1图片,表单都属于行内块元素&#xff0c;默认的vertical-align 是基线对齐。 5.2解决图片底部默认空白缝隙问题 6.溢出的文字省略号显示 1.单…

linux centos7 查看端口占用命令netstat 报错提示 –bash:netstat:未找到命令解决方法

今天在一台centos7上用netstat命令看端口占用情况&#xff0c;提示 –bash:netstat:未找到命令&#xff1a; 解决方法&#xff1a; 输入 yum search ifconfig 查看这个命令是在 net-tools.x86_64里的&#xff1a; 然后安装这个包&#xff0c;输入 yum install net-tools 安装&…

ERTEC200P-2 PROFINET设备完全开发手册(2-1)

2. 入门指导&#xff1a;第一个PN IO设备 开发之前的准备&#xff0c;需要的软件&#xff1a; TIA Portal V16、V17串口终端软件 (MobaXterm或Putty或TeraTerm)Win10 并且安装64位JAVA运行环境J-Link的驱动软件Proneta&#xff08;推荐使用&#xff09; 需要准备的硬件 性能…

通信算法之130:软件无线电-接收机架构

1. 超外差式接收机 2.零中频接收机 3.数字中频接收机

洛谷B2033A*B问题

洛谷B2033 题目描述 输入两个正整数A 和B&#xff0c;求 AB 的值。注意乘积的范围和数据类型的选择。 输入格式 一行&#xff0c;包含两个正整数 A 和B&#xff0c;中间用单个空格隔开。1≤A,B≤50000。 输出格式 一个整数&#xff0c;即AB 的值 代码&#xff1a; #include&…

MySQL-双主高可用

目录 &#x1f341;拓扑环境 &#x1f341;配置两台MySQL主主同步 &#x1f343;修改MySQL配置文件 &#x1f343;配置主从关系 &#x1f343;测试主主同步 &#x1f341;keepalived高可用 &#x1f343;keepalived的安装配置 &#x1f343;master配置 &#x1f343;slave配置 …

Aurora 64B/66B 协议介绍

简介 Aurora 是一个用于在点对点串行链路间移动数据的可扩展轻量级链路层协议。这为物理层提供透明接口&#xff0c;让专有协议或业界标准协议上层能方便地使用高速收发器。虽然使用的逻辑资源非常少&#xff0c;但 Aurora 能提供低延迟高带宽和高度可配置的特性集。 特性&…

凹凸/法线/移位贴图的区别

你是否在掌握 3D 资产纹理的道路上遇到过障碍&#xff1f; 不要难过&#xff01; 许多刚接触纹理或 3D 的艺术家在第一次遇到凹凸贴图&#xff08;Bump Map&#xff09;、法线贴图&#xff08;Normal Map&#xff09;和移位贴图&#xff08;Displacement Map&#xff09;时通常…

React class组件和hooks setState异步更新数据详解

一、 class组件setState详解 1.class组件setState异步更新数据详解 class Father extends React.Component{state {num:0}addHandler () > { this.setState({num: 100})console.log(state中的值,this.state.num)}render() { return (<div><button onClick{this…

DBC数据库中定义信号时采用的两种字节顺序:Intel、Motorola(深度好文)

我之前写过好几篇文章介绍大端小端的存储、显示和读取。在介绍DBC的文章中,也有信号在CAN消息数据中如何定义的顺序,它和大端小端采用的原理相同,但是不能带入数据大端小端存储的方法。这里千万要注意! DBC数据库中定义信号时采用的字节顺序,如果想讲明白,很简单。但是如…

「解析」Jetson 安装 CUDA/cuDNN

注意&#xff1a;自从JetPack 升级到 5.0版本之后&#xff0c;可以&#xff0c;JetPack 官方教程 官方教程提供了三种方法&#xff1a;SD卡、SDK Manager 以及 apt安装Jetpack。前两种主要用于Orin系列之前的 Jetson开发板&#xff0c;主要针对还没有烧录系统的空机。而从 Jets…

手机也可以3D沙发建模

3D沙发建模是当今室内设计领域中必不可少的一种技术。通过此技术&#xff0c;我们可以使用虚拟设计软件创建高质量的3D沙发模型。这些模型具有极高的精度和逼真度&#xff0c;可以帮助设计师更好地展示他们的创意&#xff0c;并有效地促进设计过程。 在进行3D沙发建模时&#…