Utilizzando @RequestBody di primavera e la lettura HttpServletRequest.getInputStream () in seguito

StackOverflow https://stackoverflow.com/questions/4097012

Domanda

Sono la mappatura dei dati JSON post di mia richiesta in un oggetto di annotazione utilizzando @RequestBody di primavera e MappingJacksonHttpMessageConverter. Tuttavia dopo che mi piacerebbe leggere i dati in forma String di fare qualche ulteriore autenticazione. Ma quando lo smistamento è avvenuto, il InputStream in HttpServletRequest è vuoto. Una volta che tolgo il parametro @RequestBody dal metodo della lettura dei dati POST in un opere String come previsto.

Devo compromesso rinunciando al @RequestBody e facendo la vincolante in qualche modo manualmente o c'è una soluzione più elegante?

È stato utile?

Soluzione

Quindi, in sostanza è necessario calcolare un hash del corpo della richiesta. Il modo elegante per farlo è quello di applicare un decoratore al InputStream.

Ad esempio, all'interno di un metodo del gestore (in questo caso non è possibile utilizzare @RequestBody e necessità di creare manualmente HttpMessageConverter):

@RequestMapping(...)
public void handle(HttpServletRequest request) throws IOException {
    final HashingInputStreamDecorator d = 
        new HashingInputStreamDecorator(request.getInputStream(), secretKey);
    HttpServletRequest wrapper = new HttpServletRequestWrapper(request) {
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return d;
        }
    };

    HttpMessageConverter conv = ...;
    Foo requestBody = (Foo) conv.read(Foo.class, new ServletServerHttpRequest(wrapper));
    String hash = d.getHash();

    ...
}

dove hash viene calcolato in modo incrementale in metodi read sovrascritto di HashingInputStreamDecorator.

È inoltre possibile utilizzare @RequestBody se si crea un Filter per applicare il decoratore. In questo caso decoratore può passare l'hash calcolato al metodo del gestore come attributo richiesta. Tuttavia, è necessario mappare attentamente questo filtro da applicare solo alle richieste a metodo di gestore specifico.

Altri suggerimenti

Nel vostro fagioli urlMapping si può dichiarare lista di intercettori supplementari:

  <bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
      <list>
        <bean class="org.foo.MyAuthInterceptor"/>
      </list>
    </property>
  </bean>

Gli intercettori hanno accesso a HttpServletRequest, anche se si legge dal flusso è probabile che il parametro mapper non sarà in grado di leggerlo.

public class AuthInterceptor extends HandlerInterceptorAdapter {

  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    ...
  }

  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) {
    ...
  }
}

Se comprendo questo, un modo corretto comune utilizzato con JAX-RS (che è simile a Spring MVC per le richieste di legame) è alla prima "legare" in qualche tipo prima intermedia (solitamente byte [], ma String anche lavori), e associare manualmente da quello a oggetto, utilizzando sottostante raccoglitore di dati (Jackson). Spesso faccio questo per essere in grado di personalizzare completamente la gestione degli errori di associazione dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top