以Spring方式构建企业Java应用程序

我认为可以肯定地说, Java EE在Java开发人员中享有很高的声誉。 尽管多年来确实在各个方面都有所改善,甚至将其改名为Eclipse Foundation成为Jakarta EE ,但其苦味仍然相当浓厚。 另一方面,我们拥有Spring框架 (或者为了更好地反映现实,一个成熟的Spring平台 ):出色,轻巧,快速,创新和高产的Java EE替代品。 那么,为什么要打扰Java EE ?

我们将通过展示使用大多数Java EE规范构建现代Java应用程序有多么容易来回答这个问题。 成功的关键要素是Eclipse Microprofile : 微服务时代的企业Java。

我们将要构建的应用程序就是RESTful Web API,用于管理人员,就这么简单。 在Java中构建RESTful Web服务的标准方法是使用JAX-RS 2.1 ( JSR-370 )。 因此, CDI 2.0 ( JSR-365 )将负责依赖注入,而JPA 2.0 ( JSR-317 )将涵盖数据访问层。 当然, Bean Validation 2.0 ( JSR-380 )正在帮助我们处理输入验证。

我们将要依赖的唯一非Java EE规范是OpenAPI v3.0 ,它有助于提供RESTful Web API的可用描述。 这样,让我们​​开始使用PersonEntity域模型(将getter和setter省略为不太相关的细节):

@Entity
@Table(name = "people")
public class PersonEntity {@Id @Column(length = 256) private String email;@Column(nullable = false, length = 256, name = "first_name")private String firstName;@Column(nullable = false, length = 256, name = "last_name")private String lastName;@Versionprivate Long version;
}

它只是具有绝对最小的一组属性。 JPA存储库非常简单,并实现了一组典型的CRUD方法。

@ApplicationScoped
@EntityManagerConfig(qualifier = PeopleDb.class)
public class PeopleJpaRepository implements PeopleRepository {@Inject @PeopleDb private EntityManager em;@Override@Transactional(readOnly = true)public Optional<PersonEntity> findByEmail(String email) {final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<PersonEntity> query = cb.createQuery(PersonEntity.class);final Root<PersonEntity> root = query.from(PersonEntity.class);query.where(cb.equal(root.get(PersonEntity_.email), email));try {final PersonEntity entity = em.createQuery(query).getSingleResult();return Optional.of(entity);} catch (final NoResultException ex) {return Optional.empty();}}@Override@Transactionalpublic PersonEntity saveOrUpdate(String email, String firstName, String lastName) {final PersonEntity entity = new PersonEntity(email, firstName, lastName);em.persist(entity);return entity;}@Override@Transactional(readOnly = true)public Collection<PersonEntity> findAll() {final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<PersonEntity> query = cb.createQuery(PersonEntity.class);query.from(PersonEntity.class);return em.createQuery(query).getResultList();}@Override@Transactionalpublic Optional<PersonEntity> deleteByEmail(String email) {return findByEmail(email).map(entity -> {em.remove(entity);return entity;});}
}

事务管理(即@Transactional批注)需要一些解释。 在典型的Java EE应用程序中,容器运行时负责管理事务。 由于我们不想随身携带应用程序容器,而是保持精简,因此我们可以使用EntityManager来启动/提交/回滚事务。 当然可以解决,但是会污染样板代码。 可以说,更好的选择是使用Apache DeltaSpike CDI扩展进行声明式事务管理 (这是@Transactional@EntityManagerConfig注释的来源)。 下面的代码段说明了如何进行集成。

@ApplicationScoped
public class PersistenceConfig {@PersistenceUnit(unitName = "peopledb")private EntityManagerFactory entityManagerFactory;@Produces @PeopleDb @TransactionScopedpublic EntityManager create() {return this.entityManagerFactory.createEntityManager();}public void dispose(@Disposes @PeopleDb EntityManager entityManager) {if (entityManager.isOpen()) {entityManager.close();}}
}

太棒了,最难的部分已经过去了! 接下来是人员 数据传输对象和服务层。

public class Person {@NotNull private String email;@NotNull private String firstName;@NotNull private String lastName;
}

老实说,为了使示例应用程序尽可能小,我们可以完全跳过服务层,直接进入存储库。 但这通常不是一个很好的做法,因此无论如何让我们介绍PeopleServiceImpl

