您的位置:首页 > 其它

Web Service笔记(五):CXF开发RESTful风格的Web Service

2014-11-26 21:30 537 查看
前言:

1、Web Service笔记(五):利用CXF结合Spring开发web service

2、XML学习笔记(三):Jaxb负责xml与javaBean映射

3、jax-rs详解

4、可以使用浏览器的工具调试:如 Firefox 的RESTClient 和chrome的REST Console。

一、配置Spring的配置文件

1、需要引入新的 jar 包。



2、配置 applicationContext-server.xml 文件。使用 jaxrs:server ,记得引入jaxrs 的schema 约束。

1)address:为地址,如 http://localhost:8080/Java_WS_Server/rest/ 2)serviceBeans:暴露的ws服务类。也可以使用“#beanId”,引入。

<!-- REST WebService 接口-->
<jaxrs:server id="restfulServer" address="/rest">
<jaxrs:inInterceptors>
</jaxrs:inInterceptors>
<jaxrs:serviceBeans>
<bean class="cn.rest.rest.SurpolicyEntrence"></bean>
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>
<jaxrs:languageMappings>
<entry key="en" value="en-gb"/>
</jaxrs:languageMappings>
</jaxrs:server>


二、Restful 服务类需要实现jax_rs规范。就像ws的服务类需要实现jax_ws规范一样。
1、在 javax.ws.rs.* 中定义,都是一些注解,是 JAX-RS (JSR 311) 规范的一部分。

2、具体的注解如下:

1)@Path:定义资源基 URI。由上下文根和主机名组成,如:

http://localhost:8080/Java_WS_Server/rest/surpolicy


2)@GET/@POST:这意味着以下方法可以响应 HTTP GET 或是 HTTP POST方法。

3)@Produces:响应内容 MIME 类型。如

@Produces(MediaType.TEXT_PLAIN)
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })


4)@Context: 使用该注释注入上下文对象,比如 Request、Response、UriInfo、ServletContext 等。

@Context HttpServletRequest servletRequest
@Context HttpServletResponse servletResponse
@Context
private UriInfo uriInfo;


5)@PathParam("contact"):该注释将参数注入方法参数的路径。其他可用的注释有 @FormParam、@QueryParam 等。

3、一般来说,服务类与方法上应该分别标注注解 @Path,用于区分访问路径。

@Path(value = "/surpolicy")
public class SurpolicyEntrence {}
@Path("/sendXml")
public String sendXml(String requestXML) {}


三、简单的 RESTful 服务

1、服务类代码:

/**
* 简单服务方法
* @param input
* 访问地址:http://localhost:8080/Java_WS_Server/rest/surpolicy/sendString/queryParams_aa
* @return
*/
@GET
@Path("/sendString/{input}")
// @Produces("text/plain")
@Produces(MediaType.TEXT_PLAIN)
public String sendStringParam(@PathParam("input") String input) {
System.out.println("接收的参数: \r\n" + input);
String tReturn = "成功返回";
return tReturn;

}


启动服务后,访问 http://localhost:8080/Java_WS_Server,有Available RESTful services的内容,说明发布成功。



2、分析:

1)前提:服务类的path定义为如下,故所有的方法的访问地址都为
http://localhost:8080/Java_WS_Server/rest/surpolicy/ + "方法自己的地址"。/rest 为在配置文件中配置的address地址

@Path(value = "/surpolicy")
public class SurpolicyEntrence {}


2)@Path("/sendString/{input}") :用浏览器的rest 工具访问的时候,必须把参数放在url地址后面。如:

http://localhost:8080/Java_WS_Server/rest/surpolicy/sendString/queryParams_aa


3)访问的结果如下:



后台显示:表示成功。返回的信息可以在 RestClient 中查看。

接收的参数:
queryParams_aa


3、客户端代码:本文中的客户端统一使用 org.apache.cxf.jaxrs.client.WebClient 实现。

其他实现方式见:

HTTP访问的两种方式(HttpClient和HttpURLConnection)

利用HttpURLConnection和WebClient发布REST风格的WebService客户端(解决超时问题)

1)WebClient 可以使用spring注入,也可以手工创建:

// 手动创建webClient对象,注意这里的地址是发布的那个/rest地址
// String url = "http://localhost:8080/Java_WS_Server/rest/";
// client = WebClient.create(url);

// 从Spring Ioc容器中拿webClient对象,或者直接用注入
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");
client = ctx.getBean("webClient", WebClient.class);


