热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javalicense实现_用Spring构建企业Java应用程序

来源:SpringForAll社区通过在本教程中构建一个简单的RESTfulwebAPI,了解关于使用JavaEE和Spring框架构建企业Java应用

374075a53530c68abfc59a6550b3f910.png

来源:SpringForAll社区

通过在本教程中构建一个简单的RESTful web API,了解关于使用Java EE和Spring框架构建企业Java应用程序的更多信息。

我认为可以说Java EE在Java开发人员中获得了相当坏的名声。尽管多年来,它确实在各个方面都有所改善,甚至从Eclipse Foundation变成了JakartaEE,但它的苦味仍然相当强烈。另一方面,我们有Spring Framework(或者更好地反映现实,一个成熟的Spring Platform),这是一个出色的、轻量级的、快速的、创新的、高生产力的Java EE替代品。那么,为什么要为Java EE费心呢?我们将通过展示使用大多数Java EE规范构建现代Java应用程序是多么容易来回答这个问题。在这方面取得成功的关键因素是Eclipse Microprofile:J2EE的微服务时代。我们将要构建的应用程序是用于管理人员的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;

   @Version

   private 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 findByEmail(String email) {

       final CriteriaBuilder cb = em.getCriteriaBuilder();

       final CriteriaQuery query = cb.createQuery(PersonEntity.class);

       final Root 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

   @Transactional

   public 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 findAll() {

       final CriteriaBuilder cb = em.getCriteriaBuilder();

       final CriteriaQuery query = cb.createQuery(PersonEntity.class);

       query.from(PersonEntity.class);

       return em.createQuery(query).getResultList();

   }

   @Override

   @Transactional

   public Optional deleteByEmail(String email) {

       return findByEmail(email)

           .map(entity -> {

               em.remove(entity);

               return entity;

           });

   }

}

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

@ApplicationScoped

public class PersistenceConfig {

   @PersistenceUnit(unitName = "peopledb")

   private EntityManagerFactory entityManagerFactory;

   @Produces @PeopleDb @TransactionScoped

   public EntityManager create() {

       return this.entityManagerFactory.createEntityManager();

   }

   public void dispose(@Disposes @PeopleDb EntityManager entityManager) {

       if (entityManager.isOpen()) {

           entityManager.close();

       }

   }

}

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

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;

   @Override

   public Optional findByEmail(String email) {

       return repository

           .findByEmail(email)

           .map(this::toPerson);

   }

   @Override

   public Person add(Person person) {

       return toPerson(repository.saveOrUpdate(person.getEmail(), person.getFirstName(), person.getLastName()));

   }

   @Override

   public Collection getAll() {

       return repository

           .findAll()

           .stream()

           .map(this::toPerson)

           .collect(Collectors.toList());

   }

   @Override

   public Optional 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 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 Mavenpom.xml文件。

   1.8.1

   2.1

       org.apache.deltaspike.modules

       deltaspike-jpa-module-api

       ${deltaspike.version}

       compile

       org.apache.deltaspike.modules

       deltaspike-jpa-module-impl

       ${deltaspike.version}

       runtime

       ws.ament.hammock

       dist-microprofile

       ${hammock.version}

       ws.ament.hammock

       jpa-openjpa

       ${hammock.version}

       ws.ament.hammock

       util-beanvalidation

       ${hammock.version}

       ws.ament.hammock

       util-flyway

       ${hammock.version}

       ws.ament.hammock

       swagger

       ${hammock.version}

在没有进一步的ado的情况下,让我们立即构建和运行应用程序(如果您想知道应用程序使用的是什么关系数据存储,那么它是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: applicationjson"

    -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 Validation 工作正常?为了触发它,让我们发送部分准备好的请求。

>  curl  --X POST http://localhost:10900/api/people -H "Content-Type: applicationjson"

    -d '{"firstName": "John", "lastName": "Smith"}'

HTTP/1.1 400 Bad Request

Content-Length: 0

OpenAPI规范和预捆绑的Swagger UI发行版也可以通过http://localhost:10900/index.html?url=http://localhost:10900/api/openapi.json获得。到目前为止,一切都很好,但公平地说,我们根本没有谈到测试我们的应用程序。要为添加一个person的场景设计出集成测试有多难呢?事实证明,围绕Java EE应用程序测试的框架已经有了很大的改进。特别是,使用Arquillian测试框架(以及受欢迎的JUnit和REST Assured)非常容易完成。一个真实的例子抵得上千言万语。

@RunWith(Arquillian.class)

@EnableRandomWebServerPort

public class PeopleApiTest {

   @ArquillianResource private URI uri;

   @Deployment

   public 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");

   }

   @Test

   public 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的方式!事实上,与Spring的相似之处并非巧合,因为它很有启发性,很有启发性,而且无疑将继续激励Java EE生态系统中的创新。未来如何?我认为,无论对于雅加达EE还是Eclipse Microprofile来说,都是光明的。后者刚刚接近2.0版本,提供了大量新的规范,这些规范旨在满足微服务体系结构的需求。目睹这些转变真是太棒了。项目的完整源代码可以在GitHub上找到。

原文链接:https://dzone.com/articles/building-enterprise-java-applications-the-spring-w

作者:Andriy Redko

译者:xieed

·END·

 近期热文:

  • 深入聊一聊 Spring AOP 实现机制

  • Spring Cloud Stream 学习小清单

  • 在一台Mac上不同平台同时使用多个Git账号

  • Git 版本控制之 GitFlow

  • 彻底搞懂 Git-Rebase

  • 我说分布式事务之最大努力通知型事务

  • 我说分布式事务之TCC

  • 不可错过的CMS学习笔记

  • 在生产中使用Java 11:需要了解的重要事项

  • 可能是最全面的G1学习笔记

2dcd0cae73041832c483d193454d66d5.png

看完,赶紧点个“好看”鸭

点鸭点鸭

↓↓↓↓




推荐阅读
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 开发笔记:spring boot项目打成war包部署到服务器的步骤与注意事项
    本文介绍了将spring boot项目打成war包并部署到服务器的步骤与注意事项。通过本文的学习,读者可以了解到如何将spring boot项目打包成war包,并成功地部署到服务器上。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
author-avatar
_LiNanaP
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有