当前位置: 首页 > 工具软件 > RESTEasy > 使用案例 >

REST(四)RESTEasy实现REST

宫弘亮
2023-12-01
RESTEasy是JBoss的一个开源项目,提供各种框架帮助你构建RESTful Web Services和RESTful Java应用程序。它是JAX-RS规范的一个完整实现并通过JCP认证。作为一个JBOSS的项目,它当然能和JBOSS应用服务器很好地集成在一起。但是,它也能在任何运行JDK5或以上版本的Servlet容器中运行。RESTEasy还提供一个RESTEasy JAX-RS客户端调用框架。能够很方便与EJB、Seam、Guice、Spring和Spring MVC集成使用。支持在客户端与服务器端自动实现GZIP解压缩。

其他RESTEasy介绍见官网:[url]http://resteasy.jboss.org/[/url]。本节简单介绍RESTEasy2+spring4的集成及客户端访问。

[b]1.spring web基础环境[/b]
见之前章节创建的web工程testRest。

[b]2.REST地址[/b]
与上一节类似,设计RESTEasy模块/resteasy/*。

[b]3.RESTEasy库[/b]
在项目pom.xml中加入RESTEasy依赖:

<properties>
<!-- resteasy高版本要求jdk1.8,使用低版本 -->
<resteasy.version>3.0.0.Final</resteasy.version>
</properties>
<dependencies>
...
<!-- resteasy begin -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
<!-- resteasy end -->
...

版本使用3.0.0.Final,因为更新的版本要求jdk1.8才能运行。

[b]4.Servlet[/b]
配置RESTEasy访问入口。

<!-- resteasy -->
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>
com.sunbin.test.resteasy.TeachersResource,com.sunbin.test.resteasy.TeacherResource
</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/resteasy</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
<servlet-name>resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resteasy</servlet-name>
<url-pattern>/resteasy/*</url-pattern>
</servlet-mapping>

resteasy Servlet将拦截/resteasy/*下的所有访问。
RESTEasy与web、spring集成后,不需要再自己实现Application、Component等组件,也不需要配置文件进行路径配置,仅需要使用@Path注解。

[b]5.实现api[/b]
新建com.sunbin.test.resteasy包,新增TeachersResource类,以实现/teachers路径的接口:

package com.sunbin.test.resteasy;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.springframework.beans.factory.annotation.Autowired;

import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;

@Path("/teachers")
@Produces(MediaType.APPLICATION_JSON)
public class TeachersResource {

@Autowired
private TeacherService teacherService;

@GET
public Map get() {
System.out.println("Resteasy TeachersResource.get");
Map map = new HashMap();
map.put("teachers", teacherService.list());
return map;
}

@POST
public Map post(@FormParam("age") int age, @FormParam("name") String name) {
Map map = new HashMap();
try {
Teacher teacher = new Teacher();
teacher.setName(name);
teacher.setAge(age);
System.out.println("Resteasy TeachersResource.post:" + teacher);
teacherService.save(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}

}

路径注解@Path、返回类型注解@Produces、访问方法@GET、参数读取@FormParam,都和Jersey的JAX-RS相同。

重新部署项目后,访问[url]http://localhost:8080/testRest/resteasy/teachers[/url],发现报错:
java.lang.NullPointerException
com.sunbin.test.resteasy.TeachersResource.get(TeachersResource.java:29)
检查后发现是teacherService.list()语句中teacherService为null,@Autowired注解没有生效。
尝试使用xml配置方式实现teacherService注入,或使用jsr规范自有的@Inject、@Resource注解也不生效。

为什么会这样?分析是因为RESTEasy和spring的beanfactory之间依赖注入的问题。
RESTEasy官网手册推荐以下两种解决方法:
1.通过WebApplicationContextUtils工具类获取ApplicationContext对象
2.自定义工具类
具体使用方法见我之前的文章:[url=http://sb33060418.iteye.com/blog/2372874]spring4学习(三)在非Spring类中获取Bean[/url]

为了方便注入,这里采用第二种方法:定义Context工具类SpringContextHolder并配置至spring。之后需要对Resource类进行改造:

package com.sunbin.test.resteasy;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.sunbin.common.spring.SpringContextHolder;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;

@Path("/teachers")
@Produces(MediaType.APPLICATION_JSON)
public class TeachersResource {

private TeacherService teacherService;

public TeachersResource() {
super();
// 不能自动注入,需要手动getBean赋值
teacherService = (TeacherService) SpringContextHolder
.getBean("teacherService");
// TODO Auto-generated constructor stub
}

@GET
public Map get() {
System.out.println("Resteasy TeachersResource.get");
Map map = new HashMap();
map.put("teachers", teacherService.list());
return map;
}

@POST
public Map post(@FormParam("age") int age, @FormParam("name") String name) {
Map map = new HashMap();
try {
Teacher teacher = new Teacher();
teacher.setName(name);
teacher.setAge(age);
System.out.println("Resteasy TeachersResource.post:" + teacher);
teacherService.save(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}

}

在TeachersResource类的构造方法中手动通过SpringContextHolder获取Bean,再赋值给resource。

同样的,新增TeacherResource类,以实现/teacher/{id}路径的接口:

package com.sunbin.test.resteasy;

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
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;

import com.sunbin.common.spring.SpringContextHolder;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;

@Path("teacher/{id}")
@Produces(MediaType.APPLICATION_JSON)
public class TeacherResource {

private TeacherService teacherService;

public TeacherResource() {
super();
teacherService = (TeacherService) SpringContextHolder
.getBean("teacherService");
// TODO Auto-generated constructor stub
}

@GET
public Map get(@PathParam("id") int id) {
System.out.println("Resteasy TeacherResource.get:" + id);
Teacher teacher = new Teacher();
teacher.setId(id);
Map map = new HashMap();
map.put("teacher", teacherService.get(teacher));
return map;
}

@PUT
public Map put(@PathParam("id") int id, @FormParam("age") int age,
@FormParam("name") String name) {
Map map = new HashMap();
try {
Teacher teacher = new Teacher();
teacher.setId(id);
teacher.setName(name);
teacher.setAge(age);
System.out.println("Resteasy TeacherResource.put:" + id + ":"
+ teacher);
teacherService.update(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}

@DELETE
public Map delete(@PathParam("id") int id) {
Map map = new HashMap();
try {
System.out.println("Resteasy TeacherResource.delete:" + id);
Teacher teacher = new Teacher();
teacher.setId(id);
teacherService.remove(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}

}


[b]6.js测试[/b]
使用上一节的测试页面src\main\webapp\rest\index.jsp进行测试:

...
<script type="text/javascript">
// 测试框架
//var restType = "jersey";
//var restType = "restlet";
var restType = "resteasy";
//var restType = "restCxf";
//var restType = "restMvc";
...

重新部署后,使用浏览器访问[url]http://localhost:8080/testRest/rest[/url],测试内容和Restlet测试相同。

[b]7.RESTEasy Client测试[/b]
RESTEasy提供Client库用于测试REST接口。
新建TestResteasy类,代码如下:

package com.sunbin.test.resteasy;

import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;

public class TestResteasy {

public static final String URL_BASE = "http://localhost:8080/testRest/resteasy/";

public static void main(String[] args) {
ResteasyClient client = new ResteasyClientBuilder().build();
String module = "teacher";
String url = "";
String result = "";
Entity<Form> entity = null;
Form form = null;
ResteasyWebTarget baseTarget = client.target(URL_BASE);
ResteasyWebTarget target = null;

url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("post\t " + url);
target = baseTarget.path(module + "s");
form = new Form().param("age", "1").param("name", "a");
entity = Entity.form(form);
result = target.request().post(entity, String.class);
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("get\t " + url);
target = baseTarget.path(module + "/1");
result = target.request().get(String.class);
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("put\t " + url);
target = baseTarget.path(module + "/1");
form = new Form().param("age", "11").param("name", "aa");
entity = Entity.form(form);
result = target.request().put(entity, String.class);
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("delete\t " + url);
target = baseTarget.path(module + "/1");
result = target.request().delete(String.class);
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);
}
}

测试结果与Restlet类似。
 类似资料: