我有一个使用Spring MVC Framework的简单Restful Web服务。当我从浏览器运行它时,我没有问题;它工作正常。我接下来做的是使用RestTemplate和JUnit创建一个Restful Client。除了一种方法,我的所有方法都能正常工作。这是将对象添加到集合的方法。我可以看到我正确填充对象,但是当对象到达服务器(tomcat 8.x)时,对象的属性为null。
这是我的测试客户端。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import com.baml.rdhs.model.Issuer;
import junit.framework.TestCase;
//@FixMethodOrder(MethodSorters.NAME_ASCENDING)
/* This annotation is for builds
* This allows for the maven build and deploy
* before running the integration tests
*/
@Category(IntegrationTest.class)
public class TestSpringRestClient extends TestCase {
public static final String SERVER_URI = "http://localhost:8080/datahubservice";
private static final Logger logger = LoggerFactory.getLogger(TestSpringRestClient.class);
private static final String ticker = "IBM";
private static Issuer issuer = null;
protected void setUp() {
issuer = new Issuer();
issuer.setCountry("USA");
issuer.setTicker("IBM");
issuer.setIssuerType("corp");
issuer.setIssuerName("International Business Machines");
}
@Test
public static void testGetHome() {
RestTemplate restTemplate = new RestTemplate();
String results = null;
results = restTemplate.getForObject(SERVER_URI + "/", String.class);
assertNotNull(results);
if (results != null) {
logger.info("Inside testGetHome, returned: " + results);
} else {
logger.info("Inside testGetHome, home NOT FOUND!");
}
}
@Test
public static void testGetIssuerByTicker() {
RestTemplate restTemplate = new RestTemplate();
Issuer myIssuer = null;
myIssuer = restTemplate.getForObject(SERVER_URI + "/issuer/" + ticker, Issuer.class);
assertNotNull(myIssuer);
if (myIssuer != null) {
logger.info("Inside testGetIssuerByTicker, returned: " + myIssuer.toString());
} else {
logger.info("Inside testGetIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
}
}
@SuppressWarnings("unchecked")
@Test
public static void testGetAllIssuers() {
RestTemplate restTemplate = new RestTemplate();
Map<String, Issuer> results = null;
results = restTemplate.getForObject(SERVER_URI + "/issuers", Map.class);
assertNotNull(results);
if (results != null) {
logger.info("Inside testGetAllIssuers, returned: " + results.toString());
} else {
logger.info("Inside testGetAllIssuers, results: NOT FOUND!");
}
}
@Test
public static void testDeleteIssuerByTicker() {
RestTemplate restTemplate = new RestTemplate();
Issuer myIssuer = null;
myIssuer = restTemplate.getForObject(SERVER_URI + "/issuer/delete/" + ticker, Issuer.class);
assertNotNull(myIssuer);
if (myIssuer != null) {
logger.info("Inside testDeleteIssuerByTicker, returned: " + myIssuer.toString());
} else {
logger.info("Inside testDeleteIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
}
}
@Test
public static void testAddIssuerByTicker() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getMessageConverters());
Issuer myIssuer = null;
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<Issuer> entity = new HttpEntity<Issuer>(issuer, headers);
logger.info("Adding issuer:" + issuer.toString());
//myIssuer = restTemplate.postForObject(SERVER_URI + "/issuer/addIssuer", issuer, Issuer.class);
ResponseEntity<Issuer> resource = restTemplate.exchange(SERVER_URI + "/issuer/addIssuer", HttpMethod.POST, entity, Issuer.class);
myIssuer = resource.getBody();
assertNotNull(myIssuer);
if (myIssuer != null) {
logger.info("Inside testAddIssuerByTicker, returned: " + myIssuer.toString());
} else {
logger.info("Inside testAddIssuerByTicker, myIssuer: " + myIssuer + ", NOT FOUND!");
}
}
private static List<HttpMessageConverter<?>> getMessageConverters() {
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingJackson2HttpMessageConverter());
return converters;
}
}
这是我的RestController:
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.baml.rdhs.model.Issuer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
/**
* Handles requests for the application home page.
*/
@Api(value="issuers", description="Issuers API")
@Controller
public class RestController {
/*
* Place holder for service class
*/
private static final Logger logger = LoggerFactory.getLogger(RestController.class);
private Map<String, Issuer> issuers = new HashMap<String, Issuer>();
public RestController() {
// pre-initialize the list of issuers available ...
issuers.put("ATEN", new Issuer("ATEN", "A10 Networks Inc", "corp", "USA"));
issuers.put("AAPL", new Issuer("AAPL", "Apple Inc", "corp", "USA"));
issuers.put("T", new Issuer("T", "AT&T", "corp", "USA"));
issuers.put("CSCO", new Issuer("CSCO", "Cisco Systems, Inc.", "corp", "USA"));
issuers.put("CTXS", new Issuer("CTXS", "Citrix Systems, Inc.", "corp", "USA"));
issuers.put("GOOGL", new Issuer("GOOGL", "Google Inc", "corp", "USA"));
issuers.put("IBM", new Issuer("IBM", "IBM", "corp", "USA"));
issuers.put("JNPR", new Issuer("JNPR", "Juniper Networks, Inc.", "corp", "USA"));
issuers.put("MSFT", new Issuer("MSFT", "Microsoft Corporation", "corp", "USA"));
issuers.put("ORCL", new Issuer("ORCL", "Oracle Corporation", "corp", "USA"));
}
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
@ApiOperation(value="Home screen",
notes="This is a test url whereby one can test the service is up and running.", response=String.class)
@ApiResponses(value= {@ApiResponse(code=201, message="Hello world!", response=String.class),
@ApiResponse(code=500, message="Error reaching the web service")})
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "status";
}
@RequestMapping(value="/issuers", method=RequestMethod.GET)
@ResponseBody
@ApiOperation(value="Fetch all Issuers",
notes="This returns a listing of all Issures currently held in the application.", response=Map.class)
public Map<String, Issuer> getAllIssuers() {
logger.info("Inside getAllIssuers() method...");
try {
String mapAsJson = new ObjectMapper().writeValueAsString(issuers);
logger.info("Issuers returned: " + mapAsJson);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return issuers;
}
@RequestMapping(value="/issuer/{ticker}", method=RequestMethod.GET)
@ResponseBody
@ApiOperation(value="One one Issuer record",
notes="This method searches the Map of all Issuers for one record based upon the ticker.", response=String.class)
public Issuer getIssuerByTicker(@PathVariable("ticker") String ticker) {
Issuer myIssuer = issuers.get(ticker);
if (myIssuer != null) {
logger.info("Inside getIssuerByTicker, returned: " + myIssuer.toString());
} else {
logger.info("Inside getIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
}
return myIssuer;
}
@RequestMapping(value="/issuer/delete/{ticker}", method=RequestMethod.GET)
@ResponseBody
public Issuer deleteIssuerByTicker(@PathVariable("ticker") String ticker) {
Issuer myIssuer = issuers.remove(ticker);
if (myIssuer != null) {
logger.info("Inside deleteIssuerByTicker, deleted: " + myIssuer.toString());
} else {
logger.info("Inside deleteIssuerByTicker, ticker: " + ticker + ", NOT FOUND!");
}
return myIssuer;
}
@RequestMapping(value="/issuer/create", method=RequestMethod.GET)
public ModelAndView addIssuer() {
return new ModelAndView("addIssuer", "command", new Issuer());
}
@RequestMapping(value="/issuer/addIssuer", method=RequestMethod.POST)
@ResponseBody
public Issuer addIssuer(@ModelAttribute("issuer") Issuer issuer) {
logger.info("Issuer received from client" + issuer);
if (issuer != null) {
logger.info("Inside addIssuer, adding: " + issuer.toString());
} else {
logger.info("Inside addIssuer...");
}
if(issuer.getTicker()!= null)
issuers.put(issuer.getTicker(), issuer);
return issuer;
}
}
这是我从测试客户端发送的对象:
public class Issuer implements Serializable {
@JsonIgnore
private static final long serialVersionUID = 4260711945094777831L;
@JsonProperty
private String ticker;
@JsonProperty
private String issuerName;
@JsonProperty
private String issuerType;
@JsonProperty
private String country;
public Issuer() {
}
public Issuer(String ticker, String issuerName, String issuerType, String country) {
setTicker(ticker);
setIssuerName(issuerName);
setIssuerType(issuerType);
setCountry(country);
}
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
public String getIssuerName() {
return issuerName;
}
public void setIssuerName(String issuerName) {
this.issuerName = issuerName;
}
public String getIssuerType() {
return issuerType;
}
public void setIssuerType(String issuerType) {
this.issuerType = issuerType;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String toString() {
return "[" + getTicker()
+ ", " + getIssuerName()
+ ", " + getIssuerType()
+ ", " + getCountry()
+ "]";
}
}
这是我的调度员 - servlet:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- for processing requests with annotated controller methods and set Message Converters from the list of converters -->
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<!-- To convert JSON to Object and vice versa -->
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="prefixJson" value="false" />
<beans:property name="supportedMediaTypes" value="application/json" />
</beans:bean>
<context:component-scan base-package="com.baml.rdhs" />
</beans:beans>
任何建议都将不胜感激。
拉斯
更新:
我重新运行测试,这是日志输出:
[main] INFO com.baml.rdhs.test.integration.TestSpringRestClient - 添加发行人:[IBM,International Business Machines,corp,USA]
[main] INFO com.baml.rdhs.test.util.LoggerInterceptor - -------------发送请求-------------
[main] INFO com.baml.rdhs.test.util.LoggerInterceptor - with body -----:{“ticker”:“IBM”,“issuerName”:“International Business Machines”,“issuerType”: “corp”,“country”:“USA”} --------
[main] INFO com.baml.rdhs.test.util.LoggerInterceptor - 和headers ---:{Accept = [application / json,application / * + json],Content-Type = [application / json],内容长度= [99]}
[main] INFO com.baml.rdhs.test.util.LoggerInterceptor - 响应头是:{Server = [Apache-Coyote / 1.1],Content-Type = [application / json],Transfer-Encoding = [chunked ],日期= [星期二,2015年12月15日16:45:12 GMT]}
[main] INFO com.baml.rdhs.test.integration.TestSpringRestClient - 在testAddIssuerByTicker内部,返回:[null,null,null,null]
答案 0 :(得分:1)
您在执行content-type
请求时应设置POST
标题。
@Test
public static void testAddIssuerByTicker() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getMessageConverters());
Issuer myIssuer = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Issuer> entity = new HttpEntity<Issuer>(issuer, headers);
logger.info("Adding issuer:" + issuer.toString());
//myIssuer = restTemplate.postForObject(SERVER_URI + "/issuer/addIssuer", issuer, Issuer.class);
ResponseEntity<Issuer> resource = restTemplate.exchange(SERVER_URI + "/issuer/addIssuer", HttpMethod.POST, entity, Issuer.class);
myIssuer = resource.getBody();
assertNotNull(myIssuer);
if (myIssuer != null) {
logger.info("Inside testAddIssuerByTicker, returned: " + myIssuer.toString());
} else {
logger.info("Inside testAddIssuerByTicker, myIssuer: " + myIssuer + ", NOT FOUND!");
}
}
更新调试:
我建议调试RestTemplate
确切发送的内容:
public class LoggerInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggerInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
logger.info("------------- sending request ------------- " );
if(!request.getMethod().equals(HttpMethod.GET)){
logger.info("with body ----- : \n " + new String(body) + " --------");
}
logger.info("\n and headers --- :\n "+ request.getHeaders());
ClientHttpResponse response = execution.execute(request, body);
logger.info("response headers are : " + response.getHeaders());
return response;
}
}
并将拦截器添加到RestTemplate
:
public RestTemplate getTemplate() {
RestTemplate template = new RestTemplate();
ClientHttpRequestFactory requestFactory =
new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
template.setRequestFactory(requestFactory);
List<ClientHttpRequestInterceptor> interceptors = new LinkedList<ClientHttpRequestInterceptor>();
LoggerInterceptor logger = new LoggerInterceptor();
interceptors.add(logger);
template.setInterceptors(interceptors);
return template;
}
当您手动创建RestTemplate
时,请替换getTemplate()
并使用调试信息更新您的问题。
更新
最后我看到了问题所在。您不需要在addIssuer()方法中使用@ModelAttribute。将其替换为@RequestBody,以便从请求正文中读取对象。将模型公开给Web视图时使用@modelattribute。