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
的分页,我创建了一些帮助程序类: Page
, Sort
和PageAssertion
。 您可以在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!");}
}
通过上面的代码,我希望根上下文中可以同时使用health和spring-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
Jersey和Spring Boot入门相关推荐
- Spring Boot 入门
一.Spring Boot 入门 1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Spring技术栈的一个大整合: J2EE开发的一站式解决方案: 2.微服务 2014,m ...
- Spring Boot 入门与实战笔记
**一.**Spring Boot 入门 1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Spring技术栈的一个大整合: J2EE开发的一站式解决方案: 2.微服务 20 ...
- Spring Boot入门到牛X
Spring Boot入门到牛X 1.Spring Boot 项目下载地址:https://download.csdn.net/download/weixin_39549656/10287664 1. ...
- Spring Boot 入门笔记
一.Spring Boot 入门 1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Spring技术栈的一个大整合: J2EE开发的一站式解决方案: 2.微服务 2014,m ...
- Spring Boot入门——全局异常处理
Spring Boot入门--全局异常处理 参考文章: (1)Spring Boot入门--全局异常处理 (2)https://www.cnblogs.com/studyDetail/p/702758 ...
- Spring Boot 入门——Spring Boot 简介||微服务简介
Spring Boot 入门 1.Spring Boot 简介 Spring Boot来简化Spring应用开发,约定大于配置, 去繁从简,just run就能创建一个独立的,产品级别的应用 简化Sp ...
- Spring Boot 入门(五):集成 AOP 进行日志管理
本篇文章是接着 Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理写的,按照前面几篇博客的教程,可以搭建一个简单的项目,主要包含了 Pagehelper+MyBatis 分页 ...
- Spring Boot 入门之缓存和 NoSQL 篇(四)
原文地址:Spring Boot 入门之缓存和 NoSQL 篇(四) 博客地址:http://www.extlight.com 一.前言 当系统的访问量增大时,相应的数据库的性能就逐渐下降.但是,大多 ...
- Spring Boot 入门小目标 3 --- 先来试着热部署
2019独角兽企业重金招聘Python工程师标准>>> Spring Boot 入门小目标---先来试着热部署 这次写的主要就是 使用 springloaded 来实现 热部署. 很 ...
最新文章
- 解密 Dubbo 三大中心的部署架构
- 机器学习在稀疏标注数据内部审计中的应用
- 【一篇文章搞懂】25K大牛甩出的超详细面试总结
- 用Visual C#开发简单的复合控件
- java根据ip查计算机名_Java如何从IP地址查找主机名?
- 5G NR RLC:RLC架构和RLC entity
- Interface classes
- PHP框架最低支持PHP版本
- sublime 如何使用less_Sublime Text3 使用教程
- 三星Galaxy Note系列旗舰今年确定缺席:超万名粉丝请愿望其回归
- python全局变量修改_python中全局变量的修改
- An internal error occurred during: Android Library Update.
- 勤哲excel服务器端口协议,用勤哲Excel服务器实现管理完整.doc
- 新手初用mybatis
- 蓝牙 sig base uuid_蓝牙,从系统开机说起
- Atcoder ABC162 D - RGB Triplets
- gbd调试的基本使用方法
- 004_simulink建立子系统
- unity 查找所以物体_unity中查找物体的方法
- 作为一名女程序员是什么体验?
热门文章
- 2019蓝桥杯省赛---java---C---2(矩阵切割)
- linux挂载多个目录下,linux – 如何在centos上使用nfs4挂载多个文件夹?
- ios刷android8.0,颤抖吧 iOS, Android 8.0正式发布!
- oracle spacial,Oracle Spacial(空间数据库)geometry元数据结构
- python爬新闻并保存csv_用python爬取内容怎么存入 csv 文件中
- thinking-in-java(20)注解
- 产品原型示例_原型设计模式示例
- ejb能调用另一个ejb吗_异步EJB只是一个Gi头吗?
- jboss eap 7.0_是时候抛弃Java 7 – JBoss EAP 6.4了!
- rest接口自动化测试_REST服务的自动化测试