使用spring,需要配置 applicationContext-client.xml 代码:

<bean id="webClient" class="org.apache.cxf.jaxrs.client.WebClient" factory-method="create">
<constructor-arg type="java.lang.String" value="http://localhost:8080/Java_WS_Server/rest/" />
</bean>


2)先初始化 webClient对象

public void init() {
// 手动创建webClient对象,注意这里的地址是发布的那个/rest地址
// String url = "http://localhost:8080/Java_WS_Server/rest/";
// client = WebClient.create(url);

// 从Spring Ioc容器中拿webClient对象,或者直接用注入
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");
client = ctx.getBean("webClient", WebClient.class);

}


3)简单服务的访问方法:

/**
* 测试服务端的简单方法
*/
public void sendString(){
String tResponseMsg = client.path("surpolicy/ping/{input}","我来ping一下。。").accept(MediaType.TEXT_PLAIN).get(String.class);
System.out.println(tResponseMsg);
}


4)显示:

服务端:
接收的参数:
我来ping一下。。

客户端:
成功返回


四、以XML为交互内容的 RESTful 服务

(一)需要使用 jaxb 来映射Xml与javaBean。

1、接收的javaBean 代码。

package cn.rest.bean;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

/**
*
* UserBean.java
*
* @title User的传输数据类
* @description
* @author SAM-SHO
* @Date 2014-11-25
*/

@XmlRootElement(name = "USER")
public class UserBean {
private String name;
private String age;
private UserAddress userAddress;//地址
private List<UserPhone> phoneList ;//手机

@XmlElement(name="NAME")
public String getName() {
return name;
}

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

@XmlElement(name = "AGE")
public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}

@XmlElement(name = "UserAddress")
public UserAddress getUserAddress() {
return userAddress;
}

public void setUserAddress(UserAddress userAddress) {
this.userAddress = userAddress;
}

@XmlElementWrapper(name = "PhoneList")
@XmlElement(name = "UserPhone")
public List<UserPhone> getPhoneList() {
return phoneList;
}

public void setPhoneList(List<UserPhone> phoneList) {
this.phoneList = phoneList;
}

}
package cn.rest.bean;

public class UserPhone {

private String type;//电话号码类型
private String num;//电话号码

public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}

}


package cn.rest.bean;

import javax.xml.bind.annotation.XmlElement;

public class UserAddress {

private String homeAddress;//家庭地址
private String workAddress;//公司地址

@XmlElement(name = "HomeAddress")
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}

@XmlElement(name = "WorkAddress")
public String getWorkAddress() {
return workAddress;
}
public void setWorkAddress(String workAddress) {
this.workAddress = workAddress;
}

}


2、返回的javaBean 代码。

package cn.rest.bean.response;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* 返回商城退保结果对象
* @author SAM
*
*/
@XmlRootElement(name = "RETURN")
public class ReturnDTO  {

protected String code;
protected String msg;

@XmlElement(name="Code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@XmlElement(name="MSG")
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}

}


3、转换工具类。

package cn.rest.util;
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.xml.sax.InputSource;
import cn.rest.bean.UserBean;

/**
*
* ObjectAndXmlHandle.java
*
* @title jaxb处理xml解析
* @description
* @author SAM-SHO
* @Date 2014-11-25
*/
public class ObjectAndXmlHandle {

public static UserBean parseXml2OUserBean(String xml) {
try {
JAXBContext context = JAXBContext.newInstance(UserBean.class);
InputSource is = new InputSource();
StringReader xmlStr = new StringReader(xml);
is.setCharacterStream(xmlStr);
Unmarshaller unmarshaller = context.createUnmarshaller();
UserBean user = (UserBean) unmarshaller.unmarshal(is);
return user;
} catch (JAXBException e) {
e.printStackTrace();
return null;
}
}

public static void Object2Xml(Object object) {
//		FileWriter writer = null;
try {
JAXBContext context = JAXBContext.newInstance(object.getClass());
Marshaller marshal = context.createMarshaller();
marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshal.setProperty("jaxb.encoding", "utf-8");
marshal.marshal(object, System.out);

//	        writer = new FileWriter("shop.xml");
//	        marshal.marshal(object, writer);
} catch (Exception e) {
e.printStackTrace();
}
}
}


(二)、服务端方法代码

1、把 xml 以 String 的方法传输。

