前言
这几天公司新项目用要搭建一个基于spring和jersey实现的Restful webservice,maven环境是沿用的以前项目的pom,整个过程弄了半天才弄好,记录下来以备翻看,也为偶尔路过的朋友提供一份参考,不足之处敬请谅解
开发环境 eclipse Kepler + tomcat7 + jdk1.7 + maven
什么是Restful
REST指的是一组架构约束条件和原则,满足这些原则的应用或者设计就叫Restful, Restful描述了一个架构样式的互联系统(如 Web 应用程序)。REST 约束条件应用于一个整体应用时,将生成一个简单、可扩展、有效、安全、可靠的架构。
Restful原则:
1.HTTP直接传输数据
2.所有操作是无状态的
3.所有网络上的事物都可以抽象为一个资源(resource)
4,每一个资源都有唯一的URI
WEB环境配置
由于我们要实现的是JAX-RS2.0,JSR311标准(和JAX-RS1.x区别很大),eclipse->project facets选项里选择如下图
- JAX-RS2.0需要最少JDK1.7版本的支持
- web项目版本需要3.1版本,由于Tomcat7.0不能发布3.1的web模组,所以我是通过更改项目的.settings文件来实现的,此处有一个问题,即更改了项目的buildpath和编译等级为1.7版本,仍然无法选中JAX-RS为2.0,报需要JDK1.7的支持,直到删除项目,重新导入才算OK
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>mmp</display-name>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</context-param>
<servlet>
<servlet-name>jerseyrs</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.zzrh.mmp.rest.RestInit</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jerseyrs</servlet-name>
<!--rest服务接口匹配路径-->
<url-pattern>/service>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
Maven
由于沿用了之前项目的pom,导致jar包环境比较混乱也用了些时间整理,项目启动起来,大多数是报NosuchMethodExcption,ClassNotFoundException,最终整合出一个稳定的版本。此处需要注意的是,JAX-RS2.0和JAX-RS1.X 区别很大,jar包支持方面差别也很大,所以尽量从头配置pom避免一些不必要的异常。
pom.xml 标红部分为jersey rest配置
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.10</junit.version>
<log4j.version>1.2.14</log4j.version>
<mysql.jdbc.version>5.1.21</mysql.jdbc.version>
<spring.version>4.1.7.RELEASE</spring.version>
<mybatis.version>3.2.5</mybatis.version>
<mybatis.spring.version>1.2.3</mybatis.spring.version>
<mina.core.version>2.0.9</mina.core.version>
<commons.lang.version>2.6</commons.lang.version>
<commons.fileupload.version>1.3.1</commons.fileupload.version>
<tomcat.jdbc.version>7.0.63</tomcat.jdbc.version>
<asm.version>3.3.1</asm.version>
<org.json.version>20140107</org.json.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>${mina.core.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat.jdbc.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.danga</groupId>
<artifactId>java-memcached</artifactId>
<version>2.6.3</version>
</dependency>
<!-- commons配置 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons.lang.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<!-- ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
<dependency>
<groupId>com.googlecode.ehcache-spring-annotations</groupId>
<artifactId>ehcache-spring-annotations</artifactId>
<version>1.2.0</version>
</dependency>
<!-- json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${org.json.version}</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.8</version>
</dependency>
<!-- mysql的依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.jdbc.version}</version>
</dependency>
<!-- mybatis的依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>0.7</version>
</dependency>
<!-- GZip -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>0.7</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
<!--jersey--></span>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.2</version>
</dependency>
<!--JAXB API-->
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.1</version>
</dependency>
<!-- Json支持 -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.12</version>
</dependency>
</dependencies></project>
<!-- jersey end -->
代码
Ok,环境配好了,下一步我们需要设置servlet的配置类,如图中所标注的,我们已经在web.xml里配置了这个servlet
<servlet>
<servlet-name>jerseyrs</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</span></param-name>
<param-value>com.zzrh.mmp.rest.RestInit</span></param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
对应的启动类定义如下:
/**
*
* <pre>
* @author {zhangsheng}
*
* </pre>
*/
public class RestInit extends ResourceConfig {
public RestInit() {
packages("com.zzrh.mmp.controller");//包路径下符合要求的类将被发布成webservice
register(LoggingFilter.class);//注册logger
register(JacksonJsonProvider.class);//注册json支持
}
}
现在我们就可以发布webservice服务了,
新建一个类和方法,指定@Path等注解
/**
* register
*/
@POST
@Path("register")
@Consumes("application/x-www-form-urlencoded")
public void register(@BeanParam User user) {
Map<String,Object> map = this.getReturnMap();
//register process
user.setUserName("already register");
map.put("msg", "success!");
map.put("user", user);
HtmlUtil.writerJson(response, map);
}
注解解释:
请求方法类型@POST,
请求路径@Path,
接受请求MIMETYPE@Consumes,
方法产生MIMETYPE@Produces
JAX-RS2.0带来的好处之一 @BeanParam注解,可以将HTTP请求传来的参数封装到javabean或DTO里,springmvc,struts formbean都可以实现类似功能
如果想在方法上使用@BeanParam,需要在对应的model或DTO里加上@XmlRootElement,并且属性也要加上相应注解
package com.zzrh.mmp.rest;
import javax.ws.rs.FormParam;
import javax.ws.rs.PathParam;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private String userName;
@FormParam("name")
private String name;
private String telephone;
@FormParam("email")
private String email;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
进行测试,点击go to register发送post请求到rest接口
此处有一个问题,即ajax提交的contentType默认为 application/x-www-form-urlencoded;charset=UTF-8;这样的话jersey容器是无法接到请求参数的,所以需要改造一下,
1.前端可以直接指定contentType
2。后台方式需要配置在web.xml里配置filter来改变请求头,此处不再展开
function register(){
$.ajax({
url:"http://127.0.0.1:8080/webservice/service/userInfo/register",
type:'POST',
contentType:"<span style="color:#ff6666;">application/x-www-form-urlencoded</span>"
data: $("#form1").serialize(),
success: function(data){
alert(data.msg + " userName is " +data.user.userName);
}
});
}
总结: 搭建JAX-RS2.0 webservice的过程遇到问题最多的是jar包的混乱,另外项目需要开发工具和容器的支持,有鉴于目前一些公司都没有升级开发环境,所以对于使用jersey2.X实现的JAX-RS2.0(JSR311标准)来说,用处其实有限,尤其是在springmvc和webservice,RPC框架相当流行的今天,只是多一种选择罢了,JAX-RS2可以指定接收和返回类型,做一些项目之间的跨工程通讯还算方便,尤其是在JAVA项目之间。