您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 Code iProcess 课程 角色 咨询 工具 火云堂 讲座吧   建模者  
会员   
 
   
 
  
每天15篇文章
不仅获得谋生技能
更可以追随信仰
 
     
   
 订阅
  捐助
Jersey框架
 
366 次浏览     评价:  
 2019-4-12  
 
编辑推荐:
本文来自于cnblogs,主要从Jersey RESTful WebService框架简介,Jersey对JSON的支持,Jersey对HTTPS的支持等方面详细讲解。

Jersey RESTful WebService框架简介

开发RESTful WebService意味着支持在多种媒体类型以及抽象底层的客户端-服务器通信细节,如果没有一个好的工具包可用,这将是一个困难的任务

为了简化使用Java开发RESTful WebService及其客户端,一个轻量级的标准被提出:JAX-RS API

Jersey RESTful WebService框架是一个开源的、产品级别的JAVA框架,支持JAX-RS API并且是一个JAX-RS(JSR 311和 JSR 339)的参考实现

Jersey不仅仅是一个JAX-RS的参考实现,Jersey提供自己的API,其API继承自JAX-RS,提供更多的特性和功能以进一步简化RESTful service和客户端的开发

Maven版本:3.1.0

Jersey版本:1.18

JDK版本:1.7.0_65

一,服务端

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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>JERSEY_SERVER</groupId>
<artifactId>JERSEY_SERVER</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-grizzly2</artifactId>
<version>1.18</version>
</dependency>
</dependencies>
</project>

 

首先介绍几个注解:

@Path

用来为资源类或方法定义URI,当然除了静态URI也支持动态URI

@Path("service")
public class MyResource {
@Path("{sub_path}")
@GET
public String getResource(@PathParam("sub_path") String resourceName) {
......
如果此时客户端请求的U

 

如果此时客户端请求的URI为http://127.0.0.1:10000/service/sean,则sub_path的值为sean

@PathParam用来将请求URI的一部分作为方法参数传入方法中

对URI的动态部分,可以自定义校验正则表达式,如果请求参数校验失败,容器返回404 Not Found

@Path("{sub_path:[A-Z]*}")

表明被注解的方法响应HTTP GET请求,@POST、@PUT和@DELETE同理

@Consumes

定义请求的媒体类型,如果不指定,则容器默认可接受任意媒体类型,容器负责确认被调用的方法可接受HTTP请求的媒体类型,否则返回415 Unsupported Media Type

方法级注解将覆盖类级注解

@Produces

定义响应媒体类型,如果不指定,则容器默认可接受任意媒体类型,容器负责确认被调用的方法可返回HTTP请求可以接受媒体类型,否则返回406 Not Acceptable

方法级注解将覆盖类级注解

@QueryParam

public String getResource(
@DefaultValue("Just a test!") @QueryParam("desc") String description) {
......
}

 

如果请求URI中包含desc参数,例如:http://127.0.0.1:10000/service/sean?desc=123456,则desc参数的值将会赋给方法的参数description,否则方法参数description的值将为@DefaultValue注解定义的默认值

@Context

将信息注入请求或响应相关的类,可注入的类有:Application,UriInfo,Request,HttpHeaders和SecurityContext

@Singleton和@PerRequest

默认情况下,资源类的生命周期是per-request,也就是系统会为每个匹配资源类URI的请求创建一个实例,这样的效率很低,可以对资源类使用@Singleton注解,这样在应用范围内,只会创建资源类的一个实例

服务端程序如下:

package com.sean;

import java.io.IOException;
import java.net.URI;
import java.util.Iterator;

import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.glassfish.grizzly.http.server.HttpServer;

import com.sun.jersey.api .container.grizzly2.GrizzlyServerFactory;
import com.sun.jersey.api .core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.resource.Singleton;

@Singleton
@Path("service")
public class MyResource {

@Path("{sub_path:[a-zA-Z0-9]*}")
@GET
@Consumes ({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
@Produces (MediaType.TEXT_PLAIN)
public String getResourceName(
@PathParam ("sub_path") String resourceName,
@DefaultValue ("Just a test!") @QueryParam("desc") String description,
@Context Request request,
@Context UriInfo uriInfo,
@Context HttpHeaders httpHeader) {
System.out.println (this.hashCode());

// 将HTTP请求打印出来
System.out.println ("****** HTTP request ******");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append (request.getMethod() + " ");
strBuilder.append(uriInfo.getRequestUri().toString() + " ");
strBuilder.append("HTTP/1.1[\\r\\n]");
System.out.println (strBuilder.toString());
MultivaluedMap<String, String> headers = httpHeader.getRequestHeaders();
Iterator<String> iterator = headers.keySet().iterator();
while(iterator.hasNext()){
String headName = iterator.next();
System.out.println (headName + ":" + headers.get(headName) + "[\\r\\n]");
}
System.out.println ("[\\r\\n]");
String responseStr =resourceName + "[" + description + "]";
return responseStr;
}

public static void main (String[] args) {
URI uri = UriBuilder.fromUri ("http://127.0.0.1").port (10000).build();
ResourceConfig rc = new PackagesResourceConfig ("com.sean");
try {
HttpServer server = GrizzlyServerFactory.createHttpServer (uri, rc);
server.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

 

二,客户端

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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>JERSEY_CLIENT</groupId>
<artifactId>JERSEY_CLIENT</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-grizzly2</artifactId>
<version>1.18</version>
</dependency>
</dependencies>
</project>

 

客户端程序如下:

package com.sean;

import java.net.URI;
import java.util.Iterator;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;

public class JerseyClient {

public static void main(String[] args) {
// 要使用Jersey Client API,必须首先创建Client的实例
// 有以下两种创建Client实例的方式

// 方式一
ClientConfig cc = new DefaultClientConfig();
cc.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10*1000);
// Client实例很消耗系统资源,需要重用
// 创建web资源,创建请求,接受响应都是线程安全的
// 所以Client实例和WebResource实例可以在多个线程间安全的共享
Client client = Client.create(cc);

// 方式二
// Client client = Client.create();
// client.setConnectTimeout(10*1000);
// client.getProperties().put (ClientConfig.PROPERTY _CONNECT_TIMEOUT, 10*1000);

// WebResource将会继承Client中timeout的配置
WebResource resource = client.resource("http://127.0.0.1:10000/ service/sean?desc =description");

String str = resource
.accept(MediaType.TEXT_PLAIN)
.type(MediaType.TEXT_PLAIN)
.get(String.class);
System.out.println("String:" + str);

URI uri = UriBuilder.fromUri ("http://127.0.0.1/service/sean" ).port(10000)
.queryParam ("desc", "description").build();
resource = client.resource(uri);

//header方法可用来添加HTTP头
ClientResponse response = resource.header("auth", "123456")
.accept(MediaType.TEXT_PLAIN)
.type(MediaType.TEXT_PLAIN)
.get(ClientResponse.class);
// 将HTTP响应打印出来
System.out.println ("****** HTTP response ******");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append ("HTTP/1.1 ");
strBuilder.append (response.getStatus() + " ");
strBuilder.append (response.getStatusInfo() + "[\\r\\n]");
System.out.println (strBuilder.toString());
MultivaluedMap<String, String> headers = response.getHeaders();
Iterator<String> iterator = headers.keySet().iterator();
while (iterator.hasNext()){
String headName = iterator.next();
System.out.println (headName + ":" + headers.get(headName) + "[\\r\\n]");
}
System.out.println ("[\\r\\n]");
System.out.println (response.getEntity(String.class) + "[\\r\\n]");
}
}

 

服务端日志如下:

二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.sean
二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class com.sean.Test
class com.sean.MyResource
二月 06, 2015 4:33:33 下午 com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
二月 06, 2015 4:33:33 下午 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18 11/22/2013 01:21 AM'
二月 06, 2015 4:33:34 下午 org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [127.0.0.1:10000]
二月 06, 2015 4:33:34 下午 org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.

****** HTTP request ******
GET http://127.0.0.1:10000/service/sean?desc =description HTTP/1.1[\r\n]
accept:[text/plain][\r\n]
content-type:[text/plain][\r\n]
user-agent:[Java/1.7.0_65][\r\n]
host:[127.0.0.1:10000][\r\n]
connection:[keep-alive][\r\n]
[\r\n]

****** HTTP request ******
GET http://127.0.0.1:10000/service/sean?desc =description HTTP/1.1[\r\n]
auth:[123456][\r\n]
accept:[text/plain][\r\n]
content-type:[text/plain][\r\n]
user-agent:[Java/1.7.0_65][\r\n]
host:[127.0.0.1:10000][\r\n]
connection:[keep-alive][\r\n]
[\r\n]

 

客户端日志如下:

String:sean[description]
****** HTTP response ******
HTTP/1.1 200 OK[\r\n]
Transfer-Encoding:[chunked][\r\n]
Date:[Fri, 06 Feb 2015 08:33:38 GMT][\r\n]
Content-Type:[text/plain][\r\n]
[\r\n]
sean[description][\r\n]

Jersey对JSON的支持

Jersey提供3种基本方式来使用JSON格式

无论使用何种方式,在原有包的基础上,都需要在客户端和服务端Maven配置文件中添加jersey-json包以支持JSON格式

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.18</version>
</dependency>

一,基于POJO

Request类和Response类(服务端和客户端都需要)都是基本的POJO:

package com.sean;

public class Request {
private String query;

public String getQuery() {
return query;
}

public void setQuery(String query) {
this.query = query;
}
}

package com.sean;

public class Response {
private int respCode;
private String respDesc;

public int getRespCode() {
return respCode;
}

public void setRespCode(int respCode) {
this.respCode = respCode;
}

public String getRespDesc() {
return respDesc;
}

public void setRespDesc(String respDesc) {
this.respDesc = respDesc;
}
}

 

服务端代码:

package com.sean;

import java.io.IOException;
import java.net.URI;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.grizzly.http.server.HttpServer;

import com.sun.jersey.api.container .grizzly2.GrizzlyServerFactory;
import com.sun.jersey.api.core .PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey .api.json.JSONConfiguration;

@Path("query")
public class MyResource {

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response query(Request req) {
System.out.println(req.getQuery());

Response resp = new Response();
resp.setRespCode(0);
resp.setRespDesc(req.getQuery());
return resp;
}

public static void main (String[] args) {
URI uri = UriBuilder.fromUri ("http://127.0.0.1" ).port(10000).build();
ResourceConfig rc = new PackagesResourceConfig ("com.sean");
//使用Jersey对POJO的支持,必须设置为true
rc.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
try {
HttpServer server = GrizzlyServerFactory.createHttpServer(uri, rc);
server.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

客户端代码:

package com.sean;

import javax.ws.rs.core.MediaType;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;

public class JerseyClient {

public static void main (String[] args) {
ClientConfig cc = new DefaultClientConfig();
//使用Jersey对POJO的支持,必须设置为true
cc.getFeatures().put (JSONConfiguration.FEATURE _POJO _MAPPING, Boolean.TRUE);
Client client = Client.create(cc);

WebResource resource = client.resource ("http://127.0.0.1:10000/query");

Request req = new Request();
req.setQuery ("name");

ClientResponse response = resource
.accept (MediaType.APPLICATION_JSON)
.type (MediaType.APPLICATION_JSON)
.post (ClientResponse.class, req);

Response resp = response.getEntity(Response.class);
System.out.println (resp.getRespCode() + " " + resp.getRespDesc());
}
}

二,基于JAXB

使用JAXB的优点在于,无论使用XML格式还是JSON格式数据,都可以使用统一的Java模型

缺点很难找到一个合适的方式来生成特殊的JSON格式,这也是Jersey提供很多控制选项的原因

将Request类和Response类进行修改:

package com.sean;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Request {
private String query;

public String getQuery() {
return query;
}

public void setQuery(String query) {
this.query = query;
}
}

package com.sean;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Response {
private int respCode;
private String respDesc;

public int getRespCode() {
return respCode;
}

public void setRespCode(int respCode) {
this.respCode = respCode;
}

public String getRespDesc() {
return respDesc;
}

public void setRespDesc(String respDesc) {
this.respDesc = respDesc;
}
}

服务端代码去掉下面的配置

// rc.getFeatures().put (JSONConfiguration.FEATURE _POJO_MAPPING, true);

客户端代码去掉下面的配置

// cc.getFeatures().put (JSONConfiguration.FEATURE _POJO_MAPPING, Boolean.TRUE);

Jersey提供很多控制选项以便更精细的控制JSON的解析、组装过程,但是就我个人来看,JAXB提供的标签足够使用了

三,基于底层JSONObject/JSONArray

最大的优势在于可以完全控制JSON的解析、组装过程,相应的,在处理数据对象时也要更复杂

服务端代码如下:

package com.sean;

import java.io.IOException;
import java.net.URI;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.glassfish.grizzly.http.server.HttpServer;

import com.sun.jersey.api.container.grizzly2 .GrizzlyServerFactory;
import com.sun.jersey.api.core .PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;

@Path("query")
public class MyResource {

@POST
@Consumes (MediaType.APPLICATION_JSON)
@Produce s(MediaType.APPLICATION_JSON)
public JSONObject query (JSONObject query) {
//{"query":"name"}
System.out.println (query.toString());

JSONObject resp = new JSONObject();
try {
resp.put("respCode", 0);
resp.put("respDesc", query.get("query"));
} catch (JSONException e) {
e.printStackTrace();
}
return resp;
}

public static void main (String[] args) {
URI uri = UriBuilder.fromUri ("http://127.0.0.1" ).port(10000).build();
ResourceConfig rc = new PackagesResourceConfig ("com.sean");
try {
HttpServer server = GrizzlyServerFactory.createHttpServer (uri, rc);
server.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


客户端代码如下:

package com.sean;

import javax.ws.rs.core.MediaType;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api. client.config.DefaultClientConfig;

public class JerseyClient {

public static void main(String[] args) {
ClientConfig cc = new DefaultClientConfig();
Client client = Client.create(cc);

WebResource resource = client.resource ("http://127.0.0.1:10000/query");

JSONObject req = new JSONObject();
try {
req.put ("query", "name");
} catch (JSONException e) {
e.printStackTrace();
}

ClientResponse response = resource
.accept (MediaType.APPLICATION_JSON)
.type (MediaType.APPLICATION_JSON)
.post (ClientResponse.class, req);

JSONObject resp = response.getEntity(JSONObject.class);
//{"respCode":0, "respDesc": "name"}
System.out.println(resp.toString());
}
}

与JAXB相比,结果是相同的,但是处理过程(主要是组装JSON对象)要复杂

对于上面3种方式,均可使用String类代替Request类、Response类或JSONObject类,Jersey会自动将对象转换为JSON串

当然,如果客户端修改为String,服务端也要相应的修改为String类型

修改客户端代码:

public class JerseyClient {

public static void main(String[] args) {
ClientConfig cc = new DefaultClientConfig();
Client client = Client.create(cc);

WebResource resource = client.resource ("http://127.0.0.1:10000/query");

JSONObject req = new JSONObject();
try {
req.put("query", "name");
} catch (JSONException e) {
e.printStackTrace();
}

String response = resource
.accept(MediaType.APPLICATION_JSON)
.type(MediaType.APPLICATION_JSON)
.post(String.class, req.toString());
}
}

Jersey对HTTPS的支持

证书的生成过程这里就不介绍了

代码结构如下:

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/xsd/maven -4.0.0.xsd">
<modelVersion> 4.0.0</modelVersion>
<groupId> JERSEY</groupId>
<artifactId> JERSEY</artifactId>
<version>1.0< /version>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId> jersey-client</artifactId>
<version> 1.18</version>
</dependency>
<dependency>
<groupId> com.sun.jersey</groupId>
<artifactId> jersey-grizzly2</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media </groupId>
<artifactId> jersey-media-json-jackson</artifactId>
<version> 2.15</version>
</dependency>
</dependencies>
</project>

Person类是基本的JAXB:

package com.sean;

import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Person {
private String name;
private List<String> addresses;

public Person(){}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<String> getAddresses() {
return addresses;
}

public void setAddresses(List<String> addresses) {
this.addresses = addresses;
}
}

客户端代码:

package com.sean;

import java.net.URI;

import javax.net.ssl.SSLContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.jersey.SslConfigurator;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client .config.ClientConfig;
import com.sun.jersey.api.client .config.DefaultClientConfig;
import com.sun.jersey.client .urlconnection.HTTPSProperties;

public class SSLClient {
public static void main(String[] args) {
int authType =
Integer.valueOf (Config.getConfig().getProperty ("authority")).intValue();

SslConfigurator sslConfig = SslConfigurator.newInstance();
if(authType == 1){
sslConfig.trustStoreFile (Config.getConfig().getProperty ("clientTrustCer"))
.trustStorePassword (Config.getConfig().getProperty ("clientTrustCerPwd"));
}else if(authType == 2){
sslConfig.keyStoreFile (Config.getConfig().getProperty ("clientCer"))
.keyStorePassword (Config.getConfig().getProperty ("clientCerPwd"))
.keyPassword (Config.getConfig().getProperty ("clientKeyPwd"))
.trustStoreFile (Config.getConfig().getProperty ("clientTrustCer"))
.trustStorePassword (Config.getConfig().getProperty ("clientTrustCerPwd"));
}
sslConfig.securityProtocol (Config.getConfig().getProperty ("protocol"));
SSLContext sslContext = sslConfig.createSSLContext();

ClientConfig cc = new DefaultClientConfig();
cc.getProperties().put (HTTPSProperties.PROPERTY _HTTPS_PROPERTIES,
new HTTPSProperties (new MyHostnameVerifier(), sslContext));
Client client = Client.create(cc);

URI uri = UriBuilder.fromUri ("https://127.0.0.1/ queryAddress").port(10000).build();
WebResource resource = client.resource(uri);

Person person = new Person();
person.setName ("sean");

ClientResponse response = resource
.accept (MediaType.APPLICATION_XML)
.type (MediaType.APPLICATION_XML)
.post (ClientResponse.class, person);

String addresses = response.getEntity(String.class);
System.out.println (addresses);
}
}

SSL握手过程中,会对请求IP或请求域名进行校验,如果在证书信息中无法找到相关请求IP或请求域名则会报错(javax.NET.ssl.SSLHandshakeException: Java.security.cert.CertificateException: No subject alternative names present)

这里实现自己的校验逻辑(如果请求的IP为127.0.0.1或请求的域名为localhost,则直接通过校验)以覆盖默认逻辑

package com.sean;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

public class MyHostnameVerifier implements HostnameVerifier {

@Override
public boolean verify(String hostname, SSLSession session) {
if("127.0.0.1".equals(hostname) || "localhost".equals(hostname) )
return true;
else
return false;
}
}


服务端代码:

package com.sean;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.jersey.SslConfigurator;

import com.sun.jersey.api.container .ContainerFactory;
import com.sun.jersey.api.container.grizzly2 .GrizzlyServerFactory;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;

@Path("queryAddress")
public class SSLServer {

@POST
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public Person queryAddress(String name) {
System.out.println(name);

Person person = new Person();
List<String> addresses = new ArrayList<String>();
addresses.add("address1");
addresses.add("address2");
person.setAddresses(addresses);
return person;
}

public static void main(String[] args) {
Integer authType =
Integer.valueOf (Config.getConfig().getProperty ("authority")).intValue();

SslConfigurator sslConfig = SslConfigurator.newInstance();
if(authType == 1){
sslConfig.keyStoreFile (Config.getConfig().getProperty ("serverCer"))
.keyStorePassword (Config.getConfig().getProperty ("serverCerPwd"))
.keyPassword (Config.getConfig().getProperty ("serverKeyPwd"));
}else if(authType == 2){
sslConfig.keyStoreFil e (Config.getConfig().getProperty ("serverCer"))
.keyStorePassword (Config.getConfig().getProperty ("serverCerPwd"))
.keyPassword (Config.getConfig().getProperty ("serverKeyPwd"))
.trustStoreFile (Config.getConfig().getProperty ("serverTrustCer"))
.trustStorePassword (Config.getConfig().getProperty ("serverTrustCerPwd"));
}
sslConfig.securityProtocol (Config.getConfig().getProperty ("protocol"));
SSLContext sslContext = sslConfig.createSSLContext();

SSLEngineConfigurator sslEngineConfig = new SSLEngineConfigurator (sslContext);
//默认情况下是客户端模式,如果忘记修改模式
//会抛出异常
//javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 1]
sslEngineConfig.setClientMode (false);
if(authType == 1)
sslEngineConfig .setWantClientAuth(true);
else if (authType == 2)
sslEngineConfig.setNeedClientAuth (true);

ResourceConfig rc = new PackagesResourceConfig ("com.sean");
HttpHandler handler = ContainerFactory.createContainer(
HttpHandler.class, rc);

URI uri = UriBuilder.fromUri ("https://127.0.0.1/") .port(10000).build();
try {
HttpServer server = GrizzlyServerFactory.createHttpServer (uri, handler, true,
sslEngineConfig);
server.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

配置文件类:

package com.sean;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

public class Config{
private static Properties config;

public static Properties getConfig(){
try{
if(null == config){
File configFile =
new File ("src/main/resources/config/config.properties");
if(configFile.exists() && configFile.isFile()
&& configFile.canRead()){
InputStream input = new FileInputStream(configFile);
config = new Properties();
config.load(input);
}
}
}catch(Exception e){
//default set
config = new Properties();
config.setProperty ("authority", String.valueOf(1));
config.setProperty ("protocol", "SSL");
config.setProperty ("serverCer", "src/main/resources/certificate/server.jks");
config.setProperty ("serverCerPwd", "1234sp");
config.setProperty ("serverKeyPwd", "1234kp");
config.setProperty ("serverTrustCer", "src/main/resources/certificate/serverTrust.jks");
config.setProperty ("serverTrustCerPwd", "1234sp");
config.setProperty ("clientCer", "src/main/resources/certificate/client.jks");
config.setProperty ("clientCerPwd", "1234sp");
config.setProperty ("clientKeyPwd", "1234kp");
config.setProperty ("clientTrustCer", "src/main/resources/certificate/clientTrust.jks");
config.setProperty ("clientTrustCerPwd", "1234sp");
}
return config;
}
}

配置文件config.properties:

#1:单向认证,只有服务器端需证明其身份
#2:双向认证,服务器端和客户端都需证明其身份
authority=2
#通信协议
protocol=SSL
#服务端证书信息
serverCer= src/main/resources/certificate/server.jks
#keystore的storepass
serverCerPwd=1234sp
#keystore的keypass
serverKeyPwd= 1234kp
#服务端证书信息
serverTrustCer= src/main/resources/certificate/serverTrust.jks
serverTrustCerPwd= 1234sp
#客户端证书信息
clientCer= src/main/resources/certificate/client.jks
clientCerPwd= 1234sp
clientKeyPwd= 1234kp
clientTrustCer= src/main/resources/certificate/clientTrust.jks
clientTrustCerPwd=1234sp

服务端运行结果:

三月 03, 2015 3:30:54 下午 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.sean
三月 03, 2015 3:30:54 下午 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class com.sean.SSLServer
三月 03, 2015 3:30:54 下午 com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
三月 03, 2015 3:30:54 下午 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.18 11/22/2013 01:21 AM'
三月 03, 2015 3:30:55 下午 org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [127.0.0.1:10000]
三月 03, 2015 3:30:55 下午 org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><person><name>sean</name></person>

客户端运行结果

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <person> <addresses>address1</addresses> <addresses>address2 </addresses></person>


   
366 次浏览  评价: 差  订阅 捐助
相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
每天2个文档/视频
扫描微信二维码订阅
订阅技术月刊
获得每月300个技术资源
 
 

关于我们 | 联系我们 | 京ICP备10020922号 京公海网安备110108001071号