走向REST:在Spring和JAX-RS(Apache CXF)中嵌入Jetty

对于服务器核心Java开发人员而言,向世界“展示”的唯一方法是使用API​​。 今天的帖子都是关于JAX-RS的 :使用Java编写和公开RESTful服务。

但是,我们不会使用涉及应用程序服务器,WAR打包以及诸如此类的传统的重量级方法来做到这一点。 相反,我们将使用很棒的Apache CXF框架,并且一如既往地依靠Spring将所有组件连接在一起。 当然,我们也不会停止,因为我们需要一个Web服务器来运行我们的服务。 使用胖子或一个罐子的概念,我们将Jetty服务器嵌入到我们的应用程序中,并使最终的JAR可重新分发(包括所有依赖项)并且可运行。

这是很多工作,所以让我们开始吧。 如前所述,我们将使用Apache CXF , Spring和Jetty作为构建块,因此让我们在POM文件中对其进行描述。 值得一提的另一个依赖项是出色的用于JSON处理的Jackson库。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelversion>4.0.0</modelversion><groupid>com.example</groupid><artifactid>spring-one-jar</artifactid><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><properties><project.build.sourceencoding>UTF-8</project.build.sourceencoding><org.apache.cxf.version>2.7.2</org.apache.cxf.version><org.springframework.version>3.2.0.RELEASE</org.springframework.version><org.eclipse.jetty.version>8.1.8.v20121106</org.eclipse.jetty.version></properties><dependencies>   <dependency><groupid>org.apache.cxf</groupid><artifactid>cxf-rt-frontend-jaxrs</artifactid><version>${org.apache.cxf.version}</version></dependency><dependency><groupid>javax.inject</groupid><artifactid>javax.inject</artifactid><version>1</version></dependency><dependency><groupid>org.codehaus.jackson</groupid><artifactid>jackson-jaxrs</artifactid><version>1.9.11</version></dependency><dependency><groupid>org.codehaus.jackson</groupid><artifactid>jackson-mapper-asl</artifactid><version>1.9.11</version></dependency><dependency><groupid>cglib</groupid><artifactid>cglib-nodep</artifactid><version>2.2</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-core</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-context</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-web</artifactid><version>${org.springframework.version}</version></dependency><dependency><groupid>org.eclipse.jetty</groupid><artifactid>jetty-server</artifactid><version>${org.eclipse.jetty.version}</version></dependency><dependency><groupid>org.eclipse.jetty</groupid><artifactid>jetty-webapp</artifactid><version>${org.eclipse.jetty.version</version></dependency>  </dependencies><build><plugins><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-compiler-plugin</artifactid><version>3.0</version><configuration><source>1.6</source><target>1.6</target></configuration></plugin>  <plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-jar-plugin</artifactid><configuration><archive><manifest><mainclass>com.example.Starter</mainclass></manifest></archive></configuration></plugin><plugin><groupid>org.dstovall</groupid><artifactid>onejar-maven-plugin</artifactid><version>1.4.4</version><executions><execution><configuration><onejarversion>0.97</onejarversion><classifier>onejar</classifier></configuration><goals><goal>one-jar</goal></goals></execution></executions></plugin></plugins></build><pluginrepositories><pluginrepository><id>onejar-maven-plugin.googlecode.com</id><url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url></pluginrepository></pluginrepositories><repositories><repository><id>maven2-repository.dev.java.net</id><url>http://download.java.net/maven/2/</url></repository></repositories>
</project>

它有很多东西,但是应该很清楚。 现在,我们准备从简单的JAX-RS应用程序开始开发第一个JAX-RS服务。

package com.example.rs;import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;@ApplicationPath( 'api' )
public class JaxRsApiApplication extends Application {
}

看起来很简单,我们的应用程序将/ api定义为JAX-RS服务的入口路径。 样本服务将管理由Person类代表的人员

package com.example.model;public class Person {private String email;private String firstName;private String lastName;public Person() {}public Person( final String email ) {this.email = email;}public String getEmail() {return email;}public void setEmail( final String email ) {this.email = email;}public String getFirstName() {return firstName;}public String getLastName() {return lastName;}public void setFirstName( final String firstName ) {this.firstName = firstName;}public void setLastName( final String lastName ) {this.lastName = lastName;} 
}

并遵循基本的业务服务(为简单起见,不包括数据库或任何其他存储)。

package com.example.services;import java.util.ArrayList;
import java.util.Collection;import org.springframework.stereotype.Service;import com.example.model.Person;@Service
public class PeopleService {public Collection< Person > getPeople( int page, int pageSize ) {Collection< Person > persons = new ArrayList< Person >( pageSize );for( int index = 0; index < pageSize; ++index ) {persons.add( new Person( String.format( 'person+%d@at.com', ( pageSize * ( page - 1 ) + index + 1 ) ) ) );}return persons;}public Person addPerson( String email ) {return new Person( email );}
}

如您所见,我们将根据请求的页面动态生成人员列表。 标准Spring注释@Service将此类标记为服务bean。 我们的JAX-RS服务PeopleRestService将使用它来检索人员,如以下代码所示。

package com.example.rs;import java.util.Collection;import javax.inject.Inject;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;import com.example.model.Person;
import com.example.services.PeopleService;@Path( '/people' ) 
public class PeopleRestService {@Inject private PeopleService peopleService;@Produces( { 'application/json' } )@GETpublic Collection< Person > getPeople( @QueryParam( 'page') @DefaultValue( '1' ) final int page ) {return peopleService.getPeople( page, 5 );}@Produces( { 'application/json' } )@PUTpublic Person addPerson( @FormParam( 'email' ) final String email ) {return peopleService.addPerson( email );}
}

尽管很简单,但该类需要更多说明。 首先,我们要向/ people端点公开我们的RESTful服务。 将其与/ api (我们的JAX-RS应用程序所在的位置)组合,则以/ api / people作为限定路径给出。

现在,只要有人向该路径发出HTTP GET ,就应该调用方法getPeople 。 此方法接受可选的参数页面 (默认值为1),并以JSON形式返回人员列表。 反过来,如果有人向同一路径发出HTTP PUT ,则应调用addPerson方法(使用必需的参数email ),并以JSON形式返回new person。

现在,让我们看一下应用程序的核心Spring配置。

package com.example.config;import java.util.Arrays;import javax.ws.rs.ext.RuntimeDelegate;import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import com.example.rs.JaxRsApiApplication;
import com.example.rs.PeopleRestService;
import com.example.services.PeopleService;@Configuration
public class AppConfig { @Bean( destroyMethod = 'shutdown' )public SpringBus cxf() {return new SpringBus();}@Beanpublic Server jaxRsServer() {JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );factory.setServiceBeans( Arrays.< Object >asList( peopleRestService() ) );factory.setAddress( '/' + factory.getAddress() );factory.setProviders( Arrays.< Object >asList( jsonProvider() ) );return factory.create();}@Bean public JaxRsApiApplication jaxRsApiApplication() {return new JaxRsApiApplication();}@Bean public PeopleRestService peopleRestService() {return new PeopleRestService();}@Bean public PeopleService peopleService() {return new PeopleService();}@Beanpublic JacksonJsonProvider jsonProvider() {return new JacksonJsonProvider();}
}

它看起来并不复杂,但是在后台却发生了很多事情。 让我们将其分解为香料。 这里的两个关键组件是工厂JAXRSServerFactoryBean ,它为配置我们的JAX-RS服务器实例提供了所有繁重的工作,而SpringBus实例则将 Spring和Apache CXF无缝地粘合在一起。 所有其他组件代表常规的Spring Bean。

图片上还没有嵌入Jetty Web服务器实例。 我们的主要应用程序类Starter正是这样做的。

package com.example;import org.apache.cxf.transport.servlet.CXFServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import com.example.config.AppConfig;public class Starter {public static void main( final String[] args ) throws Exception {Server server = new Server( 8080 );// Register and map the dispatcher servletfinal ServletHolder servletHolder = new ServletHolder( new CXFServlet() );final ServletContextHandler context = new ServletContextHandler();   context.setContextPath( '/' );context.addServlet( servletHolder, '/rest/*' );  context.addEventListener( new ContextLoaderListener() );context.setInitParameter( 'contextClass', AnnotationConfigWebApplicationContext.class.getName() );context.setInitParameter( 'contextConfigLocation', AppConfig.class.getName() );server.setHandler( context );server.start();server.join(); }
}

查看此代码后,我们发现我们正在端口8080上运行Jetty服务器实例,我们正在配置Apache CXF servlet来处理/ rest / *路径上的所有请求(连同我们的JAX-RS应用程序和服务一起为我们提供了/ rest / api / people ),我们使用上面定义的配置添加了参数化的Spring上下文侦听器,最后启动了服务器。 此时,我们拥有的是托管我们的JAX-RS服务的功能完善的Web服务器。 让我们来看看它的作用。 首先,让我们将其包装为单个,可运行和可再分配的脂肪或一个罐子 :

mvn clean package

让我们从目标文件夹中拾取位并运行它们:

java -jar target/spring-one-jar-0.0.1-SNAPSHOT.one-jar.jar

我们应该看到这样的输出:

2013-01-19 11:43:08.636:INFO:oejs.Server:jetty-8.1.8.v20121106
2013-01-19 11:43:08.698:INFO:/:Initializing Spring root WebApplicationContext
Jan 19, 2013 11:43:08 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Jan 19, 2013 11:43:08 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing Root WebApplicationContext: startup date [Sat Jan 19 11:43:08 EST 2013]; root of context hierarchy
Jan 19, 2013 11:43:08 AM org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider registerDefaultFilters
INFO: JSR-330 'javax.inject.Named' annotation found and supported for component scanning
Jan 19, 2013 11:43:08 AM org.springframework.web.context.support.AnnotationConfigWebApplicationContext loadBeanDefinitions
INFO: Successfully resolved class for [com.example.config.AppConfig]
Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Jan 19, 2013 11:43:09 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f8166e5: 
defining beans [org.springframework.context.annotation.internal
ConfigurationAnnotationProcessor,
org.springframework.context.annotation.internalAutowiredAnnotationProcessor,
org.springframework.context.annotation.internalRequiredAnnotationProces
sor,org.springframework.context.annotation.internalCommonAnnotationProcessor,appConfig,
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,c
xf,jaxRsServer,jaxRsApiApplication,peopleRestService,peopleService,jsonProvider]; root of factory hierarchy
Jan 19, 2013 11:43:10 AM org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be /api
Jan 19, 2013 11:43:10 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 2227 ms
2013-01-19 11:43:10.957:INFO:oejsh.ContextHandler:started o.e.j.s.ServletContextHandler{/,null}
2013-01-19 11:43:11.019:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080

让我们的服务器启动并运行,让我们向它发出一些HTTP请求,以确保一切都按预期运行:

> curl http://localhost:8080/rest/api/people?page=2
[{'email':'person+6@at.com','firstName':null,'lastName':null},{'email':'person+7@at.com','firstName':null,'lastName':null},{'email':'person+8@at.com','firstName':null,'lastName':null}, {'email':'person+9@at.com','firstName':null,'lastName':null}, {'email':'person+10@at.com','firstName':null,'lastName':null}
]> curl http://localhost:8080/rest/api/people -X PUT -d 'email=a@b.com'
{'email':'a@b.com','firstName':null,'lastName':null}

太棒了! 并且请注意,我们完全不使用XML ! 源代码: https : //github.com/reta/spring-one-jar/tree/jetty-embedded

在结束这篇文章之前,我想提到一个很棒的项目Dropwizard ,它使用了非常相似的概念,但是由于Yammer的支持,所以将其推向了出色的,精心设计的框架。

参考: 走向REST:在Andriy Redko {devmind}博客上,从我们的JCG合作伙伴 Andrey Redko 嵌入Spring和JAX-RS(Apache CXF)的Jetty 。

翻译自: https://www.javacodegeeks.com/2013/01/going-rest-embedding-jetty-with-spring-and-jax-rs-apache-cxf.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369826.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分组后分页_SQL(约束、视图、分页、序列、索引、同义词、创建用户,为用户授权、执行计划的使用 数据的导入导出)...

学习主题&#xff1a;SQL学习目标&#xff1a;掌握约束掌握视图修改表名与删除表删除表中的列语句的语法结构是什么&#xff1f;答&#xff1a;delete 表名from table where ;删除表中的列语句的语法结构是什么&#xff1f;答&#xff1a;delete 表名from table where ;截断表的…

第三百三十四节,web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息...

第三百三十四节&#xff0c;web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻&#xff0c;爬取Ajax动态生成的信息 crapy爬取百度新闻&#xff0c;爬取Ajax动态生成的信息&#xff0c;抓取百度新闻首页的新闻rul地址 有多网站&#xff0c;当你浏览器访问时看到的信息&#xf…

BEM思想之彻底弄清BEM语法

BEM的意思就是块&#xff08;block&#xff09;、元素&#xff08;element&#xff09;、修饰符&#xff08;modifier&#xff09;,是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格&#xf…

Hibernate Search 4.2最终发布:支持空间查询

JBoss已宣布发布Hibernate Search 4.2 final。 您可以从Sourceforge下载它或使用Maven构件 。 在新版本中&#xff0c;包含了一些有趣的功能&#xff1a; Hibernate Search现在支持空间查询 。 使用Spatial扩展&#xff0c;您可以将全文查询与基于到空间点的距离的限制结合起…

推荐算法

5类系统推荐算法,非常好使,非常全 今日头条用了哪五种推荐算法 视频 今日头条核心技术“个性推荐算法”揭秘转载于:https://www.cnblogs.com/lhuser/p/8306092.html

python的应用包括哪些_Python应用领域有哪些?

1、数据分析与处理通常情况下&#xff0c;Python被用来做数据分析。用C设计一些底层的算法进行封装&#xff0c;然后用Python进行调用。因为算法模块较为固定&#xff0c;所以用Python直接进行调用&#xff0c;方便且灵活&#xff0c;可以根据数据分析与统计的需要灵活使用。Py…

win10系统同时安装python2和python3

1、官网下载python2和python3版本 2、安装python3&#xff0c;勾上Add Python3.5 to PATH&#xff0c;自定义选择安装目录&#xff0c;安装&#xff0c;验证&#xff1a;WINR--->cmd&#xff0c;输入python看看是否安装python3 3、安装python2&#xff0c;自定义安装目录&am…

使用NoSQLUnit测试Spring Data MongoDB应用程序

Spring Data MongoDB是Spring Data项目中的项目&#xff0c;它提供了Spring编程模型的扩展&#xff0c;用于编写使用MongoDB作为数据库的应用程序。 要使用NoSQLUnit为Spring Data MongoDB应用程序编写测试&#xff0c;除了考虑Spring Data MongoDB使用一个名为_class的特殊属…

20170117小测

今天再次迎来了我们的例行考试。 T1&#xff1a; 首先我们考虑那些点是可以共存的&#xff0c;我们可以枚举一个质数做他们的gcd&#xff0c;然后把这些点放在一张图里求直径。所以我们要做的就是把这些点的值分解质因数&#xff0c;对每个质因数挂一个链&#xff0c;代表有那些…

java实现红包要多少钱_java实现红包的分配算法

个人推测&#xff0c;微信红包在发出的时候已经分配好金额。比如一个10元的红包发给甲乙丙三个人&#xff0c;其实在红包发出去的时候&#xff0c;已经确定了第一个会领取多少&#xff0c;第二个会领取多少金额。而不是在领取的时候才计算的。下面贴出实现方法&#xff1a;publ…

iOS中Safari浏览器select下拉列表文字太长被截断的处理方法

网页中的select下拉列表&#xff0c;文字太长的话在iOS的Safari浏览器里会被自动截断&#xff0c;显示成下面这种&#xff1a; 安卓版的浏览器则没有这个问题。 如何让下拉列表中的文字在iOS的Safari浏览器里显示完整呢&#xff1f;答案是使用<optgroup></optgroup>…

HDU1042 N!(大整数类应用)

Problem Description Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N!InputOne N in one line, process to the end of file.OutputFor each N, output N! in one line.Sample Input123Sample Output126Code&#xff1a;#include <iostream> #includ…

Java内部具有原子更新的动态热交换环境

有人可能会说上述标题可以简称为OSGi &#xff0c;我想在一开始就放弃这种思考过程。 对于OSGi而言&#xff0c;这不是一个冒犯&#xff0c;这是一个很棒的规范&#xff0c;在实现层或可用性层上都弄得一团糟&#xff0c;这就是我对OSGi的信念。 当然&#xff0c;您可以使用OS…

Css Secret 案例Demo全套

Css Secret 案例全套 github地址 案例地址 去年买了一本CSS揭秘的css专题书&#xff0c;该书揭示了 47 个鲜为人知的 CSS 技巧&#xff0c;主要内容包括背景与边框、形状、 视觉效果、字体排印、用户体验、结构与布局、过渡与动画等。去年买入时&#xff0c;就决定将里面所有…

底量超顶量超级大黑马指标源码_底量超顶量+地量买点_月线底量超顶量大牛股,底量超顶量超级大黑马,底量超顶量买入指标,后量超前量买入指标_指标公式分享交流论坛_理想论坛 - 股票论坛...

l 图形特征&#xff1a;(1) 当股价从头部滑落一段时间后&#xff0c;会有一个见底回升的过程。(2) 这个头部区间的成交量称为顶量&#xff0c;见底回升时的成交量称为底量。(3) 如果底量能大大地超过顶量&#xff0c;则较容易通过顶量造成的压力带。…

php var_export与var_dump 输出的不同

问题发现在跟踪yratings_get_targets的时候&#xff0c;error_log(var_export(yblog_mspconfiginit("ratings"),true));老是打印出yblog_mspconfiginit(“ratings”)的返回是NULL 导致我以为是无法建立和DB的连接&#xff0c;走错路了一天。最后才发现&#xff0c;这…

Servlet 开发

1. Servlet &#xff08;很久远的东西&#xff0c;但是现在学习原理&#xff09; html css js 前端页面&#xff08;静态的&#xff09; form action ".html" Servlet 允许将action属性设置为映射&#xff0c;通过映射找到相关的Servlet class 进行数据的处理。…

JAX-RS Bean验证错误消息国际化

Bean验证简介 JavaBeans验证&#xff08;Bean验证&#xff09;是一种新的验证模型&#xff0c;可作为Java EE 6平台的一部分使用。 约束条件支持Bean验证模型&#xff0c;该约束以注释的形式出现在JavaBeans组件&#xff08;例如托管Bean&#xff09;的字段&#xff0c;方法或类…

CentOS 7 Flannel的安装与配置

1. 安装前的准备 etcd 3.2.9 Docker 17.12.0-ce 三台机器10.100.97.236, 10.100.97.92, 10.100.97.81 etcd不同版本之间的差别还是挺大的&#xff0c;使用V3版本跟Flannel整合起来会有坑&#xff0c;下文详解。 2. 安装 sudo yum install -y flannel 安装后&#xff0c;版本是0…

给Ambari集群里安装基于Hive的大数据实时分析查询引擎工具Impala步骤(图文详解)...

不多说&#xff0c;直接上干货&#xff01; Impala和Hive的关系&#xff08;详解&#xff09; 扩展博客 给Clouderamanager集群里安装基于Hive的大数据实时分析查询引擎工具Impala步骤&#xff08;图文详解&#xff09; 参考 hortonworks ambari集成impala ambari hdp 集成 imp…