Je construis un service REST sur Spring 3.1. J'utilise l'annotation @EnableWebMVC pour cela. Étant donné que mon service n'acceptera que les requêtes JSON, je souhaite également vider la requête entrante dans une collection MongoDB pour la journalisation (et, ultérieurement, pour la transformation des données). J'aimerais accéder à la requête JSON brute (ce que je pouvais faire avec une implémentation non-print en utilisant "@Content HttpServletRequest request" comme paramètre de méthode).
Je suis un débutant au printemps. Alors, aidez-moi gentiment avec les instructions pour y parvenir. Merci!
UPDATE: Le problème n'est pas complètement résolu. Seuls mes tests avec GET ont fonctionné. Il échoue avec POST. Donc décoché la réponse acceptée
Le problème est que, même si je crée un HttpServletRequestWrapper, je ne peux pas transférer la demande après avoir traité et emballé la demande. Voici ce qui se passe:
Intercepteur:
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 Méthode de traitement
@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!";
}
Maintenant, je reçois une exception chaque fois que j'envoie un 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)
Je m'attendais à ce que HttpServletRequestWrapper
s'occupe de la mise en cache de la demande. Mais cela n'arrive pas d'une manière ou d'une autre.
En utilisant l'objet HttpServletRequest , vous pouvez accéder à l'URL utilisée par le client pour effectuer la demande, à la méthode utilisée (GET, POST, PUT, etc.), à la chaîne de requête et aux en-têtes.
Obtenir le RequestBody peut être un peu plus compliqué et nécessiter l'utilisation de l'objet HttpServletRequestWrapper . Etant donné que le corps de la demande ne peut être lu qu'une seule fois, vous devez étendre l'encapsuleur pour y accéder, de sorte que votre contrôleur cible puisse toujours y accéder ultérieurement pour désérialiser votre JSON en objets 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;
}
}
Pour accéder aux demandes dans un emplacement central, vous pouvez utiliser un filtre ou un intercepteur de ressort. Ces deux éléments sont appelés avant que la demande ne soit déléguée au contrôleur et tous deux ont accès au servlet.
Voici un exemple de journalisation avec utilisant un 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>
Dans LoggerInterceptor, vous pouvez utiliser le code suivant pour accéder à la demande:
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);
Je doute que HttpServletRequestWrapper
puisse un jour fonctionner. Jetez un coup d’œil à l’implémentation DispatcherServlet:
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
Il passe encore référence à "processedRequest
", qui fait référence à une demande HttpServletRequest
dont le flux a déjà été lu.
Je sais que c'est une vieille question, mais pour ceux d'entre vous qui recherchent encore une solution, cela a fonctionné pour moi:
import Java.io.BufferedReader;
import Java.io.ByteArrayInputStream;
import Java.io.ByteArrayOutputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.InputStreamReader;
import Java.io.OutputStream;
import Java.io.PrintWriter;
import Java.util.Collection;
import Java.util.Enumeration;
import Java.util.HashMap;
import Java.util.Locale;
import Java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.Apache.commons.io.output.TeeOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpLoggingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(HttpLoggingFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
Map<String, String> requestMap = this
.getTypesafeRequestMap(httpServletRequest);
BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
httpServletRequest);
BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
httpServletResponse);
final StringBuilder logMessage = new StringBuilder(
"REST Request - ").append("[HTTP METHOD:")
.append(httpServletRequest.getMethod())
.append("] [PATH INFO:")
.append(httpServletRequest.getPathInfo())
.append("] [REQUEST PARAMETERS:").append(requestMap)
.append("] [REQUEST BODY:")
.append(bufferedRequest.getRequestBody())
.append("] [REMOTE ADDRESS:")
.append(httpServletRequest.getRemoteAddr()).append("]");
chain.doFilter(bufferedRequest, bufferedResponse);
logMessage.append(" [RESPONSE:")
.append(bufferedResponse.getContent()).append("]");
logger.debug(logMessage.toString());
} catch (Throwable a) {
logger.error(a.getMessage());
}
}
private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
Map<String, String> typesafeRequestMap = new HashMap<String, String>();
Enumeration<?> requestParamNames = request.getParameterNames();
while (requestParamNames.hasMoreElements()) {
String requestParamName = (String) requestParamNames.nextElement();
String requestParamValue = request.getParameter(requestParamName);
typesafeRequestMap.put(requestParamName, requestParamValue);
}
return typesafeRequestMap;
}
@Override
public void destroy() {
}
private static final class BufferedRequestWrapper extends
HttpServletRequestWrapper {
private ByteArrayInputStream bais = null;
private ByteArrayOutputStream baos = null;
private BufferedServletInputStream bsis = null;
private byte[] buffer = null;
public BufferedRequestWrapper(HttpServletRequest req)
throws IOException {
super(req);
// Read InputStream and store its content in a buffer.
InputStream is = req.getInputStream();
this.baos = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int read;
while ((read = is.read(buf)) > 0) {
this.baos.write(buf, 0, read);
}
this.buffer = this.baos.toByteArray();
}
@Override
public ServletInputStream getInputStream() {
this.bais = new ByteArrayInputStream(this.buffer);
this.bsis = new BufferedServletInputStream(this.bais);
return this.bsis;
}
String getRequestBody() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
this.getInputStream()));
String line = null;
StringBuilder inputBuffer = new StringBuilder();
do {
line = reader.readLine();
if (null != line) {
inputBuffer.append(line.trim());
}
} while (line != null);
reader.close();
return inputBuffer.toString().trim();
}
}
private static final class BufferedServletInputStream extends
ServletInputStream {
private ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais) {
this.bais = bais;
}
@Override
public int available() {
return this.bais.available();
}
@Override
public int read() {
return this.bais.read();
}
@Override
public int read(byte[] buf, int off, int len) {
return this.bais.read(buf, off, len);
}
}
public class TeeServletOutputStream extends ServletOutputStream {
private final TeeOutputStream targetStream;
public TeeServletOutputStream(OutputStream one, OutputStream two) {
targetStream = new TeeOutputStream(one, two);
}
@Override
public void write(int arg0) throws IOException {
this.targetStream.write(arg0);
}
public void flush() throws IOException {
super.flush();
this.targetStream.flush();
}
public void close() throws IOException {
super.close();
this.targetStream.close();
}
}
public class BufferedResponseWrapper implements HttpServletResponse {
HttpServletResponse original;
TeeServletOutputStream tee;
ByteArrayOutputStream bos;
public BufferedResponseWrapper(HttpServletResponse response) {
original = response;
}
public String getContent() {
return bos.toString();
}
public PrintWriter getWriter() throws IOException {
return original.getWriter();
}
public ServletOutputStream getOutputStream() throws IOException {
if (tee == null) {
bos = new ByteArrayOutputStream();
tee = new TeeServletOutputStream(original.getOutputStream(),
bos);
}
return tee;
}
@Override
public String getCharacterEncoding() {
return original.getCharacterEncoding();
}
@Override
public String getContentType() {
return original.getContentType();
}
@Override
public void setCharacterEncoding(String charset) {
original.setCharacterEncoding(charset);
}
@Override
public void setContentLength(int len) {
original.setContentLength(len);
}
@Override
public void setContentType(String type) {
original.setContentType(type);
}
@Override
public void setBufferSize(int size) {
original.setBufferSize(size);
}
@Override
public int getBufferSize() {
return original.getBufferSize();
}
@Override
public void flushBuffer() throws IOException {
tee.flush();
}
@Override
public void resetBuffer() {
original.resetBuffer();
}
@Override
public boolean isCommitted() {
return original.isCommitted();
}
@Override
public void reset() {
original.reset();
}
@Override
public void setLocale(Locale loc) {
original.setLocale(loc);
}
@Override
public Locale getLocale() {
return original.getLocale();
}
@Override
public void addCookie(Cookie cookie) {
original.addCookie(cookie);
}
@Override
public boolean containsHeader(String name) {
return original.containsHeader(name);
}
@Override
public String encodeURL(String url) {
return original.encodeURL(url);
}
@Override
public String encodeRedirectURL(String url) {
return original.encodeRedirectURL(url);
}
@SuppressWarnings("deprecation")
@Override
public String encodeUrl(String url) {
return original.encodeUrl(url);
}
@SuppressWarnings("deprecation")
@Override
public String encodeRedirectUrl(String url) {
return original.encodeRedirectUrl(url);
}
@Override
public void sendError(int sc, String msg) throws IOException {
original.sendError(sc, msg);
}
@Override
public void sendError(int sc) throws IOException {
original.sendError(sc);
}
@Override
public void sendRedirect(String location) throws IOException {
original.sendRedirect(location);
}
@Override
public void setDateHeader(String name, long date) {
original.setDateHeader(name, date);
}
@Override
public void addDateHeader(String name, long date) {
original.addDateHeader(name, date);
}
@Override
public void setHeader(String name, String value) {
original.setHeader(name, value);
}
@Override
public void addHeader(String name, String value) {
original.addHeader(name, value);
}
@Override
public void setIntHeader(String name, int value) {
original.setIntHeader(name, value);
}
@Override
public void addIntHeader(String name, int value) {
original.addIntHeader(name, value);
}
@Override
public void setStatus(int sc) {
original.setStatus(sc);
}
@SuppressWarnings("deprecation")
@Override
public void setStatus(int sc, String sm) {
original.setStatus(sc, sm);
}
@Override
public String getHeader(String arg0) {
return original.getHeader(arg0);
}
@Override
public Collection<String> getHeaderNames() {
return original.getHeaderNames();
}
@Override
public Collection<String> getHeaders(String arg0) {
return original.getHeaders(arg0);
}
@Override
public int getStatus() {
return original.getStatus();
}
}
}
Ensuite, enregistrez simplement le filtre dans web.xml et vous avez terminé. Tous les crédits à: http://wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431 (je viens de le corriger).
Hé, tu peux essayer avec ça:
@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!";
}
Ici: s’il prouve l’URI avec le '/' il permet à toutes les opérations de s’exécuter. tels que get post update et delete avec la même valeur URI.
Je crée une version Ouputstream sans aucune dépendance vis-à-vis des bibliothèques tierces pour une réutilisation plus facile. Vous pouvez utiliser cette classe 2 wrapper pour obtenir facilement le corps de la demande et de la réponse .
Mais de toute façon, je dois utiliser un filtre pour le faire à la place de l'intercepteur. Comme @ user1323865 l'a mentionné, au printemps 4, la demande traitée est utilisée à la fois dans l'intercepteur et le gestionnaire, de sorte que vous ne pouvez pas utiliser ces méthodes pour l'intercepteur .
Vous pouvez également trouver de l’aide sur ce lien si vous utilisez plutôt la version Writer . Capturez et enregistrez le corps de la réponse
public class BufferedRequestWrapper extends HttpServletRequestWrapper
{
private static final class BufferedServletInputStream extends ServletInputStream
{
private ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais)
{
this.bais = bais;
}
@Override
public int available()
{
return this.bais.available();
}
@Override
public int read()
{
return this.bais.read();
}
@Override
public int read(byte[] buf, int off, int len)
{
return this.bais.read(buf, off, len);
}
}
private byte[] mBodyBuffer;
public BufferedRequestWrapper(HttpServletRequest request) throws IOException
{
super(request);
InputStream in = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) > 0)
{
baos.write(buffer, 0, bytesRead);
}
mBodyBuffer = baos.toByteArray();
}
public String getRequestBody()
{
return new String(mBodyBuffer, Charset.forName("UTF-8"));
}
@Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream()
{
ByteArrayInputStream in = new ByteArrayInputStream(mBodyBuffer);
return new BufferedServletInputStream(in);
}
}
public class BufferedResponseWrapper extends HttpServletResponseWrapper
{
private TeeServletOutputStream mTeeOutputStream;
private static class TeeOutputStream extends OutputStream
{
private OutputStream mChainStream;
private OutputStream mTeeStream;
public TeeOutputStream(OutputStream chainStream, OutputStream teeStream)
{
mChainStream = chainStream;
mTeeStream = teeStream;
}
@Override
public void write(int b) throws IOException
{
mChainStream.write(b);
mTeeStream.write(b);
mTeeStream.flush();
}
@Override
public void close() throws IOException
{
flush();
mChainStream.close();
mTeeStream.close();
}
@Override
public void flush() throws IOException
{
mChainStream.close();
}
}
public class TeeServletOutputStream extends ServletOutputStream
{
private final TeeOutputStream targetStream;
public TeeServletOutputStream(OutputStream one, OutputStream two)
{
targetStream = new TeeOutputStream(one, two);
}
@Override
public void write(int b) throws IOException
{
this.targetStream.write(b);
}
@Override
public void flush() throws IOException
{
super.flush();
this.targetStream.flush();
}
@Override
public void close() throws IOException
{
super.close();
this.targetStream.close();
}
}
private ByteArrayOutputStream mByteArrayOutputStream;
public BufferedResponseWrapper(HttpServletResponse response) throws IOException
{
super(response);
mByteArrayOutputStream = new ByteArrayOutputStream();
mTeeOutputStream = new TeeServletOutputStream(super.getResponse().getOutputStream(), mByteArrayOutputStream);
}
@Override
public PrintWriter getWriter() throws IOException
{
return super.getResponse().getWriter();
}
@Override
public ServletOutputStream getOutputStream() throws IOException
{
return mTeeOutputStream;
}
public String getResponseBody()
{
return mByteArrayOutputStream.toString();
}
}
Actuellement dans le référentiel spring-mvc, les intercepteurs sont appelés dans DispatcherServlet # doDispatch (...):
...
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
Puis-je définir ma propre DispatcherServlet
et remplacer doDispatch(...)
pour injecter une HttpRequestWrapper
avec une ByteArrayInputStream
sur getInputStream()
?
...
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
RequestWrapper wrappedRequest = new RequestWrapper(request);
logger.debug("injecting RequestWrapper: " + wrappedRequest);
super.doDispatch(wrappedRequest, response);
}
...
Cela fonctionnera-t-il dans la situation ci-dessus?
Vous devez implémenter le requestWrapper comme suit:
public class DocVerificationRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public DocVerificationRequestWrapper(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();
}
@Override
public boolean isFinished() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setReadListener(ReadListener listener) {
// TODO Auto-generated method stub
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
puis à l'intérieur de la méthode chain.doFilter de la classe filter, transmettez l'objet requestWrapper à la place de l'objet request comme suit:
@Override
public void doFilter(ServletRequest arg0, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("checking token in filter");
HttpServletRequest request = (HttpServletRequest) arg0;
DocVerificationRequestWrapper myRequestWrapper = new DocVerificationRequestWrapper((HttpServletRequest) request);
String body = myRequestWrapper.getBody();
logger.info("body = "+body);
Token token = null;
try {
JSONObject jsonObj = new JSONObject(body);
JSONObject tokenObj = (JSONObject) jsonObj.get("token");
Gson gson = new Gson();
token = gson.fromJson(tokenObj.toString(), Token.class);
if(null != token) {
if(userVerificationService==null){
ServletContext servletContext = request.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
userVerificationService = webApplicationContext.getBean(UserVerificationService.class);
}
String verStatus = userVerificationService.verifyUser(token);
logger.info("verStatus = "+verStatus);
if(verStatus != null && verStatus.equalsIgnoreCase("success")) {
chain.doFilter(myRequestWrapper, response); //here replacing request with requestWrapper
}else
logger.error("Invalid token");
}else {
logger.error("token missing.");
}
} catch (JSONException e) {
logger.error("exception in authetication filter " + e);
}
}
Ainsi, la résolution de l'exception fermée IOStream.
Une méthode simple consiste à obtenir le corps de la demande sous forme de chaîne, puis à analyser en tant qu’objet Java. Vous pouvez utiliser cette chaîne à votre guise.
Donc dans votre exemple:
@RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")
@ResponseBody
public String updateEntity(@RequestBody String empAsString) {
// Do whatever with the json as String
System.out.println(empAsString);
// Transform it into the Java Object you want
ObjectMapper mapper = new ObjectMapper();
Employee emp = mapper.readValue(empAsString, Employee.class);
// Do some DB Stuff. Anyway, the control flow does not reach this place.
return "Employee " + emp.getName() + " updated successfully!";
}
En note, si vous en avez besoin sous forme de liste, vous pouvez utiliser:
List<Employee> eventsList =
mapper.readValue(jsonInString, mapper.getTypeFactory().constructCollectionType(List.class, Employee.class));
Vous pouvez simplement utiliser:
import org.Apache.commons.io.IOUtils;
import Java.nio.charset.Charset;
String requestBody = IOUtils.toString(request.getInputStream(), Charset.forName("UTF-8").toString());