Spring REST服务:从请求检索JSON

我正在Spring 3.1上构建REST服务。我为此使用@EnableWebMVC注释。由于我的服务将仅接受JSON请求,因此我也想将传入的请求转储到MongoDB集合中以进行日志记录(以及以后的数据转换)。我想访问原始JSON请求(我可以在使用“ @Content HttpServletRequest请求”作为方法参数的非spring实现中进行此操作)。

我是Spring新手。因此,请帮助我指导实现这一目标。谢谢!

更新:该问题尚未完全解决。只有我的GET测试有效。POST失败。因此,取消选中接受的答案

问题是,即使创建了HttpServletRequestWrapper,也无法在处理并包装请求后转发请求。这是发生了什么:

拦截器:

public class DBLogInterceptor extends HandlerInterceptorAdapter {

MyRequestWrapper requestWrapper;

private final static Logger logger = Logger.getLogger(DBLogInterceptor.class);

@Override

public boolean preHandle(

HttpServletRequest request,

HttpServletResponse response,

Object handler) throws Exception

{

requestWrapper = new MyRequestWrapper(request);

// Code removed, but it just dumps requestWrapper.getBody() into DB

return super.preHandle(requestWrapper, response, handler);

}

}

HTTP POST服务方法

@RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")

@ResponseBody

public String updateEntity(@RequestBody Employee emp) {

// Do some DB Stuff. Anyway, the control flow does not reach this place.

return "Employee " + emp.getName() + " updated successfully!";

}

现在,无论何时发送POST都会得到一个异常:

12:04:53,821 DEBUG DBLogInterceptor:22 - {"name":"Van Damme","dept":"Applied Martial Arts"}

12:04:53,843 DEBUG RequestResponseBodyMethodProcessor:117 - Reading [com.test.webapp.login.domain.Employee] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@154174f9]

12:04:53,850 DEBUG ExceptionHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Stream closed

12:04:53,854 DEBUG ResponseStatusExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Streamclosed

12:04:53,854 DEBUG DefaultHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Streamclosed

12:04:53,859 DEBUG DispatcherServlet:910 - Could not complete request

java.io.IOException: Stream closed

at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:312)

at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:200)

at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:507)

at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:129)

at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:224)

at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:785)

at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:561)

at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1914)

at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:124)

at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)

at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:120)

at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:91)

at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:71)

at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)

at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)

at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)

at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)

at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)

at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)

at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)

at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

我希望HttpServletRequestWrapper能够照顾到缓存请求。但这不会以某种方式发生。

回答:

使用HttpServletRequest对象,你可以访问客户端用于发出请求的URL,使用的方法(GET,POST,PUT等),查询字符串和标头。

获取RequestBody可能会有些棘手,并且可能需要使用HttpServletRequestWrapper对象。由于请求正文只能被读取一次,因此你需要扩展包装器以访问它,以便你的目标控制器以后仍可以访问它,以将JSON反序列化为POJO对象。

public class MyRequestWrapper extends HttpServletRequestWrapper {

private final String body;

public MyRequestWrapper(HttpServletRequest request) throws IOException {

super(request);

StringBuilder stringBuilder = new StringBuilder();

BufferedReader bufferedReader = null;

try {

InputStream inputStream = request.getInputStream();

if (inputStream != null) {

bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

char[] charBuffer = new char[128];

int bytesRead = -1;

while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {

stringBuilder.append(charBuffer, 0, bytesRead);

}

} else {

stringBuilder.append("");

}

} catch (IOException ex) {

throw ex;

} finally {

if (bufferedReader != null) {

try {

bufferedReader.close();

} catch (IOException ex) {

throw ex;

}

}

}

body = stringBuilder.toString();

}

@Override

public ServletInputStream getInputStream() throws IOException {

final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());

ServletInputStream servletInputStream = new ServletInputStream() {

public int read() throws IOException {

return byteArrayInputStream.read();

}

};

return servletInputStream;

}

@Override

public BufferedReader getReader() throws IOException {

return new BufferedReader(new InputStreamReader(this.getInputStream()));

}

public String getBody() {

return this.body;

}

}

要在中央位置访问请求,可以使用过滤器或Spring拦截器。这两个请求都在将请求委派给控制器之前被调用,并且都可以访问servlet。

这是一个使用Spring Interceptor的实际记录示例:

package com.vaannila.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.BasicConfigurator;

import org.apache.log4j.Logger;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.handler. HandlerInterceptorAdapter;

public class LoggerInterceptor extends HandlerInterceptorAdapter {

static Logger logger = Logger.getLogger(LoggerInterceptor.class);

static {

BasicConfigurator.configure();

}

@Override

public boolean preHandle(HttpServletRequest request,

HttpServletResponse response, Object handler) throws Exception {

logger.info("Before handling the request");

return super.preHandle(request, response, handler);

}

@Override

public void postHandle(HttpServletRequest request,

HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

logger.info("After handling the request");

super.postHandle(request, response, handler, modelAndView);

}

@Override

public void afterCompletion(HttpServletRequest request,

HttpServletResponse response, Object handler, Exception ex)

throws Exception {

logger.info("After rendering the view");

super.afterCompletion(request, response, handler, ex);

}

}

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="viewResolver" class="org.springframework.web.servlet.view. InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

<bean id="handlerMapping" class="org.springframework.web.servlet.handler. BeanNameUrlHandlerMapping" p:interceptors-ref="loggerInterceptor" />

<bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />

<bean id="userService" class="com.vaannila.service.UserServiceImpl" />

<bean name="/userRegistration.htm" class="com.vaannila.web.UserController" p:userService-ref="userService" p:formView="userForm" p:successView="userSuccess" />

</beans>

在LoggerInterceptor中,你可以使用以下代码访问请求:

MyRequestWrapper myRequestWrapper = new MyRequestWrapper((HttpServletRequest) request);

String body = myRequestWrapper.getBody();

String clientIP = myRequestWrapper.getRemoteHost();

int clientPort = request.getRemotePort();

String uri = myRequestWrapper.getRequestURI();

System.out.println(body);

System.out.println(clientIP);

System.out.println(clientPort);

System.out.println(uri);

以上是 Spring REST服务:从请求检索JSON 的全部内容, 来源链接: utcz.com/qa/400573.html

回到顶部