使用Maven构建微服务项目:从依赖管理到RESTEasy jar数据包下载指南

这些数据库的大小约为830kb。当然,这些直接的依赖性使用Maven一起建立项目也将带来一些及时的依赖性。

使用Maven构建微服务项目:从依赖管理到RESTEasy jar数据包下载指南

接下来,我将使用“ Maven方法”来构建此项目,例如,在SRC/Main/Java中,使用Maven Build命令等。如果您不想使用Maven,也可以下载Resteasy Jar直接从下载页[16]的数据包。下载时,请忽略Resteasy网站上的提示弹出:JBOSS只是试图指导您采用更多的“企业”方法。您只需要单击“继续下载”即可进行后续操作。

项目设计

以下微服务可用于以非常简单的方式演示一些基本概念。如下图所示,它包括5个级别。

在这里,水果应用是微服务的切入点。 Fruitservice提供主要路径(/水果),并且还充当路由器函数。苹果和水果都是模型。水果包含一些抽象功能,苹果将专门扩展其功能。

与您的想法一致,FruitComparator可以提供比较功能。不熟悉Java比较器的读者可以了解本文中对象的等效性和比较,在这里我将使用字符来替换它们。虽然水果孔板不是模型,但我更喜欢将比较器与要比较的对象类型相似。

模型

让我们从水果开始

package com.lyndseypadget.resteasy.model;
import javax.xml.bind.annotation.XmlElement;
public abstract class Fruit {
private String id;
private String variety;
@XmlElement
public String getId() {
   return id;
}
public void setId(String id) {
   this.id = id;
}
@XmlElement
public String getVariety() {
   return variety;
}
public void setVariety(String variety) {
   this.variety = variety;
}
}

然后,苹果在此级别上扩展了它:

package com.lyndseypadget.resteasy.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "apple")
public class Apple extends Fruit {
private String color;
@XmlElement
public String getColor() {
   return color;
}
public void setColor(String color) {
   this.color = color;
}
}

以上不是特别惊人的代码,您可能认为这是不值得炫耀的。这只是Java继承的一个简单示例。但关键是这两个注释@xmlelement和@xmlrootelement,它定义了XML Apple结构的外观:

<apple>
<id>1id>
<variety>Golden deliciousvariety>
<color>yellowcolor>
apple>

因为没有明显的构造函数的约定:Java使用隐式的无参数默认构造函数,因此正在发生更微妙的事情。该无参数构造函数对于对JAXB进行神奇效果非常必要(本文解释了这一点,并且在必要时,如何使其与XMLADAPTER一起使用)。

现在我们有了一个对象:定义的苹果。它具有三个属性:ID,多样性和颜色。

服务

Fruitservice用作与微服务相互作用的主要路径(/水果)。在这种情况下,我使用@Path注释直接在该层次结构中定义了第一个路径 /水果 /苹果。随着RESTFUL微服务的扩展,您可能需要在自己的层次结构中定义多个最终路径(例如 /苹果, /香蕉, /橙色)。

package com.lyndseypadget.resteasy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.lyndseypadget.resteasy.model.Apple;
import com.lyndseypadget.resteasy.model.FruitComparator;
@Path("/fruits")
public class FruitService {
private static Map apples = new TreeMap();
private static Comparator comparator = new FruitComparator();
@GET
@Path("/apples")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List getApples() {
   List retVal = new ArrayList(apples.values());
   Collections.sort(retVal, comparator);
   return retVal;
}
}

此Apple地图可帮助我们根据ID跟踪Apple的数据,从而模拟某些类型的数据持久性层。使用GetApples方法(常见的HTTP请求方法)返回地图跟踪的相关Apple数据。 GET /Apples路由由@Get和@path注释定义,可以在数据传输格式XML或JSON中生成内容。

此方法需要返回列表<Apple>对象,然后使用此比较器按多种属性对列表进行排序。

水果肉饼看起来像这样:

package com.lyndseypadget.resteasy.model;
import java.util.Comparator;
public class FruitComparator implements Comparator {
public int compare(F f1, F f2) {
   return f1.getVariety().compareTo(f2.getVariety());
}
}

请注意,如果我们想对Apple的特定属性(例如Color)进行分类,则必须创建一个新的比较器来替换它并提供一个名称,例如AppleComparator。

应用程序

在ResteAsy3.1.x中,您需要定义扩展应用程序的级别。 Resteasy示例文档表明这是单身注册表,如下所示:

package com.lyndseypadget.resteasy;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;
public class FruitApplication extends Application
{
  HashSet singletons = new HashSet();
  public FruitApplication()
 
{
singletons.add(new FruitService());
  }
  @Override
public Set getClasses()
{
 HashSet set = new HashSet();
 return set;
}
@Override
public Set getSingletons()
{
 return singletons;  
}
}

如果我们只想说明此示例,我们就不需要在此级别上做很多工作,但是我们需要在Web.xml文件中将其连接,这将在后面的“ Web Service Connection”中介绍。

对象构建集合

GET /Apples调用将返回以下数据:


<collection>
<apple>
   <id>1id>
   <variety>Golden deliciousvariety>
   <color>yellowcolor>
apple>
collection>

[
{
   "apple": {
       "id": 1,
       "variety": "Golden delicious",
       "color": "yellow"
   }
}
]

但是,我们可以更改数据以稍有不同:


<apples>
<apple>
   <id>1id>
   <variety>Golden deliciousvariety>
   <color>yellowcolor>
apple>
apples>

 {
"apples": {
   "apple": {
       "id": 1,
       "variety": "Golden delicious",
       "color": "yellow"
   }
}
}

第二个选项在XML中看起来更好,但对JSON的效果较小。如果您喜欢此结构​​,则可以使用自己的类型来包装列表<Apple>并修改FruitService.getApples方法以返回此类型:

package com.lyndseypadget.resteasy.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "apples")
public class Apples {
private static Comparator comparator = new FruitComparator();
@XmlElement(name = "apple", type = Apple.class)
private List apples;
public List getApples() {
   Collections.sort(apples, comparator);
   return apples;
}
public void setApples(Collection apples) {
   this.apples = new ArrayList(apples);
}
}

这些评论有效地“备注”了根元素,即收集/列表。通过阅读Javax.xml.bind.annotation的Javadoc文档,您可以尝试使用不同的XML模式映射进行注释。

当然,如果您真的无法通过一般方法签名,则可以编码和编写不同的方法 - 一种用于XML,另一个用于JSON。

一些Web服务连接

从将服务部署到tomcat开始,我使用位于src/main/webapp/web inf/web.xml中的Web应用程序部署描述符文件。它包含以下内容:


   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>resteasydisplay-name>
<context-param>
   <param-name>javax.ws.rs.core.Applicationparam-name>
   <param-value>com.lyndseypadget.resteasy.FruitApplicationparam-value>
context-param>
<context-param>
   <param-name>resteasy.servlet.mapping.prefixparam-name>
   <param-value>/v1param-value>
context-param>
<listener>
   <listener-class>
       org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
   listener-class>
listener>
<servlet>
   <servlet-name>Resteasyservlet-name>
   <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcherservlet-class>
