现在,是时候构建我们的 RESTful Web 服务实现了,如下所示:
- Delete the default implementation class, HelloWorldEndpoint.java, created by the Thorntail generator.
- Define a new package, named service (the fully qualified name will be com.packtpub.thorntail.footballplayermicroservice.rest.service), where we will put the RESTful web service implementation.
- Finally, let's build the API implementations by using the CDI specifications (in order to inject the entity manager used to manage database connections) and the JAX-RS (in order to implement the RESTful operations). We will create an AbstractFacade class that defines the standard CRUD of our microservice:
package com.packtpub.thorntail.footballplayermicroservice.rest.service;
import java.util.List;
import javax.persistence.EntityManager;
/**
* Abstract facade used to define the CRUD APIs of our micro service.
*
* @author Mauro Vocale
* @param <T> The type class of our entity domain.
* @version 1.0.0 17/08/2018
*/
public abstract class AbstractFacade<T> {
private final Class<T> entityClass;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery<T> cq =
getEntityManager().getCriteriaBuilder().createQuery(entityClass);
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
}
- Finally, the real implementation is as follows:
package com.packtpub.thorntail.footballplayermicroservice.rest.service;
import com.packtpub.thorntail.footballplayermicroservice.model.FootballPlayer;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Class that exposes the APIs implementations of our CRUD micro service.
*
* @author Mauro Vocale
* @version 1.0.0 17/08/2018
*/
@ApplicationScoped
@Path("/footballplayer")
public class FootballPlayerFacadeREST extends AbstractFacade<FootballPlayer> {
@PersistenceContext(unitName = "FootballPlayerPU")
private EntityManager em;
public FootballPlayerFacadeREST() {
super(FootballPlayer.class);
}
@POST
@Override
@Consumes({MediaType.APPLICATION_JSON})
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void create(FootballPlayer entity) {
super.create(entity);
}
@PUT
@Path("{id}")
@Consumes({MediaType.APPLICATION_JSON})
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void edit(@PathParam("id") Integer id, FootballPlayer entity) {
super.edit(entity);
}
@DELETE
@Path("{id}")
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void remove(@PathParam("id") Integer id) {
super.remove(super.find(id));
}
@GET
@Path("{id}")
@Produces({MediaType.APPLICATION_JSON})
public FootballPlayer find(@PathParam("id") Integer id) {
return super.find(id);
}
@GET
@Override
@Produces({MediaType.APPLICATION_JSON})
public List<FootballPlayer> findAll() {
return super.findAll();
}
@Override
protected EntityManager getEntityManager() {
return em;
}
}
- Now, we will be able to create our Uber JAR, with the following command:
$ mvn clean package
- Launch our microservice application by using the following command:
$ java -jar target/football-player-microservice-thorntail.jar
让我们检查应用程序是否已部署以及 Thorntail 是否已启动并运行,如下所示:
2018-07-17 16:41:31,640 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 12) WFLYUT0021: Registered web context: '/' for server 'default-server'
2018-07-17 16:41:31,674 INFO [org.jboss.as.server] (main) WFLYSRV0010: Deployed "football-player-microservice.war" (runtime-name : "football-player-microservice.war")
2018-07-17 16:41:31,680 INFO [org.wildfly.swarm] (main) WFSWARM99999: Thorntail is Ready
- Now, invoke the API that retrieves the list of football players, as follows:
$ curl http://localhost:8080/footballplayer | json_pp
输出应该类似于以下内容(为方便起见,这里只截取了一部分):
[
{
"id":1,
"name":"Gianluigi",
"surname":"Buffon",
"age":40,
"team":"Paris Saint Germain",
"position":"goalkeeper",
"price":2
},
{
"id":2,
"name":"Manuel",
"surname":"Neuer",
"age":32,
"team":"Bayern Munchen",
"position":"goalkeeper",
"price":35
},
{
"id":3,
"name":"Keylor",
"surname":"Navas",
"age":31,
"team":"Real Madrid",
"position":"goalkeeper",
"price":18
},
...
]
- Finally, we will create the JUnit test, in order to ensure that our APIs are working properly. Let's add the Maven dependencies, as follows:
<properties>
...
<version.resteasy>3.0.19.Final</version.resteasy>
</properties>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>arquillian</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${version.resteasy}</version>
<scope>test</scope>
</dependency>
- Then, we will create the test class, named FootballPlayerFacadeRESTTest, in the package com.packtpub.thorntail.footballplayermicroservice.rest.service, under the src/main/test directory:
package com.packtpub.thorntail.footballplayermicroservice.rest.service;
import com.packtpub.thorntail.footballplayermicroservice.model.FootballPlayer;
import com.packtpub.thorntail.footballplayermicroservice.rest.RestApplication;
...
/**
* Unit Test class needed to test the APIs.
*
* @author Mauro Vocale
* @version 1.0.0 18/07/2018
*/
@RunWith(Arquillian.class)
public class FootballPlayerFacadeRESTTest {
private static final String API_URL = "http://localhost:8080/footballplayer";
/**
*
* @return @throws Exception
*/
@Deployment
public static Archive createDeployment() throws Exception {
JAXRSArchive deployment = ShrinkWrap.create(JAXRSArchive.class);
deployment.addPackage(FootballPlayer.class.getPackage());
deployment.addPackage(AbstractFacade.class.getPackage());
deployment.addPackage(RestApplication.class.getPackage());
deployment.addAsWebInfResource(new ClassLoaderAsset(
"META-INF/create.sql", FootballPlayerFacadeREST.class.
getClassLoader()),"classes/META-INF/create.sql");
deployment.addAsWebInfResource(new ClassLoaderAsset(
"META-INF/load.sql", FootballPlayerFacadeREST.class.getClassLoader()),
"classes/META-INF/load.sql");
deployment.addAsWebInfResource(new ClassLoaderAsset(
"META-INF/persistence.xml", FootballPlayerFacadeREST.class.
getClassLoader()), "classes/META-INF/persistence.xml");
deployment.addAsWebInfResource(new ClassLoaderAsset(
"project-defaults.yml", FootballPlayerFacadeREST.class.
getClassLoader()), "classes/project-defaults.yml");
deployment.addAllDependencies();
System.out.println(deployment.toString(true));
return deployment;
}
private final Client client = ClientBuilder.newBuilder().build();
private WebTarget target;
...
@Before
public void setUp() {
target = client.target(API_URL);
}
/**
* Test of create method, of class FootballPlayerFacadeREST.
*/
@Test
@InSequence(2)
public void testCreate() {
System.out.println("create");
FootballPlayer player = new FootballPlayer("Mauro", "Vocale", 38,
"Juventus", "central midfielder", new BigInteger("100"));
Response response = target.request().post(Entity.entity(player,
MediaType.APPLICATION_JSON_TYPE));
assertThat(response.getStatus(), is(Response.Status.NO_CONTENT.
getStatusCode()));
}
...
}
一些著名的球员失踪了吗?在本章的最后,我们将构建一个图形用户界面,帮助您插入您喜欢的用户界面。