适用于Java EE / Jakarta EE开发人员的Micronaut

城镇中有一个名为Micronaut的新微服务框架。 在本文中,我将从Java EE / Jakarta EE的角度讨论如何冒险使用Micronaut框架。 我是Java EE开发人员,因此使用诸如Eclipse MicroProfile之类的解决方案开发微服务更接近我的专业知识,但是Micronaut吸引了我的注意力,因为它具有以下功能:

–使用Java,Groovy或Kotlin开发

–易于通过Spock或JUnit进行测试..完全集成的测试

–嵌入式服务器和编译时HTTP客户端

–易于打包的Docker

–快速启动时间,低内存消耗

–完全反应

作为内心的企业开发人员,我的第一个想法通常是数据库,因为我编写的大多数应用程序都使用RDBMS。 我发现将Micronaut与RDBMS一起使用的示例数量很少,因此我认为为该用例创建另一个示例可能对我有用。 在此示例中,我使用PostgreSQL。 但是,大多数其他RDBMS也受支持。 本文无意对安装Micronaut或利用所有许多Micronaut功能进行完整说明。 相反,它是那些希望开始使用带有关系数据库的Micronaut的入门指南……尤其适合那些具有Java EE / Jakarta EE背景的人。

在我的特殊情况下,我对快速完善可测试,可扩展和高效的微服务感兴趣。 尽管我可以使用MicroProfile或标准Java EE做到这一点,但我认为学习新知识并具有使用Groovy或Kotlin的能力将很有趣。 我还想将Java EE / Jakarta EE放在上面……所以我正在使用JPA来处理数据。 许多Micronaut示例都使用Groovy和GORM来实现持久性……但是我可能不会在我的任何应用程序中使用它。

该示例是使用Apache NetBeans 9.0和Micronaut随附的命令行界面(CLI)开发的 。 此特定示例是针对Micronaut 1.0.0.M4编写的。 在这种情况下,我保持简单,只使用一个基本数据库表在PostgreSQL数据库中进行持久化。

首先,我通过发出以下命令利用CLI创建了一个应用程序:

mn create-app org.acme.books --features hibernate-jpa,jdbc-tomcat

这只是在名为“ books”的目录中为我的应用程序创建了一个框架,Application.java主类将放置在org.acme.books包中。 默认情况下,应用程序支持一些基本功能,但是在这种情况下,我添加了对Tomcat连接池的支持。 通过Java Persistence API(JPA)创建数据库连接时,将利用此功能。 默认应用程序也会在支持Gradle构建系统的情况下生成。 因此,将创建一个build.gradle,即将在其中进行依赖项管理的文件。 请注意,也可以使用Apache Maven构建系统来生成应用程序,但是在Micronaut 1.0.0.M4下运行Maven项目时遇到了问题,因此在这个示例中我坚持使用Gradle。

如果使用Apache NetBeans 9.0,则可以安装“ Groovy and Grails”和“ Gradle”插件(当前在NetBeans 8.2插件中心提供)以提供打开项目的支持。 一旦完成,就可以在NetBeans中打开项目并开始开发。 安装插件并在Apache NetBeans中打开项目后,完整的项目结构应如下图所示:

微型船

为了提供对PostgreSQL数据库的支持,我在build.gradle中添加了依赖项:

compile group: 'org.postgresql', name: 'postgresql', version: '42.2.5'

接下来,我打开了application.yml文件,并为该应用程序添加了数据源。 这是替换传统Java EE应用程序中的persistence.xml的文件。 另外,通过此文件添加了JPA支持,指示哪个包包括实体类以及Hibernate的配置。 端口8080也已设置,因为默认情况下Micronaut将选择一个随机端口来启动服务器。 application.xml的完整资源如下:

micronaut:application:name: books#Uncomment to set server portserver:port: 8080---datasources:default:url: jdbc:postgresql://localhost/postgresusername: postgrespassword: yourpassworddriverClassName: org.postgresql.DriverconnectionTimeout: 4000jpa:default:packages-to-scan:- 'org.acme.domain'properties:hibernate:hbm2ddl:auto: updateshow_sql: true

现在配置已不复存在,我可以开始有趣的部分了……开发。 在此示例中,我创建了一项基本服务,该服务允许用户在BOOK表中创建,读取,更新或删除记录。 org.acme包中自动生成的Application类,用于启动服务。

package org.acme;import io.micronaut.runtime.Micronaut;public class Application {public static void main(String[] args) {Micronaut.run(Application.class);}}

要开始开发,请在应用程序中创建两个用于组织源代码的软件包。 首先,创建org.acme.domain,它将包含实体类。 接下来,创建org.acme.book,其中将包含实现类。 在org.acme.domain包中创建一个Book.java类,它将是包含数据库标准JPA映射的实体类。 在这种情况下,请注意,我将java.time.LocalDate用于日期字段,并将数据库序列生成器用于主键填充。 来源如下:

package org.acme.domain;import java.time.LocalDate;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.SequenceGenerator;import javax.persistence.Table;import javax.validation.constraints.NotNull;/*** JPA Mappings for the BOOK database table.*/@Entity@Table(name="BOOK")public class Book {@Id@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="book_generator")@SequenceGenerator(name="book_generator",sequenceName="book_s", allocationSize=1)private Long id;@Column(name="PUBLISH_DATE")@NotNullprivate LocalDate publishDate;@Column(name="TITLE")@NotNullprivate String title;@Column(name="AUTHOR_FIRST")@NotNullprivate String authorFirst;@Column(name="AUTHOR_LAST")@NotNullprivate String authorLast;private Long pages;public Book(){}public Book(@NotNull Long id, @NotNull LocalDate publishDate, @NotNull String title, String authorFirst, String authorLast, Long pages){this.id = id;this.publishDate = publishDate;this.title = title;this.authorFirst = authorFirst;this.authorLast = authorLast;this.pages = pages;}public Book(@NotNull LocalDate publishDate, @NotNull String title, String authorFirst, String authorLast, Long pages){this.publishDate = publishDate;this.title = title;this.authorFirst = authorFirst;this.authorLast = authorLast;this.pages = pages;}/*** @return the id*/public Long getId() {return id;}/*** @param id the id to set*/public void setId(Long id) {this.id = id;}/*** @return the publishDate*/public LocalDate getPublishDate() {return publishDate;}/*** @param publishDate the publishDate to set*/public void setPublishDate(LocalDate publishDate) {this.publishDate = publishDate;}/*** @return the title*/public String getTitle() {return title;}/*** @param title the title to set*/public void setTitle(String title) {this.title = title;}/*** @return the authorFirst*/public String getAuthorFirst() {return authorFirst;}/*** @param authorFirst the authorFirst to set*/public void setAuthorFirst(String authorFirst) {this.authorFirst = authorFirst;}/*** @return the authorLast*/public String getAuthorLast() {return authorLast;}/*** @param authorLast the authorLast to set*/public void setAuthorLast(String authorLast) {this.authorLast = authorLast;}/*** @return the pages*/public Long getPages() {return pages;}/*** @param pages the pages to set*/public void setPages(Long pages) {this.pages = pages;}@Overridepublic String toString() {return "Book{" +"id=" + id +", publishDate='" + publishDate + '\'' +", title='" + title + '\'' +", authorFirst='" + authorFirst + '\'' +", authorLast='" + authorLast + '\'' +", pages='" + pages +'}';}}

在Micronaut应用程序中,需要将HTTP请求和响应封装在Serializable类中进行处理,因此,生成一些简单的“纯旧Java对象”(POJO)来封装将在数据库操作中使用的数据是有意义的。 在同一个org.acme.domain包中,我创建了两个此类,BookSaveOperation.java和BookUpdateOperation.java。 这些类将定义将数据从HTTP请求传递到控制器类所需的字段。 BookSaveOperation.java的源如下(有关完整源,请参见GitHub存储库):

