我认为可以肯定地说, 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 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

以Spring方式构建企业Java应用程序相关推荐

  1. idea 构建spring_以Spring方式构建企业Java应用程序

    idea 构建spring 我认为可以说Java EE在Java开发人员中享有很高的声誉. 尽管多年来确实在各个方面都有所改善,甚至将其改名为Eclipse Foundation成为Jakarta E ...

  2. 用Spring构建企业Java应用程序

    来源:SpringForAll社区 通过在本教程中构建一个简单的RESTful web API,了解关于使用Java EE和Spring框架构建企业Java应用程序的更多信息. 我认为可以说Java ...

  3. 1.Spring Cloud 构建微服务应用程序之概览

    1.Spring Cloud 构建微服务应用程序之概览 1.1 微服务发展史 1.2 为什么要学习微服务应用开发? 1.3 微服务和分布式之间的关系 1.4 微服务架构下构建分布式系统带来了哪些问题? ...

  4. actuator的原理_使用Spring Boot Actuator监视Java应用程序

    actuator的原理 朋友不允许朋友写用户身份验证. 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK. 数分钟之内即可在任何应用程序中对用户进行身份验证,管理和保护. 您是否曾与 ...

  5. 使用Spring Boot Actuator监视Java应用程序

    朋友不允许朋友写用户身份验证. 厌倦了管理自己的用户? 立即尝试Okta的API和Java SDK. 在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护. 您是否曾与Spring Boot ...

  6. 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序

    "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证. 开发人员 ...

  7. JAVA共有几种窗体布局方式_在Java GUI程序开发中常见的三种布局管理器是什么

    答:FlowLayout 流式布局,从左到右,如果到边界就换行再从左到右. BorderLayout 边界布局(默认布局方式),按东西南北中五个方向来布局,默认是中.后设置在同样位置的控件会覆盖之前的 ...

  8. 在独立Java应用程序中使用Tomcat JDBC连接池

    这是从我们的客人文章W4G伙伴克拉伦斯豪的作者临春3从A按. 您可能会在文章结尾找到本书的折扣券代码,仅适用于Java Code Geeks的读者! 请享用! 在需要数据访问权限的独立Java应用程序 ...

  9. 构建服务器集群感知的 Java 应用程序

    Mukul Gupta, 高级技术架构师, DGI Paresh Paladiya, 高级技术架构师, CGI 简介: 服务器集群对于高度可扩展的 Java 企业级应用程序开发已司空见惯,但是应用程序 ...

最新文章

  1. 跟我学Spring Cloud(Finchley版)-16-Zuul
  2. lua用于ios开发
  3. 使用SMARTFORM字段参数设置解决SMARTFORM中数量、金额字段显示问题
  4. 2018湖湘杯web、misc记录
  5. 阿里云服务器如何创建快照备份数据
  6. ssh,scp带密码操作
  7. MATLAB 图形着色
  8. 《飞鸽传书2007绿色版下载》总结报告
  9. python中pass语句的作用是_Python pass语句以及作用详解
  10. PHP验证码(画图)无法正常显示问题
  11. [AST实战]从零开始写一个wepy转VUE的工具
  12. 专栏全年主题合辑-代码中文命名相关实践 2018-11-10
  13. linux qt 多点触摸,Qt 4.6 添加 Multi-touch(多点触摸)支持
  14. 英语计算机四级如何查询,四级成绩查询
  15. Adams隐式4阶方法解常微分方程,fortran实现
  16. 爬虫三(Bs4搜索、Selenium基本使用、无界面浏览器、Selenium自动登录百度案例、自动获取12306登录验证码案例、切换选项卡、浏览器前进后退、登录Cnblogs获取Cookie自动点赞)
  17. 瑞萨 smart Configurator
  18. Java并发编程的艺术-Java并发编程基础
  19. C++ 关键字 typeid, typename
  20. 浙大版《C语言程序设计》第四版(何钦铭颜晖) 第11章 指针进阶 课后习题答案

热门文章

  1. 【dfs】益智游戏(2017 特长生 T2)
  2. hihocoder1147 时空阵(bfs树+DP)
  3. 依存句法分析的任务以及形式化定义
  4. 阿里巴巴制定了这 16 条
  5. Java中几种常量池的区分
  6. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
  7. 01)自学JavaScript
  8. JS中数组的常用方法
  9. 2017蓝桥杯省赛---java---B---3(承压计算)
  10. intellij-IDE运行Java程序报错:java: -source 1.5 中不支持 lambda 表达式 有用