/**
* 接受XML ,推荐使用。
* 地址:http://localhost:8080/Java_WS_Server/rest/surpolicy/sendXml
* 设置 Content-Type: APPLICATION/XML(可以不设)
* body 中设置 xml内容
*/
@POST
@Path("/sendXml")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public String sendXml(String requestXML) {
System.out.println("接收的参数:\r\n " + requestXML);

UserBean tUserBean = ObjectAndXmlHandle.parseXml2OUserBean(requestXML);

String tReturn = tUserBean.getName()+ " 你好,你的请求成功返回";
return tReturn;
}


2、RESTClient 工具访问,xml放在 Body 中,可以不设置 Content-Type



3、客户端访问代码:

/**
* 发送XML报文
*/
private void sendRequestXml() {
String tRequestXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><USER><AGE>27</AGE><NAME>SAM-SHO</NAME><PhoneList><UserPhone><num>13612345678</num><type>移动</type></UserPhone><UserPhone><num>13798765432</num><type>联通</type></UserPhone></PhoneList><UserAddress><homeAddress>苏州高新区</homeAddress><workAddress>苏州园区</workAddress></UserAddress></USER>";
String tResponseMsg = client.path("surpolicy/sendXml").accept(MediaType.APPLICATION_XML).post(tRequestXml, String.class);
System.out.println("返回的信息: \r\n" + tResponseMsg);
}


五、以JavaBean为交互内容的 RESTful 服务

1、服务端方法代码

/**
*接收Bean
*
* @param user
* http://localhost:8080/Java_WS_Server/rest/surpolicy/sendBean * 需要设置 Content-Type: application/xml
* body 中设置 xml内容
* @return
*/
@POST
@Path("/sendBean")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ReturnDTO sendBean(UserBean user) {

//转成报文
ObjectAndXmlHandle.Object2Xml(user);
System.out.println(user.getUserAddress().getHomeAddress());

ReturnDTO tReturnDTO = new ReturnDTO();
tReturnDTO.setCode("1");
tReturnDTO.setMsg(user.getName()+ " ,请求成功,已返回");

return tReturnDTO;
}


2、RESTClient访问

1)一定要设置 headers信息,设置 Content-Type: application/xml ,不然访问不了。



2)需要设置 Content-Type。



3)正确访问:



5)成功返回:



3、客户端访问:

/**
* 发送Bean
*/
private void sendRequestBean() {
UserBean tUserBean = new UserBean();
tUserBean.setName("SAM-SHO");
tUserBean.setAge("27");

UserAddress tUserAddress = new UserAddress();
tUserAddress.setWorkAddress("苏州园区");
tUserAddress.setHomeAddress("苏州高新区");
tUserBean.setUserAddress(tUserAddress);

List<UserPhone> phoneList = new ArrayList<UserPhone>();
UserPhone tUserPhone =  new UserPhone();
tUserPhone.setType("移动");
tUserPhone.setNum("13612345678");
phoneList.add(tUserPhone);

tUserPhone =  new UserPhone();
tUserPhone.setType("联通");
tUserPhone.setNum("13798765432");
phoneList.add(tUserPhone);
tUserBean.setPhoneList(phoneList);

ClientConfiguration config = WebClient.getConfig(client);
config.getHttpConduit().getClient().setReceiveTimeout(90000);//设置超时
ReturnDTO tReturnDTO = client.path("surpolicy/sendBean").accept(MediaType.APPLICATION_XML).acceptEncoding("utf-8").post(tUserBean,ReturnDTO.class );

System.out.println("返回的数据:" + tReturnDTO.getMsg());

}


六、服务端与客户端完整代码如下:

1、服务端

package cn.rest.rest;

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

import cn.rest.bean.UserBean;
import cn.rest.bean.response.ReturnDTO;
import cn.rest.util.ObjectAndXmlHandle;

