如果你的eclipse中没有安装Maven插件。
- 在eclipse中创建Maven项目
2.单击"Next"
-
选择Maven项目类型为"maven-archetype-webapp"
-
输入项目相关的Maven设置
-
分别创建src/main下java文件夹以及src下test文件夹
-
设置src/main/java和src/test/java为source folder
-
最终设置结果如下:
Q1:项目忽然出现 The superclass “javax.servlet.http.HttpServlet” was not found on the Java Build Path 的错误
Solve:点击项目右键>>Build Path>>Configure Build Path
在弹出的窗口,选择Server Runtime
点击next,选择一个自己配置好的tomcat服务
点击finish,然后apply and Close即可
Q2:在更改Dynamic Web Module的版本时(2.3->3.0),出现Cannot change version of project facet Dynamic web module to 3.0错误
说明:我们用Eclipse创建Maven结构的web项目的时候选择了Artifact Id为maven-artchetype-webapp,由于这个catalog比较老,用的servlet还是2.3的,而一般现在至少都是2.5,在Project Facets里面修改Dynamic web module为2.5的时候就会出现Cannot change version of project facet Dynamic web module to 2.5
Solve:
修改src/main/webapp/WEB-INF/web.xml文件如下:
修改前:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
这里版本太老 要更新为3.0版本:
添加一个Jersey的核心servlet(简单理解为MVC框架中的前端控制器即可):
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>jerseywstest</param-value>//代表的是你服务端的路径,要和你的工程服务器端路径保持一致。
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
其中注意ServletContainer即为核心控制器,而jersey.config.server.provider.packages参数一看就是用于扫描jersey中REST服务类所在的包(可以简单理解为SpringMVC中的component-scan);
- 修改pom.xml,添加Maven相应依赖库
在这里插入代码片
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.jianxi.tutorials.jerseyws</groupId>
<artifactId>jerseywstest</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>jerseywstest Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
<build>
<finalName>jerseywstest</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<configuration>
<warFile>target/jerseywstest.war</warFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 添加基本POJO类Student:
package net.jianxi.tutorials.jerseyws.metadata;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Student {
private int id;
private String name;
private String dept;
public int getId() {
return id;
}
public Student() {
}
public Student(int id, String name, String dept) {
super();
this.id = id;
this.name = name;
this.dept = dept;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
}
- 添加一个REST web服务实现类RestWsDemo:
1 package net.jianxi.tutorials.jerseyws;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import javax.ws.rs.DELETE;
9 import javax.ws.rs.FormParam;
10 import javax.ws.rs.GET;
11 import javax.ws.rs.POST;
12 import javax.ws.rs.PUT;
13 import javax.ws.rs.Path;
14 import javax.ws.rs.PathParam;
15 import javax.ws.rs.Produces;
16 import javax.ws.rs.QueryParam;
17 import javax.ws.rs.core.MediaType;
18
19 import net.jianxi.tutorials.jerseyws.metadata.Student;
20
21 import org.apache.log4j.Logger;
22
23
24 @Path("/students")
25 public class RestWsDemo {
26 private static Logger logger = Logger.getLogger(RestWsDemo.class);
27 private static int index = 1;
28 private static Map<Integer,Student> studentList = new HashMap<Integer, Student>();
29
30 public RestWsDemo() {
31 if(studentList.size()==0) {
32 studentList.put(index, new Student(index++, "Frank", "CS"));
33 studentList.put(index, new Student(index++, "Jersey", "Math"));
34 }
35 }
36
37 @GET
38 @Path("{studentid}")
39 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
40 public Student getMetadata(@PathParam("studentid") int studentid) {
41 if(studentList.containsKey(studentid))
42 return studentList.get(studentid);
43 else
44 return new Student(0, "Nil", "Nil");
45 }
46
47 @GET
48 @Path("list")
49 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
50 public List<Student> getAllStudents() {
51 List<Student> students = new ArrayList<Student>();
52 students.addAll(studentList.values());
53 return students;
54 }
55
56 @POST
57 @Path("add")
58 @Produces("text/plain")
59 public String addStudent(@FormParam("name") String name,
60 @FormParam("dept") String dept) {
61 studentList.put(index, new Student(index++, name, dept));
62 return String.valueOf(index-1);
63 }
64
65 @DELETE
66 @Path("delete/{studentid}")
67 @Produces("text/plain")
68 public String removeStudent(@PathParam("studentid") int studentid) {
69 logger.info("Receieving quest for deleting student: " + studentid);
70
71 Student removed = studentList.remove(studentid);
72 if(removed==null) return "failed!";
73 else return "true";
74 }
75
76 @PUT
77 @Path("put")
78 @Produces("text/plain")
79 public String putStudent(@QueryParam("studentid") int studentid,
80 @QueryParam("name") String name,
81 @QueryParam("dept") String dept
82 ) {
83 logger.info("Receieving quest for putting student: " + studentid);
84 if(!studentList.containsKey(studentid))
85 return "failed!";
86 else
87 studentList.put(studentid, new Student(studentid, name, dept));
88
89 return String.valueOf(studentid);
90 }
91 }
92
简单解释一下这段代码:
- 注意类是放在jerseywstest包中,而这个包是我们jersey.config.server.provider.packages参数中配置的包的子包,即该类是能够被扫描到的;
- 在类上面添加了@Path(“list”),代表资源根路径为list,类似于SpringMVC中在类上面添加@RequestMapping(“list”);
- 方法getAllStudents上面添加了两个标签,@GET标签代表该方法接受GET类型请求,类似于SpringMVC中的@GetMapping标签;
- @Produces标签代表该方法的响应MIME类型为application/xml,类似于@RequestMapping中的produces属性;
- 该方法返回String,这个String值Jersey会自动按照application/xml格式输出。
- 运行Maven package任务,构建war文件,部署war应用到你的Web服务器。
13. 测试
我马上就会推出如何用SoapUI工具测试Jersey Web服务的教程。这里这介绍简单的测试方法。
13.1) 对于GET,可以直接通过浏览器进行测试,在浏览器中直接输入:http://localhost:8080/jerseywstest/rest/students/list, 你应该看到返回的XML数据:
<students>
<student>
<dept>CS</dept>
<id>1</id>
<name>Frank</name>
</student>
<student>
<dept>Math</dept>
<id>2</id>
<name>Jersey</name>
</student>
</students>
输入:http://localhost:8080/jerseywstest/rest/students/1则会返回一个学生的信息。
13.2) 测试POST方法。
添加一个testpost.htm文件
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="/jerseywstest/rest/students/add" method="post">
<input type="text" id="name" name="name"/><br/>
<input type="text" id="dept" name="dept"/><br/>
<input type= "submit"/>
</form>
</body>
</html>
提交后你在用list方法就可以看到数据的变化。
13.3) PUT和DELETE方法的测试
添加一个Junit测试类
1 package net.jianxi.tutorials.jerseyws;
2
3
4 import javax.ws.rs.core.MultivaluedMap;
5
6 import org.junit.Before;
7 import org.junit.BeforeClass;
8 import org.junit.Test;
9
10 import com.sun.jersey.api.client.Client;
11 import com.sun.jersey.api.client.ClientResponse;
12 import com.sun.jersey.api.client.WebResource;
13 import com.sun.jersey.core.util.MultivaluedMapImpl;
14
15 public class RestWsDemoTest {
16 private String url = "http://localhost:8080/jerseywstest/rest/students";
17
18 @Test
19 public void testDelete() {
20 Client client = Client.create();
21 WebResource webResource = client.resource(url + "/delete/1");
22 ClientResponse response = webResource.delete(ClientResponse.class);
23
24 System.out.println("Response for delete request: " + response.getStatus());
25 }
26
27 @Test
28 public void testPut() {
29 Client client = Client.create();
30 WebResource webResource = client.resource(url + "/put");
31 MultivaluedMap queryParams = new MultivaluedMapImpl();
32 queryParams.add("studentid", "2");
33 queryParams.add("name", "nametest");
34 queryParams.add("dept", "depttest");
35 ClientResponse response = webResource.queryParams(queryParams).put(ClientResponse.class, "foo:test");
36 System.out.println("Response for put request: " + response.getStatus());
37 }
38 }
39
Jersey基础应用
下面来介绍Jersey的一些基本使用方式。做一个入门概念,注意,再次强调,Jersey的使用和SpringMVC对比着学习,会非常轻松。
资源设置
Jersey中使用@Path注解来设置资源,也支持资源的继承和路径参数,下面给出一个示例代码:
@Path("path")
public class PathRest {
/**
* 映射url中匹配的占位符
*
* @param id
* @return
*/
@GET
@Path("{id}")
public String pathParam(@PathParam("id") Long id) {
System.out.println(this);
System.out.println(id);
return "success";
}
}
简单解释:
1,PathRest类上面的@Path(“path”)限制了资源根路径为/path,而pathParam方法上的@Path("{id}")限制了子资源请求路径为/path/{id},类似于SpringMVC中的@RequestMapping("{id}")。
2,在请求方法中,使用@PathParam(“id”)完成从url中对资源占位符的解析,并同样支持类型转化,相当于SpringMVC中的@PathVariable标签;
JSON和XML
在Jersey中返回JSON类型和XML类型是非常简单的事情,而且功能比SpringMVC更强。我们先来简单的看看怎么使用(下面的案例使用Servlet容器部署的方式,使用Jetty的方式需要额外的操作)。
添加JSON和XML的pom.xml依赖
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
<scope>provided</scope>
</dependency>
添加了jersey-media-json-jackson这个依赖包,使用Jackson来完成json和xml的转化。
创建一个Department对象:
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@XmlRootElement
public class Department {
private Long id;
private String name;
}
注意,为了支持XML的生成,我们仍然添加了@XmlRootElement标签。
资源类代码:
@Path("dept")
public class DepartmentRest {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public List<Department> list() {
List<Department> dept = new ArrayList<>();
dept.add(new Department(1L, "dept1"));
dept.add(new Department(2L, "dept2"));
return dept;
}
}
注意:
1,@GET标签:说明该资源方法是使用get方式请求;
2,@Produces标签:代表该资源方法生产的响应MIME格式为application/json;
3,@Consumes标签:代表该资源方法能够接受请求MIME类型为application/json;
4,在方法中,直接返回department对象的列表;
请求GET /dept
可以看到,Jersey会自动的根据@Produces产生的数据来生成响应内容。我们再来看看XML的生成方式,只需要在资源类中增加一个方法:
@GET
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public List<Department> listXml() {
List<Department> dept = new ArrayList<>();
dept.add(new Department(1L, "dept1"));
dept.add(new Department(2L, "dept2"));
return dept;
}
可以看到,唯一的区别就是@Produces和@Consumes的类型设置为application/xml。
这次,再请求的时候,注意我们需要设置客户端的Accepts为application/xml:
得到的请求结果为:
正确得到XML的结果。
- 合并
在上面的例子中,我们是通过两个资源方法来完成JSON和XML格式的内容输出,其实Jersey中提供了更合理的方式,把两段代码合并起来:
@GET
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public List<Department> list() {
List<Department> dept = new ArrayList<>();
dept.add(new Department(1L, "dept1"));
dept.add(new Department(2L, "dept2"));
return dept;
}
可以看到,我们在@Produces和@Consumes中分别设置了我们要支持的application/xml和application/json格式,在请求的时候,分别设置Accepts为application/xml或者application/json,就可以得到JSON或者XML格式了!!这点是SpringMVC做不到的,而且更直接的反应出REST的概念!
请求类型设置
每个方法接受固定的请求类型,这个也是REST的基本需求之一。在SpringMVC中,通过@RequestMapping(method=XXX)来设置。在Jersey中,提供了一些更为简单的标签来设置,下面提供一组CRUD操作示例:
@GET //1
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_XML)
public List<Department> list() {
List<Department> dept = new ArrayList<>();
dept.add(new Department(1L, "dept1"));
dept.add(new Department(2L, "dept2"));
return dept;
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_XML)
public Department get(@PathParam("id") Long id) {
return new Department(id, "dept2");
}
@POST //2
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_XML)
public Department save(@FormParam("name") String name) {
Department d = new Department(1L, name);
return d;
}
@PUT //3
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_XML)
public Department update(@PathParam("id") Long id, @FormParam("name") String name) {
Department d = new Department(id, name);
return d;
}
@DELETE //4
@Path("{id}")
@Consumes(MediaType.APPLICATION_XML)
public void delete(@PathParam("id") Long id) {
System.out.println("删除部门:" + id);
}
为了不引入更多额外的内容,只展示了一个简单的CRUD。其中:
1,@GET注解之前已经提到过,表示接受GET类型请求,类似@GetMapping;
2,@POST,表示接受POST类型请求,类似@PostMapping,或者@RequestMapping(method=RequestMethod.POST);其次注意,在save方法参数列表中出现了@FormParam(“name”),代表name参数映射请求的form表单中的name名称的字段值;关于参数绑定,Jersey还是提供了相当多的注解来映射,后面再介绍。
3,@PUT,表示接受POST类型请求,类似@RequestMapping(method=RequestMethod.PUT);
4,@DELETE,表示接受DELETE类型请求,类似@RequestMapping(method=RequestMethod.DELETE);
5,另外,Jersey还提供了@HEAD,@OPTIONS,看名字对应的就是HEAD和OPTIONS两种请求方式,但是需要注意的一点就是Jersey没有提供针对PATCH 和 TRACE这两种请求方式的对应注解。