Jersey和Spring Boot入门

除了许多新功能,Spring Boot 1.2还带来了Jersey支持。 这是吸引喜欢标准方法的开发人员的重要一步,因为他们现在可以使用JAX-RS规范构建RESTful API,并将其轻松部署到Tomcat或任何其他Spring's Boot支持的容器中。 带有Spring平台的Jersey可以在mico服务的开发中发挥重要作用。 在本文中,我将演示如何使用Spring Boot(包括:Spring Data,Spring Test,Spring Security)和Jersey快速构建应用程序。

引导一个新项目

该应用程序是常规的Spring Boot应用程序,它使用Gradle及其最新的2.2版本。 Gradle不如Maven冗长,它特别适合Spring Boot应用程序。 可以从Gradle网站下载Gradle: http : //www.gradle.org/downloads 。

启动项目的初始依赖项:

dependencies {compile("org.springframework.boot:spring-boot-starter-web")compile("org.springframework.boot:spring-boot-starter-jersey")compile("org.springframework.boot:spring-boot-starter-data-jpa")// HSQLDB for embedded database supportcompile("org.hsqldb:hsqldb")// Utilitiescompile("com.google.guava:guava:18.0")// AssertJtestCompile("org.assertj:assertj-core:1.7.0")testCompile("org.springframework.boot:spring-boot-starter-test")
}

应用程序入口点是一个包含main方法的类,并使用@SpringBootApplication注释进行注释:

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

@SpringBootApplication注释是一个便捷注释,等效于声明@Configuration @EnableAutoConfiguration@ComponentScan @EnableAutoConfiguration@ComponentScan ,它是Spring Boot 1.2的新增功能。

球衣配置

入门就像创建用@Path和Spring的@Component注释的根资源一样容易:

@Component
@Path("/health")
public class HealthController {@GET@Produces("application/json")public Health health() {return new Health("Jersey: Up and Running!");}
}

并将其注册在从Jersey ResourceConfig扩展的Spring的@Configuration类中:

@Configuration
public class JerseyConfig extends ResourceConfig {public JerseyConfig() {register(HealthController.class);}
}

我们可以使用gradlew bootRun启动该应用程序,访问: http:// localhost:8080 / health ,我们应该看到以下结果:

{"status": "Jersey: Up and Running!"
}

但是也可以编写一个具有完全加载的应用程序上下文的Spring Boot集成测试:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest("server.port=9000")
public class HealthControllerIntegrationTest {private RestTemplate restTemplate = new TestRestTemplate();@Testpublic void health() {ResponseEntity<Health> entity = restTemplate.getForEntity("http://localhost:9000/health", Health.class);assertThat(entity.getStatusCode().is2xxSuccessful()).isTrue();assertThat(entity.getBody().getStatus()).isEqualTo("Jersey: Up and Running!");}
}

Jersey 2.x具有本机Spring支持( jersey-spring3 ),Spring Boot通过spring-boot-starter-jersey起动器为其提供了自动配置支持。 有关更多详细信息,请查看JerseyAutoConfiguration类。

根据spring.jersey.type属性值,Jersey Servlet或Filter都注册为Spring Bean:

Mapping servlet: 'jerseyServlet' to [/*]

可以通过添加到ResourceConfig配置类的javax.ws.rs.ApplicationPath批注来更改默认映射路径:

@Configuration
@ApplicationPath("/jersey")
public class JerseyConfig extends ResourceConfig {}

JSON媒体类型支持随附有jersey-media-json-jackson依赖项,该依赖项注册了可供Jersey使用的Jackson JSON提供程序。

Spring Data JPA集成

Spring Data JPA是较大的Spring Data系列的一部分,可轻松实现基于JPA的存储库。 对于那些不熟悉该项目的人,请访问: http : //projects.spring.io/spring-data-jpa/

客户和客户存储库

此示例项目的域模型只是具有一些基本字段的Customer

@Entity
public class Customer extends AbstractEntity {private String firstname, lastname;@Columnprivate EmailAddress emailAddress;

Customer需要一个@Repository ,因此我们使用Spring的Data仓库创建了一个基本的仓库。 通过简单的接口定义,Spring Data存储库减少了许多样板代码:

public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long> {}

使用域模型后,可以方便地使用一些测试数据。 最简单的方法是为data.sql文件提供要在应用程序启动时执行的SQL脚本。 该文件位于src/main/resources ,Spring会自动将其拾取。 该脚本包含几个SQL插入内容以填写customer表。 例如:

insert into customer (id, email, firstname, lastname) values (1, 'joe@doe.com', 'Joe', 'Doe');

客户总监

在使用Spring Data JPA存储库之后,我创建了一个控制器(以JAX-RS –资源表示),该控制器允许对Customer对象进行CRUD操作。

注意:我坚持使用HTTP端点的Spring MVC命名约定,但可以随意使用JAX-RS方式。

获得客户

让我们从返回所有客户的方法开始:

@Component
@Path("/customer")
@Produces(MediaType.APPLICATION_JSON)
public class CustomerController {@Autowiredprivate CustomerRepository customerRepository;@GETpublic Iterable<Customer> findAll() {return customerRepository.findAll();}
}

使用@Component保证CustomerController是一个Spring托管对象。 @Autowired可以轻松替换为标准javax.inject.@Inject注释。

由于我们在项目中使用Spring Data,因此我可以轻松利用PagingAndSortingRepository.提供的PagingAndSortingRepository. 我修改了资源方法以支持某些页面请求参数:

@GET
public Page<Customer> findAll(@QueryParam("page") @DefaultValue("0") int page,@QueryParam("size") @DefaultValue("20") int size,@QueryParam("sort") @DefaultValue("lastname") List<String> sort,@QueryParam("direction") @DefaultValue("asc") String direction) {return customerRepository.findAll(new PageRequest(page, size, Sort.Direction.fromString(direction), sort.toArray(new String[0])));
}

为了验证以上代码,我创建了Spring集成测试。 在第一次测试中,我将要求所有记录,并且根据先前准备的测试数据,我希望在20页的1页中总共有3个客户:

@Test
public void returnsAllPages() {// actResponseEntity<Page<Customer>> responseEntity = getCustomers("http://localhost:9000/customer");Page<Customer> customerPage = responseEntity.getBody();// assertPageAssertion.assertThat(customerPage).hasTotalElements(3).hasTotalPages(1).hasPageSize(20).hasPageNumber(0).hasContentSize(3);
}

在第二个测试中,我将调用大小为1的第0页,并按firstname排序,排序方向descending 。 我希望元素总数不变(3),返回的页面总数为3,返回的页面内容大小为1:

@Test
public void returnsCustomPage() {// actResponseEntity<Page<Customer>> responseEntity = getCustomers("http://localhost:9000/customer?page=0&size=1&sort=firstname&direction=desc");// assertPage<Customer> customerPage = responseEntity.getBody();PageAssertion.assertThat(customerPage).hasTotalElements(3).hasTotalPages(3).hasPageSize(1).hasPageNumber(0).hasContentSize(1);
}

该代码也可以使用curl检查:

$ curl -i http://localhost:8080/customerHTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 702
Date: Sat, 03 Jan 2015 14:27:01 GMT{...}

请注意,为了轻松测试RestTemplate的分页,我创建了一些帮助程序类: PageSortPageAssertion 。 您可以在Github中的应用程序源代码中找到它们。

添加新客户

在这个简短的代码片段中,我使用了Jersey的某些功能,如注入@Context 。 在创建新实体的情况下,我们通常要返回标题中资源的链接。 在下面的示例中,我将UriBuilder注入到终结点类中,并使用它来构建新创建的客户的位置URI:

@Context
private UriInfo uriInfo;@POST
public Response save(Customer customer) {customer = customerRepository.save(customer);URI location = uriInfo.getAbsolutePathBuilder().path("{id}").resolveTemplate("id", customer.getId()).build();return Response.created(location).build();
}

在调用POST方法(不存在电子邮件)时:

$ curl -i -X POST -H 'Content-Type:application/json' -d '{"firstname":"Rafal","lastname":"Borowiec","emailAddress":{"value": "rafal.borowiec@somewhere.com"}}' http://localhost:8080/customer

我们将得到:

HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/customer/4
Content-Length: 0
Date: Sun, 21 Dec 2014 22:49:30 GMT

当然,也可以创建集成测试。 它使用RestTemplate使用postForLocation方法保存客户,然后使用getForEntity检索它:

@Test
public void savesCustomer() {// actURI uri = restTemplate.postForLocation("http://localhost:9000/customer",new Customer("John", "Doe"));// assertResponseEntity<Customer> responseEntity =restTemplate.getForEntity(uri, Customer.class);Customer customer = responseEntity.getBody();assertThat(customer.getFirstname()).isEqualTo("John");assertThat(customer.getLastname()).isEqualTo("Doe");
}

其他方法

端点的其余方法确实很容易实现:

@GET
@Path("{id}")
public Customer findOne(@PathParam("id") Long id) {return customerRepository.findOne(id);
}@DELETE
@Path("{id}")
public Response delete(@PathParam("id") Long id) {customerRepository.delete(id);return Response.accepted().build();
}

安全

通过向项目添加新的依赖关系,可以快速地将Spring Security添加到应用程序中:

compile("org.springframework.boot:spring-boot-starter-security")

使用Spring Security在classpath中,应用程序将通过所有HTTP端点上的基本身份验证得到保护。 可以使用以下两个应用程序设置( src/main/resources/application.properties )更改默认的用户名和密码:

security.user.name=demo
security.user.password=123

在使用Spring Security应用程序运行该应用程序之后,我们需要为每个请求提供一个有效的身份验证参数。 使用curl我们可以使用--user开关:

$ curl -i --user demo:123 -X GET http://localhost:8080/customer/1

随着Spring Security的添加,我们先前创建的测试将失败,因此我们需要为RestTemplate提供用户名和密码参数:

private RestTemplate restTemplate = new TestRestTemplate("demo", "123");

分派器Servlet

Spring的Dispatcher Servlet与Jersey Servlet一起注册,并且它们都映射到根资源 。 我扩展了HealthController ,并向其中添加了Spring MVC请求映射:

@Component
@RestController // Spring MVC
@Path("/health")
public class HealthController {@GET@Produces({"application/json"})public Health jersey() {return new Health("Jersey: Up and Running!");}@RequestMapping(value = "/spring-health", produces = "application/json")public Health springMvc() {return new Health("Spring MVC: Up and Running!");}
}

通过上面的代码,我希望根上下文中可以同时使用healthspring-health端点,但显然不起作用。 我尝试了几种配置选项,包括设置spring.jersey.filter.order但没有成功。

我发现的唯一解决方案是更改Jersey @ApplicationPath或更改Spring MVC server.servlet-path属性:

server.servlet-path=/s

在后一个示例中,调用:

$ curl -i --user demo:123 -X GET http://localhost:8080/s/spring-health

返回预期结果:

{"status":"Spring MVC: Up and Running!"
}

使用Undertow代替Tomcat

从Spring Boot 1.2开始,支持Undertow轻量级高性能Servlet 3.1容器。 为了使用Undertow代替Tomcat,必须将Tomcat依赖项与Undertow的依赖项交换:

buildscript {configurations {compile.exclude module: "spring-boot-starter-tomcat"}
}    dependencies {compile("org.springframework.boot:spring-boot-starter-undertow:1.2.0.RELEASE")
}

运行该应用程序时,日志将包含:

org.xnio: XNIO version 3.3.0.Final
org.xnio.nio: XNIO NIO Implementation Version 3.3.0.Final
Started Application in 4.857 seconds (JVM running for 5.245)

摘要

在这篇博客文章中,我演示了一个简单的示例,说明如何开始使用Spring Boot和Jersey。 由于Jersey的自动配置,向Spring应用程序添加JAX-RS支持非常容易。

通常,Spring Boot 1.2使使用Java EE的应用程序构建更加容易:使用Atomikos或Bitronix嵌入式事务管理器进行JTA事务,在JEE Application Server中对DataSource和JMS ConnectionFactory进行JNDI查找,并简化JMS配置。

资源资源

  • 项目源代码: https : //github.com/kolorobot/spring-boot-jersey-demo
  • 后续: 使用JAX-RS和Spring构建HATEOAS API

翻译自: https://www.javacodegeeks.com/2015/01/getting-started-with-jersey-and-spring-boot.html

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

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

相关文章

js对象数组(JSON) 根据某个共同字段分组

希望的是将下面的对象数组&#xff1a; [{"id":"1001","name":"值1","value":"111"},{"id":"1001","name":"值1","value":"11111"},{"id&quo…

用装饰器改变收藏

装饰图案 自从第一次学习编程设计模式以来&#xff0c;装饰器模式一直是我的最爱。 在我看来&#xff0c;这是一个很新颖的想法&#xff0c;比其他想法有趣得多。 不要误会我的意思&#xff0c;其他大多数人也引起了我的注意&#xff0c;但没有什么比装饰器模式更重要。 至今&a…

ASP.NET WebAPI 自定义ControllerSelector

呃..今天同事要实现客户端调用不同版本Controller的功能, 其实几句代码就搞定了.. 首先定义自己的ControllerSelector,代码如下: public class ShadowControllerSelector : IHttpControllerSelector{private readonly HttpConfiguration _configuration;public ShadowControlle…

MomentJS计算两个时间的差值diff方法

moment(endTime).diff(moment(startTime), years)moment(endTime).diff(moment(startTime), months)moment(endTime).diff(moment(startTime), days) // 开始时间和结束时间的时间差&#xff0c;以“天”为单位&#xff1b;endTime和startTime都是毫秒数moment(endTime).d…

JAX-RS 2.0:服务器端处理管道

这篇文章的灵感来自JAX-RS 2.0规范文档 &#xff08;附录C&#xff09;中的Processing Pipeline部分。 我喜欢它是因为它提供了JAX-RS中所有模块的漂亮快照-以准备好吞咽的胶囊形式&#xff01; 礼貌– JAX-RS 2.0规范文档 因此&#xff0c;我想到了使用此图简要概述不同的JA…

基于TCP/IP的文件服务器编程一例

来源&#xff0c;华清远见嵌入式学院实验手册&#xff0c;代码来源&#xff1a;华清远见曾宏安 实现的功能&#xff1a; 编写TCP文件服务器和客户端。客户端可以上传和下载文件 客户端支持功能如下&#xff1a; 1.支持一下命令 help 显示客户端所有命令和说明 list 显示服务器…

React 向children中传值,layouts

const newChild React.children.map(children,function(childItem){return React.cloneElement(childItem,{key:传递的数据}) })

Apache TomEE + JMS。 这从未如此简单。

我记得J2EE &#xff08;1.3和1.4&#xff09;的过去&#xff0c;使用JMS启动项目非常困难。 您需要安装JMS 代理 &#xff0c;创建主题或队列 &#xff0c;最后使用服务器配置文件和JNDI开始自己的战斗。 感谢JavaEE 6及其它&#xff0c;使用JMS确实非常简单。 但是使用Apach…

Struts2显示double价格格式0.00

在国际化资源文件中加入&#xff1a; format.money{0,number,0.00} jsp页面用struts标签&#xff1a; <s:text name"format.money">   <s:param name"value" value"priceName" /> </s:text> 输出格式&#xff1a;0.00转载于…

数组方法大全ES5+ES6

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录1. 使用 Array 构造函数2. 使用数组字面量表示法数组原型方法1. join()2.push()和pop()3.shift() 和 unshift()4.sort()5.reverse()6.concat()7.slice()8.splice()9.…

【Linux系统基础】(2)在Linux上部署MySQL、RabbitMQ、ElasticSearch、Zookeeper、Kafka、NoSQL等各类软件

实战章节&#xff1a;在Linux上部署各类软件 前言 为什么学习各类软件在Linux上的部署 在前面&#xff0c;我们学习了许多的Linux命令和高级技巧&#xff0c;这些知识点比较零散&#xff0c;同学们跟随着课程的内容进行练习虽然可以基础掌握这些命令和技巧的使用&#xff0c;…

使用Java 8流进行快速失败的验证

我已经失去了使用类似方法通过失败快速验证代码状态的次数&#xff1a; public class PersonValidator {public boolean validate(Person person) {boolean valid person ! null;if (valid) valid person.givenName ! null;if (valid) valid person.familyName ! null;if (…

找到数组最大值

const maxHight Math.max.apply(null, rowData && rowData.urlImage.map(ele > ele.long) || []);

JDK 7和JDK 8中大行读取速度较慢的原因

我之前发布了博客文章“使用JDK 7和JDK 8读取慢速行”&#xff0c;并且在该问题上有一些有用的评论来描述该问题。 这篇文章提供了更多解释&#xff0c;说明为何该文章中演示的文件读取&#xff08;并由Ant的LineContainsRegExp使用 &#xff09;在Java 7和Java 8中比在Java 6中…

Spring Stateless State Security第3部分:JWT +社会认证

我的Stateless Spring Security系列文章的第三部分也是最后一部分是关于将基于JWT令牌的身份验证与spring-social-security混合在一起的。 这篇文章直接建立在此基础上&#xff0c;并且主要集中在已更改的部分上。 想法是使用基于OAuth 2的“使用Facebook登录”功能来替换基于用…

css React 单行省略和多行省略

单行省略 white-space: nowrap; text-overflow: ellipsis; overflow: hidden; word-break: break-all;多行省略 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;我们需要在需要超出加省略号的标签…

nyoj239 月老的难题 二分图 匈牙利算法

月老的难题 时间限制&#xff1a;1000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述月老准备给n个女孩与n个男孩牵红线&#xff0c;成就一对对美好的姻缘。 现在&#xff0c;由于一些原因&#xff0c;部分男孩与女孩可能结成幸福的一家&#xff0c;部分可能不会结…

使用系统规则测试System.in和System.out

编写单元测试是软件开发的组成部分。 当您的被测类与操作系统交互时&#xff0c;您必须解决的一个问题是模拟其行为。 这可以通过使用模拟代替Java Runtime Environment&#xff08;JRE&#xff09;提供的实际对象来完成。 支持Java的模拟的库是例如嘲笑或jMock 。 当您完全控…

循环对象

params为对象&#xff0c;key为对象的k值 Object.keys(params).forEach(key > {formData.append(key, params[key]); });

[转]C#操作XML方法详解

本文转自&#xff1a;http://www.cnblogs.com/minotmin/archive/2012/10/14/2723482.html using System.Xml;//初始化一个xml实例XmlDocument xmlnew XmlDocument(); //导入指定xml文件xml.Load(path);xml.Load(HttpContext.Current.Server.MapPath("~/file/bookstore.xml…