/**
*
* SurpolicyEntrence.java
*
* @title CXF RESTful风格WebService
* @description
* @author SAM-SHO
* @Date 2014-11-24
*/
@Path(value = "/surpolicy")
public class SurpolicyEntrence {

/**
* 简单服务方法
* @param input
* 访问地址:http://localhost:8080/Java_WS_Server/rest/surpolicy/sendString/queryParams_aa
* @return
*/
@GET
@Path("/sendString/{input}")
// @Produces("text/plain")
@Produces(MediaType.TEXT_PLAIN)
public String sendStringParam(@PathParam("input") String input) {
System.out.println("接收的参数: \r\n" + input);
String tReturn = "成功返回";
return tReturn;

}

/**
* 接受XML ,推荐使用。
* 地址:http://localhost:8080/Java_WS_Server/rest/surpolicy/sendXml
* 设置 Content-Type: APPLICATION/XML(可以不设)
* body 中设置 xml内容
*/
@POST
@Path("/sendXml")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public String sendXml(String requestXML) {
System.out.println("接收的参数:\r\n " + requestXML);

UserBean tUserBean = ObjectAndXmlHandle.parseXml2OUserBean(requestXML);

String tReturn = tUserBean.getName()+ " 你好,你的请求成功返回";
return tReturn;
}

/**
*接收Bean
*
* @param user
* http://localhost:8080/Java_WS_Server/rest/surpolicy/sendBean * 需要设置 Content-Type: application/xml
* body 中设置 xml内容
* @return
*/
@POST
@Path("/sendBean")
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public ReturnDTO sendBean(UserBean user) {

//转成报文
ObjectAndXmlHandle.Object2Xml(user);
System.out.println(user.getUserAddress().getHomeAddress());

ReturnDTO tReturnDTO = new ReturnDTO();
tReturnDTO.setCode("1");
tReturnDTO.setMsg(user.getName()+ " ,请求成功,已返回");

return tReturnDTO;
}
}


2、客户端

package cn.rest.client;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.core.MediaType;

import org.apache.cxf.jaxrs.client.ClientConfiguration;
import org.apache.cxf.jaxrs.client.WebClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.rest.bean.UserAddress;
import cn.rest.bean.UserBean;
import cn.rest.bean.UserPhone;
import cn.rest.bean.response.ReturnDTO;

public class RestClient {

private static WebClient client;

/**
* @param args
*/
public static void main(String[] args) {
RestClient tRestClient = new RestClient();
tRestClient.init();

//1-简单测试
//		tRestClient.sendString();

// 2-发送XML报文
//		tRestClient.sendRequestXml();

// 2-发送Bean
tRestClient.sendRequestBean();
}

public void init() {
// 手动创建webClient对象,注意这里的地址是发布的那个/rest地址
// String url = "http://localhost:8080/Java_WS_Server/rest/";
// client = WebClient.create(url);

// 从Spring Ioc容器中拿webClient对象,或者直接用注入
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");
client = ctx.getBean("webClient", WebClient.class);

}

/**
* 测试服务端的简单方法
*/
public void sendString(){
String tResponseMsg = client.path("surpolicy/sendString/{input}","我来ping一下。。").accept(MediaType.TEXT_PLAIN).get(String.class);
System.out.println(tResponseMsg);
}

/**
* 发送XML报文
*/
private void sendRequestXml() {
String tRequestXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><USER><AGE>27</AGE><NAME>SAM-SHO</NAME><PhoneList><UserPhone><num>13612345678</num><type>移动</type></UserPhone><UserPhone><num>13798765432</num><type>联通</type></UserPhone></PhoneList><UserAddress><homeAddress>苏州高新区</homeAddress><workAddress>苏州园区</workAddress></UserAddress></USER>";
String tResponseMsg = client.path("surpolicy/sendXml").accept(MediaType.APPLICATION_XML).post(tRequestXml, String.class);
System.out.println("返回的信息: \r\n" + tResponseMsg);
}

/**
* 发送Bean
*/
private void sendRequestBean() {
UserBean tUserBean = new UserBean();
tUserBean.setName("SAM-SHO");
tUserBean.setAge("27");

UserAddress tUserAddress = new UserAddress();
tUserAddress.setWorkAddress("苏州园区");
tUserAddress.setHomeAddress("苏州高新区");
tUserBean.setUserAddress(tUserAddress);

List<UserPhone> phoneList = new ArrayList<UserPhone>();
UserPhone tUserPhone =  new UserPhone();
tUserPhone.setType("移动");
tUserPhone.setNum("13612345678");
phoneList.add(tUserPhone);

tUserPhone =  new UserPhone();
tUserPhone.setType("联通");
tUserPhone.setNum("13798765432");
phoneList.add(tUserPhone);
tUserBean.setPhoneList(phoneList);

ClientConfiguration config = WebClient.getConfig(client);
config.getHttpConduit().getClient().setReceiveTimeout(90000);//设置超时
ReturnDTO tReturnDTO = client.path("surpolicy/sendBean").accept(MediaType.APPLICATION_XML).acceptEncoding("utf-8").post(tUserBean,ReturnDTO.class );

System.out.println("返回的数据:" + tReturnDTO.getMsg());

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: