有没有办法配置 ClientBuilder POST 请求,使其能够接收 return 代码和 JSON 对象?
Is there a way to configure the ClientBuilder POST request that would enable it to receive both a return code AND a JSON object?
假设 "postWS" 调用 "postRespWS"...
"postWS"s GET 方法(非SpringMVC)利用 JAX-RS "ClientBuilder" 发出对 "postRespWS" 中的 POST 方法的调用(SpringMVC) ...
(注意:"postRespWS"的POST方法应该return既是return代码又是JSON对象)
问题: 为了响应 POST 调用,"postWS" 收到成功的 return 代码(即“200”)- 但是,不是 预期的 JSON 对象...
-即,响应不包括以下 JSON 对象...
{
"entryAToList": [
{
"errorCode": "100",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000AX",
"accepted": true
},
{
"errorCode": "200",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000BX",
"accepted": true
},
{
"errorCode": "300",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000CX",
"accepted": true
}
],
"entryBToList": [
{
"errorCode": "101",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000AZ",
"accepted": false
},
{
"errorCode": "201",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000BZ",
"accepted": false
},
{
"errorCode": "301",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000CZ",
"accepted": false
}
]
}
问题:
有没有办法在 "postWS"s POST 请求中配置 ClientBuilder,使其能够同时接收 return 代码 和 JSON 对象 - 即 return 由 "postRespWS"?
编辑
更详细的注释,如下...
"postWS"的GET方法是这样的...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.Arrays;
import javax.ejb.Stateless;
import javax.ws.rs.client.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Stateless
@Path("/postservice")
public class PostService {
-
-
-
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public PostRespDTO get() {
//curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
// {
// "entryAList":["ITEM0000A","ITEM0000B","ITEM0000C"],
// "entryBList":["AAA","BBB","CCC"]
// }
PostDTO postDTO = new PostDTO();
postDTO.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A","ITEM0000B","ITEM0000C")));
postDTO.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
PostRespDTO prd = new PostRespDTO();
try {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
prd = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON), PostRespDTO.class);
} catch (Exception e) {
LOG.error("________99__________get()__________________e.getMessage()=" + e.getMessage(), e);
}
//...NOTE: "prd" does not contain the expected JSON object that is returned by "postRespWS"...
return prd;
}
-
-
-
}
"postRespWS"的POST(Spring基于MVC的)方法如下所示(注意:此方法中的代码不能被修改)...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class PostRespService {
-
-
-
@RequestMapping(value = {"/postrespservice"}, method = RequestMethod.POST)
@ResponseBody
public PostRespDTO post(@RequestBody PostDTO postDTO) {
PostRespDTO postRespDTO = new PostRespDTO();
if (postDTO != null && postDTO.getEntryAList() != null) {
try {
List<PostRespDetailA> nonDeletedList = new ArrayList<>();
List<PostRespDetailA> deletedList = new ArrayList<>();
PostRespDetailA prda = new PostRespDetailA();
int i = 100;
for (String s : postDTO.getEntryAList()) {
prda = new PostRespDetailA();
prda.setErrorCode(String.valueOf(i));
prda.setErrorMessage("blah...blah...blah...");
prda.setEntryNumber(s+"X");
prda.setAccepted(true);
deletedList.add(prda);
prda = new PostRespDetailA();
prda.setErrorCode(String.valueOf(i + 1));
prda.setErrorMessage("bleah...bleah...bleah...");
prda.setEntryNumber(s+"Z");
prda.setAccepted(false);
nonDeletedList.add(prda); //adding to both - just for testing...
i+=100;
}
postRespDTO.getEntryAToList().addAll(deletedList);
postRespDTO.getEntryBToList().addAll(nonDeletedList);
} catch (Exception e) {
LOG.error("________________________removeEntryFromStmt________________________Exception - e.getMessage()=" + e.getMessage(), e);
}
}
return postRespDTO;
}
-
-
-
}
* PostDTO.java *
package aaa.bbb.ccc.ws;
import java.io.Serializable;
import java.util.List;
public class PostDTO {
private List<String> entryAList;
private List<String> entryBList;
public List<String> getEntryAList() {
return entryAList;
}
public void setEntryAList(List<String> entryAList) {
this.entryAList = entryAList;
}
public List<String> getEntryBList() {
return entryBList;
}
public void setEntryBList(List<String> entryBList) {
this.entryBList = entryBList;
}
}
* PostRespDTO *
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.List;
public class PostRespDTO {
private List<PostRespDetailA> entryAToList;
private List<PostRespDetailA> entryBToList;
public List<PostRespDetailA> getEntryAToList() {
if (null == entryAToList) {
entryAToList = new ArrayList<>();
}
return entryAToList;
}
public List<PostRespDetailA> getEntryBToList() {
if (null == entryBToList) {
entryBToList = new ArrayList<>();
}
return entryBToList;
}
}
* PostRespDetailA.java *
package aaa.bbb.ccc.ws;
public class PostRespDetailA {
private boolean isAccepted;
private String errorCode;
private String errorMessage;
private String entryNumber;
public void setAccepted(boolean accepted){
this.isAccepted = accepted;
}
public boolean isAccepted(){
return this.isAccepted;
}
public void setErrorCode(String errorCode){
this.errorCode = errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
public void setErrorMessage(String errorMessage){
this.errorMessage = errorMessage;
}
public String getErrorMessage(){
return this.errorMessage;
}
public String getEntryNumber(){
return entryNumber;
}
public void setEntryNumber(String entryNumnber){
this.entryNumber = entryNumnber;
}
}
* PostRespDetailB.java *
package aaa.bbb.ccc.ws;
import aaa.bbb.ccc.ws.WSConstants.WSEnum;
public class PostRespDetailB {
private String entryNumnber;
private WSEnum wsEnum;
public PostRespDetailB(String entryNumnber, WSEnum wsEnum) {
this.entryNumnber = entryNumnber;
this.wsEnum = null; //wsEnum;
}
public String getEntryNumnber() {
return entryNumnber;
}
public void setEntryNumnber(String entryNumnber) {
this.entryNumnber = entryNumnber;
}
public WSEnum getWSEnum() {
return wsEnum;
}
public void setWSEnum(WSEnum wsEnum) {
this.wsEnum = wsEnum;
}
}
对 "postWS" 的测试调用,看起来像这样...
$ curl -v -k -X GET http://10.162.188.159:7001/postWS/resources/postservice
输出看起来像这样...
$ curl -v -k -X GET http://localhost:7001/postWS/resources/postservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> GET /postWS/resources/postservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept: */*
>
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Thu, 21 Jan 2016 19:56:20 GMT
< Content-Length: 2
< Content-Type: application/json
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
* Expire cleared
{}
直接对"postRespWS"的测试调用,看起来像这样...
curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
输出看起来像这样...
$ curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> POST /postRespWS/postrespservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept: */*
> Content-Type: application/json
> Content-Length: 85
>
* upload completely sent off: 85 out of 85 bytes
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Thu, 21 Jan 2016 20:40:27 GMT
< Transfer-Encoding: chunked
< Content-Type: application/json;charset=UTF-8
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
* Expire cleared
{"entryAToList":[{"errorCode":"100","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000AX","accepted":true},{"errorCode":"200","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000BX","accepted":true},{"errorCode":"300","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000CX","accepted":true}],"entryBToList":[{"errorCode":"101","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000AZ","accepted":false},{"errorCode":"201","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000BZ","accepted":false},{"errorCode":"301","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000CZ","accepted":false}]}
请注意直接调用此 POST 方法 return 如何同时使用 return 代码 (200) 和 JSON 对象...
- 有没有办法在 "postWS" 中配置 ClientBuilder 以获得相同的结果???
环境:Java7,WebLogic 12.1.3 w/"jax-rs(2.0,2.5.1)"可部署库
"postWS"的pom.xml
<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>aaa.bbb.ccc.ws</groupId>
<artifactId>postWS</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>postWS</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- You need this for Java EE support... -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.0-rc1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
<type>jar</type>
</dependency>
</dependencies>
<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
"postRespWS"的pom.xml
<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>aaa.bbb.ccc</groupId>
<artifactId>postRespWS</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>postRespWS</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
<type>jar</type>
</dependency>
</dependencies>
<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
感谢您的帮助!!
P.S.
此外,我注意到...
...当使用 "curl" 直接调用 post 并且 JSON 对象是 returned ...
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
...当通过 "postWS"(使用 ClientBuilfer)调用 post 并且 JSON 对象不是 returned...
Content-Length: 2
Content-Type: application/json
根据最近的建议,我修改了客户端代码如下...
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON));
prd = response.readEntity(PostRespDTO.class);
int status = response.getStatus();
...但是,结果没有变化...即,我收到响应代码(“200”),但是无法 see/access JSON 对象.
我设法同时收到响应代码 和 JSON 对象的唯一方法是利用 "older" 技术(不使用 ClientBuilder )...
(还不确定从中推断出什么)。 -此外,使用默认的 jax-rs 版本重新配置 WebLogic,而不是可部署的 jax-rs(2.0/2.5) 运行 库。
对 pom.xml 的更改:
-
-
-
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
-
-
-
代码更改...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.Arrays;
import javax.ejb.Stateless;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Stateless
@Path("/postservice")
public class PostService {
private static final Logger LOG = LogManager.getLogger("PostService");
public PostService() {
}
@GET
//@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON})
public PostRespDTO get() {
PostDTO postDTO = new PostDTO();
postDTO.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C")));
postDTO.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
PostRespDTO prd = new PostRespDTO();
try {
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("http://localhost:7001/postRespWS/postrespservice");
ClientResponse response = webResource.accept("application/json").type("application/json").post(ClientResponse.class, postDTO);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
prd = response.getEntity(PostRespDTO.class);
} catch (Exception e) {
LOG.error("__________________get()__________________e.getMessage()=" + e.getMessage(), e);
}
return prd;
}
}
输出(使用 curl)如下所示...
$ curl -v -k -X GET -HAccept:application/json http://localhost:7001/postWS/resources/postservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> GET /postWS/resources/postservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept:application/json
>
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Fri, 22 Jan 2016 22:56:54 GMT
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
{"entryAToList":[{"errorCode":"100","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000AX","accepted":true},{"errorCode":"200","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000BX","accepted":true},{"errorCode":"300","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000CX","accepted":true}],"entryBToList":[{"errorCode":"101","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000AZ","accepted":false},{"errorCode":"201","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000BZ","accepted":false},{"errorCode":"301","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000CZ","accepted":false}]}
可以得到回复,见SyncInvoker#post(Entity):
Invoke HTTP POST method for the current request synchronously.
Returns:
invocation response.
您可以从响应中获取实体,请参阅 Response#readEntity(Class):
Read the message entity input stream as an instance of specified Java type using a MessageBodyReader
that supports mapping the message entity stream onto the requested type.
但您需要为 JSON 注册提供商,请参阅 Configurable#register(Class):
Register a class of a custom JAX-RS component (such as an extension provider or a feature
meta-provider) to be instantiated and used in the scope of this configurable context.
正确的提供商取决于 JAX-RS 实施(Jersey, Apache CXF, Resteasy,...), model implementation (POJO, JAX-B, ...), content type (JSON, XML, text, ...) and processor implementation (Jackson, JSON-P, Jettison,...)
你修改的例子:
Client client = ClientBuilder.newBuilder().register(providerClass).build();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON));
prd = response.readEntity(PostRespDTO.class);
int status = response.getStatus();
还要确保您的 PostRespDTO
符合 Java Bean conventions,包含 getter 和 setter 方法。
假设 "postWS" 调用 "postRespWS"...
"postWS"s GET 方法(非SpringMVC)利用 JAX-RS "ClientBuilder" 发出对 "postRespWS" 中的 POST 方法的调用(SpringMVC) ...
(注意:"postRespWS"的POST方法应该return既是return代码又是JSON对象)
问题: 为了响应 POST 调用,"postWS" 收到成功的 return 代码(即“200”)- 但是,不是 预期的 JSON 对象...
-即,响应不包括以下 JSON 对象...
{
"entryAToList": [
{
"errorCode": "100",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000AX",
"accepted": true
},
{
"errorCode": "200",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000BX",
"accepted": true
},
{
"errorCode": "300",
"errorMessage": "blah...blah...blah...",
"entryNumber": "ITEM0000CX",
"accepted": true
}
],
"entryBToList": [
{
"errorCode": "101",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000AZ",
"accepted": false
},
{
"errorCode": "201",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000BZ",
"accepted": false
},
{
"errorCode": "301",
"errorMessage": "bleah...bleah...bleah...",
"entryNumber": "ITEM0000CZ",
"accepted": false
}
]
}
问题: 有没有办法在 "postWS"s POST 请求中配置 ClientBuilder,使其能够同时接收 return 代码 和 JSON 对象 - 即 return 由 "postRespWS"?
编辑更详细的注释,如下...
"postWS"的GET方法是这样的...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.Arrays;
import javax.ejb.Stateless;
import javax.ws.rs.client.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Stateless
@Path("/postservice")
public class PostService {
-
-
-
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public PostRespDTO get() {
//curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
// {
// "entryAList":["ITEM0000A","ITEM0000B","ITEM0000C"],
// "entryBList":["AAA","BBB","CCC"]
// }
PostDTO postDTO = new PostDTO();
postDTO.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A","ITEM0000B","ITEM0000C")));
postDTO.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
PostRespDTO prd = new PostRespDTO();
try {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
prd = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON), PostRespDTO.class);
} catch (Exception e) {
LOG.error("________99__________get()__________________e.getMessage()=" + e.getMessage(), e);
}
//...NOTE: "prd" does not contain the expected JSON object that is returned by "postRespWS"...
return prd;
}
-
-
-
}
"postRespWS"的POST(Spring基于MVC的)方法如下所示(注意:此方法中的代码不能被修改)...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class PostRespService {
-
-
-
@RequestMapping(value = {"/postrespservice"}, method = RequestMethod.POST)
@ResponseBody
public PostRespDTO post(@RequestBody PostDTO postDTO) {
PostRespDTO postRespDTO = new PostRespDTO();
if (postDTO != null && postDTO.getEntryAList() != null) {
try {
List<PostRespDetailA> nonDeletedList = new ArrayList<>();
List<PostRespDetailA> deletedList = new ArrayList<>();
PostRespDetailA prda = new PostRespDetailA();
int i = 100;
for (String s : postDTO.getEntryAList()) {
prda = new PostRespDetailA();
prda.setErrorCode(String.valueOf(i));
prda.setErrorMessage("blah...blah...blah...");
prda.setEntryNumber(s+"X");
prda.setAccepted(true);
deletedList.add(prda);
prda = new PostRespDetailA();
prda.setErrorCode(String.valueOf(i + 1));
prda.setErrorMessage("bleah...bleah...bleah...");
prda.setEntryNumber(s+"Z");
prda.setAccepted(false);
nonDeletedList.add(prda); //adding to both - just for testing...
i+=100;
}
postRespDTO.getEntryAToList().addAll(deletedList);
postRespDTO.getEntryBToList().addAll(nonDeletedList);
} catch (Exception e) {
LOG.error("________________________removeEntryFromStmt________________________Exception - e.getMessage()=" + e.getMessage(), e);
}
}
return postRespDTO;
}
-
-
-
}
* PostDTO.java *
package aaa.bbb.ccc.ws;
import java.io.Serializable;
import java.util.List;
public class PostDTO {
private List<String> entryAList;
private List<String> entryBList;
public List<String> getEntryAList() {
return entryAList;
}
public void setEntryAList(List<String> entryAList) {
this.entryAList = entryAList;
}
public List<String> getEntryBList() {
return entryBList;
}
public void setEntryBList(List<String> entryBList) {
this.entryBList = entryBList;
}
}
* PostRespDTO *
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.List;
public class PostRespDTO {
private List<PostRespDetailA> entryAToList;
private List<PostRespDetailA> entryBToList;
public List<PostRespDetailA> getEntryAToList() {
if (null == entryAToList) {
entryAToList = new ArrayList<>();
}
return entryAToList;
}
public List<PostRespDetailA> getEntryBToList() {
if (null == entryBToList) {
entryBToList = new ArrayList<>();
}
return entryBToList;
}
}
* PostRespDetailA.java *
package aaa.bbb.ccc.ws;
public class PostRespDetailA {
private boolean isAccepted;
private String errorCode;
private String errorMessage;
private String entryNumber;
public void setAccepted(boolean accepted){
this.isAccepted = accepted;
}
public boolean isAccepted(){
return this.isAccepted;
}
public void setErrorCode(String errorCode){
this.errorCode = errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
public void setErrorMessage(String errorMessage){
this.errorMessage = errorMessage;
}
public String getErrorMessage(){
return this.errorMessage;
}
public String getEntryNumber(){
return entryNumber;
}
public void setEntryNumber(String entryNumnber){
this.entryNumber = entryNumnber;
}
}
* PostRespDetailB.java *
package aaa.bbb.ccc.ws;
import aaa.bbb.ccc.ws.WSConstants.WSEnum;
public class PostRespDetailB {
private String entryNumnber;
private WSEnum wsEnum;
public PostRespDetailB(String entryNumnber, WSEnum wsEnum) {
this.entryNumnber = entryNumnber;
this.wsEnum = null; //wsEnum;
}
public String getEntryNumnber() {
return entryNumnber;
}
public void setEntryNumnber(String entryNumnber) {
this.entryNumnber = entryNumnber;
}
public WSEnum getWSEnum() {
return wsEnum;
}
public void setWSEnum(WSEnum wsEnum) {
this.wsEnum = wsEnum;
}
}
对 "postWS" 的测试调用,看起来像这样...
$ curl -v -k -X GET http://10.162.188.159:7001/postWS/resources/postservice
输出看起来像这样...
$ curl -v -k -X GET http://localhost:7001/postWS/resources/postservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> GET /postWS/resources/postservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept: */*
>
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Thu, 21 Jan 2016 19:56:20 GMT
< Content-Length: 2
< Content-Type: application/json
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
* Expire cleared
{}
直接对"postRespWS"的测试调用,看起来像这样...
curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
输出看起来像这样...
$ curl -v -k -H "Content-Type: application/json" -X POST -d "{\"entryAList\":[\"ITEM0000A\",\"ITEM0000B\",\"ITEM0000C\"],\"entryBList\":[\"AAA\",\"BBB\",\"CCC\"]}" http://localhost:7001/postRespWS/postrespservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> POST /postRespWS/postrespservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept: */*
> Content-Type: application/json
> Content-Length: 85
>
* upload completely sent off: 85 out of 85 bytes
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Thu, 21 Jan 2016 20:40:27 GMT
< Transfer-Encoding: chunked
< Content-Type: application/json;charset=UTF-8
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
* Expire cleared
{"entryAToList":[{"errorCode":"100","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000AX","accepted":true},{"errorCode":"200","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000BX","accepted":true},{"errorCode":"300","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000CX","accepted":true}],"entryBToList":[{"errorCode":"101","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000AZ","accepted":false},{"errorCode":"201","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000BZ","accepted":false},{"errorCode":"301","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000CZ","accepted":false}]}
请注意直接调用此 POST 方法 return 如何同时使用 return 代码 (200) 和 JSON 对象... - 有没有办法在 "postWS" 中配置 ClientBuilder 以获得相同的结果???
环境:Java7,WebLogic 12.1.3 w/"jax-rs(2.0,2.5.1)"可部署库
"postWS"的pom.xml
<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>aaa.bbb.ccc.ws</groupId>
<artifactId>postWS</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>postWS</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- You need this for Java EE support... -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.0-rc1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
<type>jar</type>
</dependency>
</dependencies>
<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
"postRespWS"的pom.xml
<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>aaa.bbb.ccc</groupId>
<artifactId>postRespWS</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>postRespWS</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
<type>jar</type>
</dependency>
</dependencies>
<build>
<finalName>${project.name}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
感谢您的帮助!!
P.S.
此外,我注意到...
...当使用 "curl" 直接调用 post 并且 JSON 对象是 returned ...
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
...当通过 "postWS"(使用 ClientBuilfer)调用 post 并且 JSON 对象不是 returned...
Content-Length: 2
Content-Type: application/json
根据最近的建议,我修改了客户端代码如下...
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON));
prd = response.readEntity(PostRespDTO.class);
int status = response.getStatus();
...但是,结果没有变化...即,我收到响应代码(“200”),但是无法 see/access JSON 对象.
我设法同时收到响应代码 和 JSON 对象的唯一方法是利用 "older" 技术(不使用 ClientBuilder )... (还不确定从中推断出什么)。 -此外,使用默认的 jax-rs 版本重新配置 WebLogic,而不是可部署的 jax-rs(2.0/2.5) 运行 库。
对 pom.xml 的更改:
-
-
-
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
-
-
-
代码更改...
package aaa.bbb.ccc.ws;
import java.util.ArrayList;
import java.util.Arrays;
import javax.ejb.Stateless;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Stateless
@Path("/postservice")
public class PostService {
private static final Logger LOG = LogManager.getLogger("PostService");
public PostService() {
}
@GET
//@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON})
public PostRespDTO get() {
PostDTO postDTO = new PostDTO();
postDTO.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C")));
postDTO.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));
PostRespDTO prd = new PostRespDTO();
try {
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);
WebResource webResource = client.resource("http://localhost:7001/postRespWS/postrespservice");
ClientResponse response = webResource.accept("application/json").type("application/json").post(ClientResponse.class, postDTO);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
prd = response.getEntity(PostRespDTO.class);
} catch (Exception e) {
LOG.error("__________________get()__________________e.getMessage()=" + e.getMessage(), e);
}
return prd;
}
}
输出(使用 curl)如下所示...
$ curl -v -k -X GET -HAccept:application/json http://localhost:7001/postWS/resources/postservice
* STATE: INIT => CONNECT handle 0x80047810; line 1034 (connection #-5000)
* Hostname was NOT found in DNS cache
* Trying ::1...
* STATE: CONNECT => WAITCONNECT handle 0x80047810; line 1087 (connection #0)
* Connected to localhost (::1) port 7001 (#0)
* STATE: WAITCONNECT => DO handle 0x80047810; line 1233 (connection #0)
> GET /postWS/resources/postservice HTTP/1.1
> User-Agent: curl/7.38.0
> Host: localhost:7001
> Accept:application/json
>
* STATE: DO => DO_DONE handle 0x80047810; line 1319 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x80047810; line 1445 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x80047810; line 1458 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Fri, 22 Jan 2016 22:56:54 GMT
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* STATE: PERFORM => DONE handle 0x80047810; line 1628 (connection #0)
* Connection #0 to host localhost left intact
{"entryAToList":[{"errorCode":"100","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000AX","accepted":true},{"errorCode":"200","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000BX","accepted":true},{"errorCode":"300","errorMessage":"blah...blah...blah...","entryNumber":"ITEM0000CX","accepted":true}],"entryBToList":[{"errorCode":"101","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000AZ","accepted":false},{"errorCode":"201","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000BZ","accepted":false},{"errorCode":"301","errorMessage":"bleah...bleah...bleah...","entryNumber":"ITEM0000CZ","accepted":false}]}
可以得到回复,见SyncInvoker#post(Entity):
Invoke HTTP POST method for the current request synchronously.
Returns: invocation response.
您可以从响应中获取实体,请参阅 Response#readEntity(Class):
Read the message entity input stream as an instance of specified Java type using a
MessageBodyReader
that supports mapping the message entity stream onto the requested type.
但您需要为 JSON 注册提供商,请参阅 Configurable#register(Class):
Register a class of a custom JAX-RS component (such as an extension provider or a
feature
meta-provider) to be instantiated and used in the scope of this configurable context.
正确的提供商取决于 JAX-RS 实施(Jersey, Apache CXF, Resteasy,...), model implementation (POJO, JAX-B, ...), content type (JSON, XML, text, ...) and processor implementation (Jackson, JSON-P, Jettison,...)
你修改的例子:
Client client = ClientBuilder.newBuilder().register(providerClass).build();
WebTarget target = client.target("http://localhost:7001/postRespWS/postrespservice");
Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(postDTO, MediaType.APPLICATION_JSON));
prd = response.readEntity(PostRespDTO.class);
int status = response.getStatus();
还要确保您的 PostRespDTO
符合 Java Bean conventions,包含 getter 和 setter 方法。