package org.acme.domain;import java.time.LocalDate;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;/**** @author Josh Juneau*/public class BookSaveOperation implements java.io.Serializable {@NotNullprivate LocalDate publishDate;@NotNull@NotBlankprivate String title;@NotNull@NotBlankprivate String authorFirst;@NotNull@NotBlankprivate String authorLast;private Long pages;public BookSaveOperation(){}public BookSaveOperation(LocalDate publishDate, String title,String authorFirst, String authorLast, Long pages){this.publishDate = publishDate;this.title = title;this.authorFirst = authorFirst;this.authorLast = authorLast;this.pages = pages;}// ...// getters and setters// ...}

应用程序业务逻辑发生在一个类中,该类非常类似于EJB或DAO实现,并且该类必须实现定义了每个业务逻辑方法的接口。 在这种情况下,我创建了一个接口org.acme.book.BookRepository.java,并定义了一些标准的操作方法:

package org.acme.book;import java.time.LocalDate;import java.util.List;import java.util.Optional;import org.acme.domain.Book;/****/public interface BookRepository {Book save(LocalDate publishDate, String title, String authorFirst, String authorLast, Long pages);Optional<Book> findById(Long id);void deleteById(Long id);List<Book> findAll();int update(Long id, LocalDate publishDate, String title, String authorFirst, String authorLast, Long pages);}

接下来,在名为org.acme.book.BookRepositoryImpl.java的类中实现该接口,并注释为@Singleton。 由于这是将实现业务逻辑的类,因此请注入一个PersistenceContext,该持久性上下文提供将用于执行数据库操作的JPA EntityManager。 只需实现BookRepository界面中概述的每个操作,并使用@Transactional(io.micronaut.spring.tx.annotation.Transactional)进行标记,就意味着仅对那些不会修改任何数据的方法进行只读。 BookRepositoryImpl.java的源如下:

package org.acme.book;import io.micronaut.configuration.hibernate.jpa.scope.CurrentSession;import io.micronaut.spring.tx.annotation.Transactional;import java.time.LocalDate;import java.util.List;import java.util.Optional;import javax.inject.Singleton;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import org.acme.domain.Book;/*** Business logic for the service.*/@Singletonpublic class BookRepositoryImpl implements BookRepository {@PersistenceContextprivate EntityManager entityManager;public BookRepositoryImpl(@CurrentSession EntityManager entityManager) {this.entityManager = entityManager;}@Override@Transactionalpublic Book save(LocalDate publishDate, String title, String authorFirst, String authorLast, Long pages) {Book book = new Book(publishDate, title, authorFirst, authorLast, pages);entityManager.persist(book);return book;}@Override@Transactional(readOnly = true)public Optional<Book> findById(Long id) {return Optional.ofNullable(entityManager.find(Book.class, id));}@Transactional(readOnly = true)public List<Book> findAll() {return entityManager.createQuery("SELECT b FROM Book b", Book.class).getResultList();}@Override@Transactionalpublic int update(Long id, LocalDate publishDate, String title, String authorFirst, String authorLast, Long pages) {return entityManager.createQuery("UPDATE Book b SET publishDate = :publishDate, title = :title, " +"authorFirst = :authorFirst, authorLast = :authorLast, pages = :pages where id = :id").setParameter("publishDate", publishDate).setParameter("title", title).setParameter("authorFirst", authorFirst).setParameter("authorLast", authorLast).setParameter("pages", pages).setParameter("id", id).executeUpdate();}@Override@Transactionalpublic void deleteById(Long id) {findById(id).ifPresent(book -> entityManager.remove(book));}}

为了从Java EE角度解释Micronaut应用程序基础结构,我将比较该实现与一个简单的JAX-RS应用程序。 Micronaut利用io.micronaut.http.annotation.Controller类来执行服务的请求-响应处理。 这非常类似于JAX-RS控制器类,但有一些细微的差异。 这让我想起了Eclipse Krazo项目或Java EE的MVC 1.0。 例如,Micronaut而不是使用JAX-RS注释javax.ws.rs.GET,javax.ws.rs.POST或javax.ws.rs.Path注释方法,而是使用io.micronaut.http.annotation.Get和io.micronaut.http.annotation.Post等。 每个方法的URI路径都可以通过@ Get,@ Post,@ Put,@ Delete批注直接声明。 每个控制器类将实现服务的功能并处理请求-响应生命周期。 通过@Inject批注或构造函数注入将用于持久性的业务逻辑(包含在BookRepositoryImpl类中)注入到控制器类中。 在此示例的源代码中,使用了构造函数注入。

package org.acme.book;import org.acme.domain.Book;import io.micronaut.http.HttpHeaders;import io.micronaut.http.HttpResponse;import io.micronaut.http.annotation.Body;import io.micronaut.http.annotation.Controller;import io.micronaut.http.annotation.Delete;import io.micronaut.http.annotation.Get;import io.micronaut.http.annotation.Post;import io.micronaut.http.annotation.Put;import io.micronaut.validation.Validated;import javax.validation.Valid;import java.net.URI;import java.util.List;import org.acme.domain.BookSaveOperation;import org.acme.domain.BookUpdateOperation;@Validated@Controller("/books")public class BookController {protected final BookRepository bookRepository;public BookController(BookRepository bookRepository) {this.bookRepository = bookRepository;}@Get("/")public List<Book> list() {return bookRepository.findAll();}@Put("/")public HttpResponse update(@Body @Valid BookUpdateOperation operation) {bookRepository.update(operation.getId(), operation.getPublishDate(),operation.getTitle(), operation.getAuthorFirst(), operation.getAuthorLast(), operation.getPages());return HttpResponse.noContent().header(HttpHeaders.LOCATION, location(operation.getId()).getPath());}@Get("/{id}")Book show(Long id) {return bookRepository.findById(id).orElse(null);}@Delete("/{id}")HttpResponse delete(Long id) {bookRepository.deleteById(id);return HttpResponse.noContent();}@Post("/")HttpResponse<Book> save(@Body @Valid BookSaveOperation operation) {Book book = bookRepository.save(operation.getPublishDate(), operation.getTitle(),operation.getAuthorFirst(), operation.getAuthorLast(), operation.getPages());return HttpResponse.created(book).headers(headers -> headers.location(location(book)));}protected URI location(Book book) {return location(book.getId());}protected URI location(Long id) {return URI.create("/books/" + id);}}

测试应用

Micronaut可以使用Spock或JUnit以及嵌入式服务器轻松进行测试,从而可以轻松地为每个控制器创建测试。 在这种情况下,我利用JUnit来测试应用程序。 我在名为org.acme.BookControllerTest的项目的测试文件夹内创建了一个测试类。

package org.acme;import io.micronaut.context.ApplicationContext;import io.micronaut.core.type.Argument;import io.micronaut.http.HttpHeaders;import io.micronaut.http.HttpRequest;import io.micronaut.http.HttpResponse;import io.micronaut.http.HttpStatus;import io.micronaut.http.client.HttpClient;import io.micronaut.runtime.server.EmbeddedServer;import java.time.LocalDate;import java.util.ArrayList;import java.util.List;import org.acme.domain.Book;import org.acme.domain.BookSaveOperation;import org.acme.domain.BookUpdateOperation;import org.junit.AfterClass;import static org.junit.Assert.assertEquals;import org.junit.BeforeClass;import org.junit.Test;/*** Test cases for BookController*/public class BookControllerTest {private static EmbeddedServer server;private static HttpClient client;private  Book book;HttpRequest request;HttpResponse response;Long id;List<Long> bookIds = new ArrayList<>();@BeforeClasspublic static void setupServer() {server = ApplicationContext.run(EmbeddedServer.class);client = server.getApplicationContext().createBean(HttpClient.class, server.getURL());}@AfterClasspublic static void stopServer() {if (server != null) {server.stop();}if (client != null) {client.stop();}}@Testpublic void testInsertBooks() {request = HttpRequest.POST("/books", new BookSaveOperation(LocalDate.now(), "Java EE 8 Recipes", "Josh", "Juneau", new Long(750)));response = client.toBlocking().exchange(request);assertEquals(HttpStatus.CREATED, response.getStatus());request = HttpRequest.POST("/books", new BookSaveOperation(LocalDate.now(), "Java 9 Recipes", "Josh", "Juneau", new Long(600)));response = client.toBlocking().exchange(request);id = entityId(response, "/books/");assertEquals(HttpStatus.CREATED, response.getStatus());}@Testpublic void testBookRetrieve() {request = HttpRequest.GET("/books");List<Book> books = client.toBlocking().retrieve(request, Argument.of(List.class, Book.class));// Populate a book instance for laterfor(Book b:books){book = b;}assertEquals(2, books.size());}@Testpublic void testBookOperations() {request = HttpRequest.GET("/books");List<Book> books = client.toBlocking().retrieve(request, Argument.of(List.class, Book.class));// Populate a book instance for laterfor(Book b:books){book = b;}request = HttpRequest.PUT("/books/", new BookUpdateOperation(book.getId(),book.getPublishDate(),"Java 10 Recipes",book.getAuthorFirst(),book.getAuthorLast(),book.getPages()));response = client.toBlocking().exchange(request);assertEquals(HttpStatus.NO_CONTENT, response.getStatus());request = HttpRequest.GET("/books/" + book.getId());book = client.toBlocking().retrieve(request, Book.class);assertEquals("Java 10 Recipes", book.getTitle());testDelete();}public void testDelete(){request = HttpRequest.GET("/books");List<Book> books = client.toBlocking().retrieve(request, Argument.of(List.class, Book.class));// Populate a book instance for laterfor(Book b:books){request = HttpRequest.DELETE("/books/" + b.getId());response = client.toBlocking().exchange(request);assertEquals(HttpStatus.NO_CONTENT, response.getStatus());}}Long entityId(HttpResponse response, String path) {String value = response.header(HttpHeaders.LOCATION);if (value == null) {return null;}int index = value.indexOf(path);if (index != -1) {return Long.valueOf(value.substring(index + path.length()));}return null;}}

考试逻辑导论

在运行@BeforeClass的方法中,将创建HTTP服务器和客户端。 同样,当测试完成执行时,将调用用@AfterClass注释的方法,如果服务器正在运行,它将停止服务器。

在textInsertBooks()方法中,通过将填充了数据的新BookSaveOperation对象传递给可通过@Post命名的“ / books”路径访问的服务,来创建两个新的书记录。 在这种情况下,将调用控制器方法BookController.save()。 看一下save()方法,您可以看到该方法只是将BookSaveOperation的内容传递给BookRepository.save()业务方法(利用该接口),从而持久化对象。 最后,返回HttpResponse。

testBookRetrieve()方法调用包含@Get名称的“ / books”路径上可用的服务。 依次调用BookController.list()方法,该方法在BookRepository上执行findAll(),返回Book对象的List。

testBookOperations()方法负责对记录进行更新。 首先,从BookController中检索Book对象的列表,然后通过使用要更新的内容填充BookUpdateOperation对象,通过BookController.update()方法更新其中一本书。

**请记住,BookSaveOperation.java和BookUpdateOperation.java对象只是用于移动数据的POJO。

最后,调用testDelete()方法,该方法遍历Book对象的List,通过对“ / books”路径的服务调用来调用BookController.delete()方法,并调用指定为@Delete的方法。

要执行测试,只需在NetBeans中右键单击该项目并选择“ Test”,或使用命令行使用以下命令来调用

./gradlew test

如果尚未创建数据库表,则将为您生成该表。 请注意,您可能需要根据环境修改application.yml中的数据库配置。

运行服务

Micronaut是独立的,允许使用基于Netty构建的嵌入式服务器执行服务。 可以通过右键单击Apache NetBeans中的项目并选择“运行”来完成。 您也可以转到命令行并使用以下命令进行调用:

./gradlew run

您应该在终端或Apache NetBeans输出面板的输出中看到托管服务器的URL。

摘要

作为Java EE开发人员,我不得不说Micronaut确实有不同的开发方法。 它与Spring Boot或Grails并没有太大区别,但又有足够的区别,以至于我花了一些时间找到解决方法。 最后,我发现它是一个易于使用的框架,它具有快速开发服务或计划任务的巨大潜力,同时仍然利用Java EE / Jakarta EE的一些概念。

我还没有使用很多功能,例如通过Micronaut框架创建计划任务,以及使用Groovy或Kotlin而不是Java进行开发。 我希望在以后的文章中继续介绍对有兴趣开始Micronaut之旅的Java EE和Jakarta EE开发人员的更多信息。

GitHub项目:https://github.com/juneau001/micronaut-books

翻译自: https://www.javacodegeeks.com/2018/09/micronaut-for-java-ee-jakarta-ee-developers.html

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

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

相关文章

塔罗牌第五张是什么牌_塔罗牌四季牌阵:冬至将至,快来看看未来这三个月运势如何?...

塔罗牌四季牌阵&#xff0c;是一个神奇的牌阵&#xff0c;因为一年之中只有占卜四次的机会。塔罗牌四季牌阵最初从塔罗师 Marcia Masino 的《Best Tarot Practices》&#xff0c;作为占卜接下来三个月也就是一个季度整体运势的一种特殊牌阵&#xff0c;只能在每年四个季节转变的…

了解Beamforming

波束成形技术是将信号以一种能量集中和定向方式发送给无线终端的技术&#xff0c;能全面改善无线终端接收的信号质量&#xff0c;并提升吞吐量。 如果要采用波束成形技术&#xff0c; 前提是必须采用多天线系统。例如&#xff0c;多进多出&#xff08;MIMO&#xff09;&#xf…

saiku docker配置部署_【安装教程】01 Gitea Docker 安装部署 - 【SkywenCode】技术团队基...

在2016年-2019年&#xff0c;SkywenCode技术团队使用码云Gitee 作为线上代码库管理&#xff0c;基于敏捷开发和持续构建的思路&#xff0c;我们整体基础建设以Drone / Jenkins Docker 的方式构建和部署整个基础建设体系。在接下来的时间里&#xff0c;SkywenCode技术团队基础建…

通信系统的主要性能指标

性能指标的作用就是用来衡量这个系统是否是一个好的系统。 总体的性能指标包括&#xff1a;有效性&#xff0c;可靠性&#xff0c;适用性&#xff0c;经济性&#xff0c;标准性&#xff0c;可维护性等。 其中关键的指标主要是有效性和可靠性。 一. 有效性 &#xff08;1&…

数学猜想验证步骤_高中数学解题思路与技巧汇总,19种解题方法,实用!

解数学题&#xff0c;除了掌握有关的数学知识之外&#xff0c;最好掌握一定的解题技巧甚至知道点解题思想。要知道高考试题的解答过程中蕴含着重要的数学思想方法&#xff0c;如果能有意识地在解题过程中加以运用&#xff0c;势必会取得很好的效用。下面邦德华纳整理了19种数学…

衡量网络性能的四大指标:带宽、时延、抖动、丢包

一 带宽 1、带宽概念&#xff1a; 带宽在百度百科中定义&#xff1a;在单位时间内从网络中的某一点到另一点所能通过的**“最高数据率”**。 计算机网络的带宽是指网络可通过的最高数据率&#xff0c;即每秒多少比特&#xff08;常用的单位是bps(bit per second)&#xff09…

kuka机器人焊接飞溅大_库卡机器人KCP4示教器屏幕校准方法

库卡于1898年在德国奥格堡成立&#xff0c;是世界几家顶级工业机器人制造商之一&#xff0c;1973年公司研发的FAMULUS第一台工业机器人诞生。库卡机器人公司在全球拥有20 多个子公司&#xff0c;涵盖了美国、墨西哥、巴西、日本、韩国、中国、台湾、印度和绝大多数欧洲国家。库…

使用Spock 1.2简化对遗留应用程序的集成测试

了解如何利用Spock 1.2切片传统应用程序的Spring上下文&#xff0c;编写集成测试。 您是否曾经想过&#xff0c;要开始使用一些遗留应用程序&#xff0c;编写一些测试以了解正在发生的事情&#xff0c;并可能收到有关回归的通知&#xff1f; 当您想实例化单个类时&#xff0c;这…

Windows中PDF TXT Excel Word PPT等Office文件在预览窗格无法预览的终级解决方法大全

切记&#xff1a;以上方法均会对注册表进行修改&#xff0c;一定要先备份整个注册表&#xff0c;以防万一&#xff0c;避免导致系统错误 一、问题症状或错误复现&#xff1a; 1、首先要打开 文件资源管理器的 文件 预览窗格 2、然后在文件资源管理器的右边就会显示预览窗格…

vue快速修改数组的某个值_详解vue组件三大核心概念

前言本文主要介绍属性、事件和插槽这三个vue基础概念、使用方法及其容易被忽略的一些重要细节。如果你阅读别人写的组件&#xff0c;也可以从这三个部分展开&#xff0c;它们可以帮助你快速了解一个组件的所有功能。本文的代码请猛戳github博客&#xff0c;纸上得来终觉浅&…

根据id获取多维数组路径_程序员的进阶课-架构师之路(2)-数组

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a;https://blog.csdn.net/m0_37609579/article/details/99355842 从这一节开始&#xff0c;我们就要正式进去数据结构的世界了…

自定义条件查询_数据查询不止有vlookup函数,自定义zlookup函数查询操作更高效...

Excel数据查询&#xff0c;相信大家首先会想到vlookup函数。毋庸置疑vlookup函数在Excel数据查询中作用是非常的强大。但是它也有一些不能实现的数据查询。如上图所示&#xff0c;我们需要根据人员的出现次数&#xff0c;提取第N次的数据。这里vlookup函数就无法使用&#xff0…

2021年中国工业互联网行业发展现状分析,“5G+工业互联网”驱动行业快速发展

一、概述 工业互联网是新一代信息通信技术与工业经济深度融合的新型基础设施、应用模式和工业生态&#xff0c;通过对人、机、物、系统等的全面连接&#xff0c;构建起覆盖全产业链、全价值链的全新制造和服务体系&#xff0c;为工业乃至产业数字化、网络化、智能化发展提供了…

针对数能同传SWIPT的个人理解与总结Part1

无线数能同传&#xff08;Simultaneous Wireless Information and Power Transfer, SWIPT&#xff09;技术是指利用无线射频信号可同时携载信息与能量的特点&#xff0c;从一个射频信号中同时接收信息与能量的技术。 一、接收机架构 SWIPT有很多种解释&#xff0c;携能通信、…

米筐量化不支持c语言_量化 | 从零开始学量化(三):数据获取途径

本系列的前两篇都是一些笼统的介绍&#xff0c;供小白制定学习计划时参考&#xff0c;现在该铺垫的都铺垫的差不多了。循序渐进&#xff0c;从本篇开始会写一些能实操的内容&#xff0c;尽量写的很细节&#xff0c;有任何问题欢迎私戳。本篇给出一些数据获取途径&#xff0c;基…

射频知识简介

无线通信系统中&#xff0c;一般包含有天线、射频前端、射频收发模块以及基带信号处理器四个部分。随着5G时代的&#xff0c;天线以及射频前端的需求量及价值均快速上升&#xff0c;射频前端是将数字信号向无线射频信号转化的基础部件&#xff0c;也是无线通信系统的核心组件。…

尽可能地做到无服务器,但不止于此

毫无疑问&#xff0c;如果您一直关注技术趋势&#xff0c;那么您会看到“无服务器”的兴起。 在某些情况下&#xff0c;“无服务器”被称为“下一个应用程序体系结构”样式。 我什至听说有人说“您不需要技术X&#xff0c;因为无服务器是未来的方式”或“技术X是红鲱鱼&#xf…

信号扫描_科研必备“武器”之扫描电子显微镜

仪器介绍扫描电子显微镜&#xff08;英语名称为Scanning Electron Microscope&#xff0c;缩写为SEM&#xff09;&#xff0c;简称扫描电镜。它是一种电子显微镜&#xff0c;利用聚焦电子束扫描样品的表面来产生样品表面的图像。最常见的扫描电镜模式是检测由电子束激发的原子发…

解决office一打开就显示正在更新,过一会就报错的问题

问题描述&#xff1a; 一打开office就显示正在更新&#xff0c;请稍后&#xff0c;过一会就弹窗报错。 解决方案&#xff1a; 1.winR输入services.msc 2.将Microsoft Office即点即用服务设为自动 如果第二步中已经是自动状态&#xff0c;先禁用一下&#xff0c;再重新设置为…

框架如何调用存储过程_如何在FastReport.Net中使用存储过程

在本文中&#xff0c;我们将讨论使用存储过程来检索报表的数据&#xff0c;使用MS SQL示例&#xff0c;将展示如何在报表中创建和使用函数。Transact SQL允许创建存储过程和函数&#xff0c;存储过程用于自动执行任何操作&#xff0c;这些功能旨在扩展查询功能&#xff0c;它们…