Maven和Jersey Framework开发REST风格Web Service

本文详细介绍在Eclipse中创建并配置Maven Web项目的步骤,解决常见错误,如Servlet类未找到的问题,以及如何更新项目facets。同时,演示如何使用Jersey RESTful框架创建、读取、更新和删除Web服务资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果你的eclipse中没有安装Maven插件。

  1. 在eclipse中创建Maven项目
    在这里插入图片描述

2.单击"Next"
在这里插入图片描述

  1. 选择Maven项目类型为"maven-archetype-webapp"
    在这里插入图片描述

  2. 输入项目相关的Maven设置
    在这里插入图片描述

  3. 分别创建src/main下java文件夹以及src下test文件夹

  4. 设置src/main/java和src/test/java为source folder

  5. 最终设置结果如下:
    在这里插入图片描述
    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);

  1. 修改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>
  1. 添加基本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;
         }
         
     }
  1. 添加一个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格式输出。
  1. 运行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这两种请求方式的对应注解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值