idea 构建spring_以Spring方式构建企业Java应用程序
idea 構建spring
我認為可以說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
idea 構建spring
總結
以上是生活随笔為你收集整理的idea 构建spring_以Spring方式构建企业Java应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 参加中视频伙伴计划,这四个地方才是正确发
- 下一篇: 自动化测试特定区域滑动_自动化用户特定实