servlet>
<servlet-mapping>
   <servlet-name>Resteasyservlet-name>
   <url-pattern>/v1/*url-pattern>
servlet-mapping>
web-app>

是的,“ servlet-name”是指servlet的名称(即服务)是恢复的。 Servlet映射URL-Pattern(/V1/*)要求Tomcat服务器将包含此模式的传入请求传输到Resteasy Service。有关如何创建此文件以及可用的不同选项的更多信息,请参见Tomcat的应用程序部署文档[17]。

建筑和部署

从项目的根目录中,您可以运行以下内容来构建战争(Web应用程序资源)文件:

mvn clean install

这将在目标文件夹中创建一个新文件夹,其中包含战争文件。虽然可以使用Maven或其他工具部署文件,但我只使用一个简单的复制命令。应当指出的是,每次您将战争重新启动到Tomcat服务器时,您都应首先暂停服务器并删除服务应用程序文件夹(在这种情况下,此文件夹:<TomCatDirectory>/webapps/resteasy)和旧一个战争文件(<tomcatdirectory>/webapps/resteasy.war)。

[sudo] cp target/resteasy.war /webapps/resteasy.war

如果此时的Tomcat服务器正在运行,则将立即部署Web服务。如果没有,则在服务器下次启动时,该服务将自动部署。然后,您可以通过以下地址访问Web服务:<tomcathost>:<tomcatport>/resteasy/v1/v1/fruits/apples。在我的示例中,此地址为:8080/reteasy/v1/fruits/苹果。

通过“内容谈判”

((内容谈判)”测试服务

内容谈判是一种提供不同资源(URI)表达的机制。最基本的是它的含义:

有关内容谈判和标题的更多信息,请参见RFC 2616的第12和14章[18]。在这种情况下,您真正​​需要知道的是:

如果您尝试将http调用到有效的端点,但是无法协商内容,则意味着没有@produces与接受数据匹配,或者@consumes no @consumes与内容型数据匹配,HTTP状态代码415:无支持的数据将返回转移格式。

获取返回通用数据传输格式的呼叫实际上可以直接进入浏览器。对于诸如get /apples之类的电话,默认情况下将获得XML:

但是,使用Postman [19]之类的工具可能会更有帮助,因为它明确指定了接受标头为应用程序/XML:

两种方法都返回一些有效但不是很有意义的XML,即一个空的Apple列表。但是这里有一些很酷的东西。将Accept标头更改为应用程序/JSON,Great,VOILA! JSON*有效*:

不只是“阅读”

您可能会发现,仅读取Restful Web服务的许多示例,其中一些示例将没有其他提示,例如如何创建,更新和删除这些操作。尽管我们已经有一个用于Web服务的框架,但这是一个无法更改的空列表,这没什么意义。因此,我们应该使用其他一些方法将Apple添加到此列表中或将其从列表中删除。

package com.lyndseypadget.resteasy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.lyndseypadget.resteasy.model.Apple;
import com.lyndseypadget.resteasy.model.FruitComparator;
@Path("/fruits")
public class FruitService {
private static Comparator comparator = new FruitComparator();
private static Map apples = new TreeMap();
private static int appleCount = 0;
@GET
@Path("/apples")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List getApples() {
   List retVal = new ArrayList(apples.values());
   Collections.sort(retVal, comparator);
   return retVal;
}
@GET
@Path("/apples/{id}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getApple(@PathParam("id") String id) {
   Apple found = apples.get(id);
   if(found == null) {
       return Response.status(404).build();
   }
   return Response.ok(found).build();
}
@DELETE
@Path("/apples/{id}")
public Response deleteApple(@PathParam("id") String id) {
   apples.remove(id);
   return Response.status(200).build();
}
@POST
@Path("/apples")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response createApple(Apple apple) {
   String newId = Integer.toString(++appleCount);
   apple.setId(newId);
   apples.put(newId, apple);
   return Response.status(201).header("Location", newId).build();
}
}

这样,已经添加了一些新功能:

这些方法完善了许多功能,以确保服务能够按预期工作。对Apple的更新(使用@put和/或@Patch),以及终点,逻辑和管理持久性的更多功能操作,读者进行练习。

当我们再次构建和部署时,我们会发现(如果使用Maven或Tomcat进行设置,请参见上面的“构建和部署”),我们现在可以在服务中创建,检索和删除Apple。即使您不在服务器上进行任何重新配置​​,也可以在XML和JSON之间进行选择性调用。

用“应用程序/JSON”内容类型和JSON主体创建一个Apple,如下图所示:

这是另一个示例:使用“应用程序/XML”内容类型和XML主体创建一个Apple。

在XML中搜索所有Apple数据:

从JSON中的ID检索Apple 2的数据:

按ID删除Apple 1的数据:

在JSON中搜索Apple的所有数据:

概括

在这里,我们探索了Resteasy Architecture如何无缝支持Java Web服务中的XML和JSON数据传输格式。我还解释了REST,媒体类型(数据传输格式),Web服务和微服务之间的技术差异,因为这些术语中有许多令人困惑的灰色区域。

我在这里列出的示例可能有点不情愿。在我的生活中,我从不真正需要与水果相关的数据,而且我从未在食品行业工作。我以水果为例的原因是因为我认为这种“规模”可以帮助每个人都了解微服务的概念。您还可以想象其他微服务(例如蔬菜,罐头食品或海鲜)如何形成食品分配系统。在现实世界中,杂货店的食品分配系统实际上非常复杂,它必须考虑到包括销售,优惠券,过期日期,营养信息等问题。

当然,您可以选择其他方法来细分系统,但是当您需要快速,高效,轻巧的工具来支持多种数据格式时,Resteasy确实是一个不错的选择。

原始链接:

参考地址:

[1],[2],[6]

[3]

[4]

[5]

[7]

[8]

[9]

[10]

[11]

[12]

[13]

[14]

[15]

[16]

[17]

[18]

[19]

关于作者:Lyndsey是密苏里州堪萨斯城的著名软件工程师和演讲者。尽管她过去一直活跃于Java领域,但她目前一直专注于Node JS+ES6的工作。她已经在一些大型企业和初创公司工作了很长时间,并且在软件和网络开发方面积累了十多年的丰富实用经验,并且擅长设计可维护和直观的恢复API网络接口。她的演讲和博客都是关于微服务,git概念和工作流以及各种软件技能的。 Lyndsey积极参与相关的地方组织,并鼓励各个年龄段的妇女积极探索数学和科学领域的职业问题。有关她的更多信息,请访问lyndseypadget.com。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读