HttpMessageConverter未将对象转换为Json

时间:2015-12-11 16:07:48

标签: json spring spring-mvc spring-rest

我有一个使用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]

1 个答案:

答案 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。