java - Reading httprequest content from spring exception handler -


i using spring's @exceptionhandler annotation catch exceptions in controllers.

some requests hold post data plain xml string written request body, want read data in order log exception. problem when request inputstream in exception handler , try read stream returns -1 (empty).

the exception handler signature is:

@exceptionhandler(throwable.class) public modelandview exception(httpservletrequest request, httpservletresponse response, httpsession session, throwable arff) 

any thoughts? there way access request body?

my controller:

@controller @requestmapping("/user/**") public class usercontroller {      static final logger log = loggerfactory.getlogger(usercontroller.class);      @autowired     iuserservice userservice;       @requestmapping("/user")     public modelandview getcurrent() {         return new modelandview("user","response", userservice.getcurrent());     }      @requestmapping("/user/firstlogin")     public modelandview firstlogin(httpsession session) {         userservice.loguser(session.getid());         userservice.setoriginalauthority();         return new modelandview("user","response", userservice.getcurrent());     }       @requestmapping("/user/login/failure")     public modelandview loginfailed() {         log.debug("loginfailed()");         status status = new status(-1,"bad login");         return new modelandview("/user/login/failure", "response",status);     }      @requestmapping("/user/login/unauthorized")     public modelandview unauthorized() {         log.debug("unauthorized()");         status status = new status(-1,"unauthorized.please login first.");         return new modelandview("/user/login/unauthorized","response",status);     }      @requestmapping("/user/logout/success")     public modelandview logoutsuccess() {         log.debug("logout()");         status status = new status(0,"successful logout");         return new modelandview("/user/logout/success", "response",status);      }      @requestmapping(value = "/user/{id}", method = requestmethod.post)     public modelandview create(@requestbody userdto userdto, @pathvariable("id") long id) {         return new modelandview("user", "response", userservice.create(userdto, id));     }      @requestmapping(value = "/user/{id}", method = requestmethod.get)     public modelandview getuserbyid(@pathvariable("id") long id) {         return new modelandview("user", "response", userservice.getuserbyid(id));     }      @requestmapping(value = "/user/update/{id}", method = requestmethod.post)     public modelandview update(@requestbody userdto userdto, @pathvariable("id") long id) {         return new modelandview("user", "response", userservice.update(userdto, id));     }      @requestmapping(value = "/user/all", method = requestmethod.get)     public modelandview list() {         return new modelandview("user", "response", userservice.list());     }      @requestmapping(value = "/user/allowedaccounts", method = requestmethod.get)     public modelandview getallowedaccounts() {         return new modelandview("user", "response", userservice.getallowedaccounts());     }      @requestmapping(value = "/user/changeaccount/{accountid}", method = requestmethod.get)     public modelandview changeaccount(@pathvariable("accountid") long accountid) {         status st = userservice.changeaccount(accountid);         if (st.code != -1) {             return getcurrent();         }         else {             return new modelandview("user", "response", st);         }     }     /*     @requestmapping(value = "/user/logout", method = requestmethod.get)     public void perlogout(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {         userservice.setoriginalauthority();         response.sendredirect("/marketplace/user/logout/spring");     }      */      @exceptionhandler(throwable.class) public modelandview exception(httpservletrequest request, httpservletresponse response, httpsession session, throwable arff) {     status st = new status();     try {         writer writer = new stringwriter();         byte[] buffer = new byte[1024];          //reader reader2 = new bufferedreader(new inputstreamreader(request.getinputstream()));         inputstream reader = request.getinputstream();         int n;         while ((n = reader.read(buffer)) != -1) {             writer.tostring();          }         string retval = writer.tostring();         retval = "";         } catch (ioexception e) {              e.printstacktrace();         }          return new modelandview("profile", "response", st);     } } 

thank you

i've tried code , i've found mistakes in exception handler, when read inputstream:

writer writer = new stringwriter(); byte[] buffer = new byte[1024];  //reader reader2 = new bufferedreader(new inputstreamreader(request.getinputstream())); inputstream reader = request.getinputstream(); int n; while ((n = reader.read(buffer)) != -1) {     writer.tostring();  } string retval = writer.tostring(); retval = ""; 

i've replaced code one:

bufferedreader reader = new bufferedreader(new   inputstreamreader(request.getinputstream())); string line = ""; stringbuilder stringbuilder = new stringbuilder(); while ( (line=reader.readline()) != null ) {     stringbuilder.append(line).append("\n"); }  string retval = stringbuilder.tostring(); 

then i'm able read inputstream in exception handler, works! if can't still read inputstream, suggest check how post xml data request body. should consider can consume inputstream 1 time per request, suggest check there isn't other call getinputstream(). if have call 2 or more times should write custom httpservletrequestwrapper make copy of request body, can read more times.

update
comments has helped me reproduce issue. use annotation @requestbody, it's true don't call getinputstream(), spring invokes retrieve request's body. have @ class org.springframework.web.bind.annotation.support.handlermethodinvoker: if use @requestbody class invokes resolverequestbody method, , on... can't read anymore inputstream servletrequest. if still want use both @requestbody , getinputstream() in own method, have wrap request custom httpservletrequestwrapper make copy of request body, can manually read more times. wrapper:

public class customhttpservletrequestwrapper extends httpservletrequestwrapper {      private static final logger logger = logger.getlogger(customhttpservletrequestwrapper.class);     private final string body;      public customhttpservletrequestwrapper(httpservletrequest request) {         super(request);          stringbuilder stringbuilder = new stringbuilder();         bufferedreader bufferedreader = null;          try {             inputstream inputstream = request.getinputstream();             if (inputstream != null) {                 bufferedreader = new bufferedreader(new inputstreamreader(inputstream));                 string line = "";                 while ((line = bufferedreader.readline()) != null) {                     stringbuilder.append(line).append("\n");                 }             } else {                 stringbuilder.append("");             }         } catch (ioexception ex) {             logger.error("error reading request body...");         } {             if (bufferedreader != null) {                 try {                     bufferedreader.close();                 } catch (ioexception ex) {                     logger.error("error closing bufferedreader...");                 }             }         }          body = stringbuilder.tostring();     }      @override     public servletinputstream getinputstream() throws ioexception {         final stringreader reader = new stringreader(body);         servletinputstream inputstream = new servletinputstream() {             public int read() throws ioexception {                 return reader.read();             }         };         return inputstream;     } } 

then should write simple filter wrap request:

public class myfilter implements filter {      public void init(filterconfig fc) throws servletexception {      }      public void dofilter(servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception {         chain.dofilter(new customhttpservletrequestwrapper((httpservletrequest)request), response);      }      public void destroy() {      }  } 

finally, have configure filter in web.xml:

<filter>          <filter-name>myfilter</filter-name>        <filter-class>test.myfilter</filter-class>   </filter>  <filter-mapping>        <filter-name>myfilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping> 

you can fire filter controllers needs it, should change url-pattern according needs.

if need feature in 1 controller, can make copy of request body in controller when receive through @requestbody annotation.


Comments

Popular posts from this blog

c# - How to set Z index when using WPF DrawingContext? -

razor - Is this a bug in WebMatrix PageData? -

visual c++ - Using relative values in array sorting ( asm ) -