@ApplicationScoped
public class PeopleServiceImpl implements PeopleService {@Inject private PeopleRepository repository;@Overridepublic Optional<Person> findByEmail(String email) {return repository.findByEmail(email).map(this::toPerson);}@Overridepublic Person add(Person person) {return toPerson(repository.saveOrUpdate(person.getEmail(), person.getFirstName(), person.getLastName()));}@Overridepublic Collection<Person> getAll() {return repository.findAll().stream().map(this::toPerson).collect(Collectors.toList());}@Overridepublic Optional<Person> remove(String email) {return repository.deleteByEmail(email).map(this::toPerson);}private Person toPerson(PersonEntity entity) {return new Person(entity.getEmail(), entity.getFirstName(), entity.getLastName());}
}

剩下的唯一部分是JAX-RS应用程序和资源的定义。

@Dependent
@ApplicationPath("api")
@OpenAPIDefinition(info = @Info(title = "People Management Web APIs", version = "1.0.0", license = @License(name = "Apache License", url = "https://www.apache.org/licenses/LICENSE-2.0"))
)
public class PeopleApplication extends Application {
}

不多说,可能就这么简单。 不过, JAX-RS资源实现更加有趣( OpenAPI注释占据了大部分位置)。

@ApplicationScoped
@Path( "/people" ) 
@Tag(name = "people")
public class PeopleResource {@Inject private PeopleService service;@Produces(MediaType.APPLICATION_JSON)@GET@Operation(description = "List all people", responses = {@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Person.class))),responseCode = "200")})public Collection<Person> getPeople() {return service.getAll();}@Produces(MediaType.APPLICATION_JSON)@Path("/{email}")@GET@Operation(description = "Find person by e-mail", responses = {@ApiResponse(content = @Content(schema = @Schema(implementation = Person.class)), responseCode = "200"),@ApiResponse(responseCode = "404", description = "Person with such e-mail doesn't exists")})public Person findPerson(@Parameter(description = "E-Mail address to lookup for", required = true) @PathParam("email") final String email) {return service.findByEmail(email).orElseThrow(() -> new NotFoundException("Person with such e-mail doesn't exists"));}@Consumes(MediaType.APPLICATION_JSON)@Produces(MediaType.APPLICATION_JSON)@POST@Operation(description = "Create new person",requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = Person.class)),), responses = {@ApiResponse(content = @Content(schema = @Schema(implementation = Person.class)),headers = @Header(name = "Location"),responseCode = "201"),@ApiResponse(responseCode = "409", description = "Person with such e-mail already exists")})public Response addPerson(@Context final UriInfo uriInfo,@Parameter(description = "Person", required = true) @Valid Person payload) {final Person person = service.add(payload);return Response.created(uriInfo.getRequestUriBuilder().path(person.getEmail()).build()).entity(person).build();}@Path("/{email}")@DELETE@Operation(description = "Delete existing person",responses = {@ApiResponse(responseCode = "204",description = "Person has been deleted"),@ApiResponse(responseCode = "404", description = "Person with such e-mail doesn't exists")})public Response deletePerson(@Parameter(description = "E-Mail address to lookup for", required = true ) @PathParam("email") final String email) {return service.remove(email).map(r -> Response.noContent().build()).orElseThrow(() -> new NotFoundException("Person with such e-mail doesn't exists"));}
}

至此,我们完成了! 但是,我们如何将所有这些部件组装并连接在一起? 这是Microprofile进入舞台的时间。 有许多实现可供选择,本文中将使用的是Project Hammock 。 我们唯一要做的就是指定我们要使用的CDI 2.0 , JAX-RS 2.1和JPA 2.0实现,它们分别转换为Weld , Apache CXF和OpenJPA (通过Project Hammock依赖关系表示)。 让我们看一下Apache Maven pom.xml文件。

<properties><deltaspike.version>1.8.1</deltaspike.version><hammock.version>2.1</hammock.version>
</properties><dependencies><dependency><groupId>org.apache.deltaspike.modules</groupId><artifactId>deltaspike-jpa-module-api</artifactId><version>${deltaspike.version}</version><scope>compile</scope></dependency><dependency><groupId>org.apache.deltaspike.modules</groupId><artifactId>deltaspike-jpa-module-impl</artifactId><version>${deltaspike.version}</version><scope>runtime</scope></dependency><dependency><groupId>ws.ament.hammock</groupId><artifactId>dist-microprofile</artifactId><version>${hammock.version}</version></dependency><dependency><groupId>ws.ament.hammock</groupId><artifactId>jpa-openjpa</artifactId><version>${hammock.version}</version></dependency><dependency><groupId>ws.ament.hammock</groupId><artifactId>util-beanvalidation</artifactId><version>${hammock.version}</version></dependency><dependency><groupId>ws.ament.hammock</groupId><artifactId>util-flyway</artifactId><version>${hammock.version}</version></dependency><dependency><groupId>ws.ament.hammock</groupId><artifactId>swagger</artifactId><version>${hammock.version}</version></dependency>
</dependencies>

事不宜迟,让我们立即构建和运行应用程序(如果您好奇应用程序正在使用什么关系数据存储,则它是H2 ,并且数据库已在内存中配置)。

> mvn clean package
> java -jar target/eclipse-microprofile-hammock-0.0.1-SNAPSHOT-capsule.jar

确保我们的人员管理RESTful Web API完全正常运行的最佳方法是向其发送几个请求:

>  curl -X POST http://localhost:10900/api/people -H "Content-Type: application\json" \-d '{"email": "a@b.com", "firstName": "John", "lastName": "Smith"}'HTTP/1.1 201 Created
Location: http://localhost:10900/api/people/a@b.com
Content-Type: application/json{"firstName":"John",""lastName":"Smith","email":"a@b.com"
}

如何确保Bean验证正常工作呢? 要触发该请求,让我们发送部分准备好的请求。

>  curl  --X POST http://localhost:10900/api/people -H "Content-Type: application\json" \-d '{"firstName": "John", "lastName": "Smith"}'HTTP/1.1 400 Bad Request
Content-Length: 0

还可以在http:// localhost:10900 / index.html?url = http:// localhost:10900 / api / openapi.json上获得OpenAPI规范和预捆绑的Swagger UI分发。

Java应用

到目前为止,到目前为止还算不错,但实际上我们还没有谈论过测试应用程序。 假设要增加一个人,要进行集成测试有多难? 事实证明,围绕测试Java EE应用程序的框架有了很大的改进。 特别是,使用Arquillian测试框架(以及最受欢迎的JUnit和REST Assured )非常容易完成。 一个真实的例子值得一千个单词。

@RunWith(Arquillian.class)
@EnableRandomWebServerPort
public class PeopleApiTest {@ArquillianResource private URI uri;@Deploymentpublic static JavaArchive createArchive() {return ShrinkWrap.create(JavaArchive.class).addClasses(PeopleResource.class, PeopleApplication.class).addClasses(PeopleServiceImpl.class, PeopleJpaRepository.class, PersistenceConfig.class).addPackages(true, "org.apache.deltaspike");}@Testpublic void shouldAddNewPerson() throws Exception {final Person person = new Person("a@b.com", "John", "Smith");given().contentType(ContentType.JSON).body(person).post(uri + "/api/people").then().assertThat().statusCode(201).body("email", equalTo("a@b.com")).body("firstName", equalTo("John")).body("lastName", equalTo("Smith"));}
}

太神奇了,不是吗? 它实际上是一个很大的乐趣,以发展现代的Java EE应用程序,可能有人会说了, 春节的方式! 实际上,与Spring的相似之处并非偶然,因为它令人鼓舞,正在鼓舞,而且无疑将继续激发Java EE生态系统中的许多创新。

未来如何? 我认为,对于Jakarta EE和Eclipse Microprofile来说 , 绝对是光明的。 后者刚刚推出了2.0版 ,其中包含大量新规范,旨在满足微服务架构的需求。 见证这些转变的发生真是太棒了。

该项目的完整资源可在Github上找到 。

翻译自: https://www.javacodegeeks.com/2018/11/building-java-applications-spring-way.html

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

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

相关文章

【渝粤题库】陕西师范大学180113 学前儿童艺术教育作业

一、简答题 1.简述学前儿童歌唱活动&#xff08;歌词方面&#xff09;如何选材&#xff1f; 2.简述罗恩菲尔德的儿童画发展阶段。 3.简述傣族民间舞的风格特点&#xff1f; 4.学前儿童美术教育的任务是什么&#xff1f; 5. 音乐的基本特征是什么&#xff1f; 6.柯思修泰纳划分的…

jq设置html的fontsize,Jquery 设置字体大小(font-size)与行高(line-height)

Jquery 设置字体大小(font-size)与行高(line-height)var cssfontSize$(".txt_container").css(font-size);var csslineHeight$(".txt_container").css(line-height);var unitcssfontSize.slice(-2);var fontSizeparseFloat(cssfontSize);var lineHeightpar…

【渝粤题库】陕西师范大学200431综合英语(一)作业(高起专、高起本)

《综合英语&#xff08;一&#xff09;》作业 I. Multiple Choice. Choose the appropriate explanation of the underlined words. Mr. Brown is the principal of a British school. A. main B. headmaster C. lawThe doctor thought the patient was really bullheaded. A.…

【渝粤题库】陕西师范大学201001 教育管理学(高起本)作业

《教育管理学》作业 一、单项选择题 1、管理的二重性是指( ) A&#xff0e;科学性与艺术性 B&#xff0e;开放性与封闭性 C&#xff0e;政治性与非政治性 D&#xff0e;规范性与灵活性 2、管理总是要经历一个过程&#xff0c;尽管不同管理情境中经历的过程不完全相同&#xff0…

计算机网络发展第二阶段 兴起于,计算机辅助开始于计算机发展第几阶段

计算机辅助开始于计算机发展第4阶段。其计算机辅助管理发展的四个阶段分别如下&#xff1a;1、单项数据处理阶段&#xff1a;这是计算机应用于管理的初级阶段&#xff0c;主要用于处理工资计算、统计报表、发放凭证等部分的事务工作&#xff0c;而原始数据的收集以及对输出结果…

【渝粤题库】陕西师范大学202011 微观经济学 作业 (专升本、高起本)

《微观经济学》作业 一、填空题&#xff1a; &#xff11;&#xff0e;实证经济学要回答的是 的问题&#xff0c;规范经济学要回答的是 的问题。 &#xff12;&#xff0e;需求变动引起均衡价格 变动&#xff0c;供给变动引起均衡价格 变动。 &#xff13;&#xff0e;边际收益…

jaxb 映射 空字段_推土机:将JAXB对象映射到业务/域对象

jaxb 映射 空字段Dozer是开放源代码&#xff08; Apache 2许可 &#xff09;“ Java Bean到Java Bean映射器&#xff0c;可将数据从一个对象递归复制到另一个对象”。 正如从其主页上的描述所描述的那样&#xff0c;它用于映射两个JavaBeans实例&#xff0c;以在实例之间进行自…

【渝粤题库】陕西师范大学202881 电子商务概论

《电子商务概论》作业 一、判断题 1、CPU中运算器的主要功能是完成对数据的算术运算、逻辑运算和逻辑判断等操作。&#xff08; &#xff09; 2、与传统的支付方式相比&#xff0c;电子支付具有方便、快捷、高效、经济、安全的优势。&#xff08; &#xff09; 3、在面向终端的…

常用计算机网络性能指标的是什么,什么是Bit?【计算机网络的性能指标】

比特(英语&#xff1a;Bit)&#xff0c;亦称二进制位&#xff0c;指二进制中的一位&#xff0c;是信息的最小单位。因此一个比特就是二进制数字中的一个 1 或 0Bit是Binary digit(二进制数字)的缩写&#xff0c;由数学家John Wilder Tukey提出(可能是1946年提出&#xff0c;但有…

使用AWS Lambda在Go中构建RESTful API

在本文中&#xff0c;我们将学习使用AWS Lambda在Go中设计&#xff0c;构建和部署RESTful API。 在开始之前&#xff0c;让我给您简要介绍一下AWS Lambda。 什么是AWS Lambda&#xff1f; AWS Lambda是一种无服务器计算服务&#xff0c;可运行我们的代码以响应事件并自动为我…

【渝粤题库】陕西师范大学210011幼儿园语言教育作业(高起专)

《幼儿园语言教育》作业 一、填空题 1、儿童语言的发展是指儿童对母语的理解和 能力随着时间的推移而发生变化的过程和现象。 2、儿童获得语言之前&#xff0c;用语音及伴随的表情或动作代替语言进行交往的现象被称为 。 3、 是指交际双方根据交际目的和语言情境有效地使用语言…

html的段落标志中 标注行中断,?HTML的段落标志中,标注行中断的是?

A:,B:,C: ,D:答案查看答案?HTML的段落标志中,标注行中断的是?解析【单选题】下列关于元素在网页中的叠放顺序描述&#xff0c;不正确的是&#xff1f;【单选题】HTML代码表示&#xff1f;【单选题】创建选项菜单应使用以下标记符&#xff1f;【单选题】在本窗口打开超链接的代…

【渝粤题库】陕西师范大学292301 国际金融学Ⅱ 作业(专升本)

《国际金融II》作业 一、判断 1、国际收支一般总是有差额的&#xff0c;当国际收入部分小于支出部分称为顺差&#xff0c;反之为逆差或赤字。 2、特别提款权在国际储备中所占的比重很大&#xff0c;约为40%。 3、在不同标价法下&#xff0c;买入价与卖出价的表示方法不同。在直…

【渝粤题库】陕西师范大学500010 量子力学 作业(专升本)

一、填空题 1、历史上第一个完全肯定光除了波动性之外还具有粒子性的科学家是 。按照光子假&#xff0c;频率为ν、波长为λ的电磁辐射其光子的能量E &#xff0c;动量P &#xff0e; 2、按照德布罗意假说&#xff0c;能量为E、动量为的自由粒子&#xff0c;其相应的物质波可表…

【渝粤题库】陕西师范大学800004 遥感概论

《遥感概论》作业 一&#xff0e; 填空题 &#xff11;&#xff0e;根据运载工具的类型&#xff0c;可分为 、 、 。    &#xff12;&#xff0e;固体自扫描目前常用的探测元件是 &#xff0c;它是一种用电荷量表示信号大小&#xff0c;用耦合方式传输信号的探测元件。 &…

undertow服务器分析_使用undertow构建和测试Websocket服务器

undertow服务器分析即将发布的JBoss Application Server版本将不再使用Tomcat作为集成的Web服务器&#xff0c;而是将其替换为undertow 。 undertow的体系结构基于可通过Builder API动态添加到服务器的处理程序。 这种方法类似于在Node.js中构造Web服务器的方式。 它使开发人员…

国家开放大学2021春1087数学分析专题研究题目

教育 教育 试卷代号&#xff1a;1087 2021年春季学期期末统一考试 数学分析专题研究 试题 2021年7月 一、单项选择题&#xff08;每小题4分&#xff0c;共20分&#xff09; 1.设映射f:A→B&#xff0c;g:B→C&#xff0c;且g。f:A→C是双射&#xff0c;则映射f一定是&#xf…

跳转指令微型计算机,哪种类型的汇编程序跳转指令最有用?

Ira Baxter..5(我已经为汇编程序编写了40多年;实际上在20世纪70年代早期设计并构建了一个生产多寄存器16位机器).真正有用的是CMP指令和指定该条件的JMP相对.我建议你让算术指令产生状态位零结果从结果出发结果的标志溢出(签名)我们称之为"条件位".你会发现它们都很有…

渝粤题库]西北工业大学组成与系统结构

一单选题 1.动态流水线是指( )。(2分) A.只有一种功能的流水线 B.同时只能完成一种功能的多功能流水线 C.功能不能改变的流水线 D .可同时执行多种功能的流水线 2.通道程序执行结束后引起的中断是(). (2分) A.程序性中断 B.外中断 C. I/O中断 D.机器校验中断 3.不属于堆栈型替…

重新开始Java的原始字符串文字讨论

在2018年12月宣布 将从JDK 12中删除原始字符串文字 。 现在&#xff0c;在新的一年中&#xff0c;与Java中原始字符串文字的设计有关的讨论又开始了。 在琥珀色专家OpenJDK邮件列表上的“ 原始字符串文字-重新开始讨论 ”一文中 &#xff0c;Brian Goetz参考了有关从JDK 12中删…