L'utilisation de @RequestBody de printemps et la lecture HttpServletRequest.getInputStream () après

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

Question

Je cartographie des données JSON POST de ma demande dans un objet en utilisant l'annotation @RequestBody de printemps et MappingJacksonHttpMessageConverter. Cependant, après que je voudrais lire les données sous forme de String faire une authentification supplémentaire. Mais quand le rassemblement est arrivé, le InputStream dans HttpServletRequest est vide. Une fois que je supprimer le paramètre @RequestBody de la méthode la lecture des données POST dans un ouvrage de String comme prévu.

Dois-je faire des compromis en renonçant à la @RequestBody et faire la main ou est-il obligatoire en quelque sorte une solution plus élégante?

Était-ce utile?

La solution

Donc, en gros vous devez calculer un hachage du corps de la requête. La façon élégante de le faire est d'appliquer un décorateur à la InputStream.

Par exemple, dans une méthode de gestionnaire (dans ce cas, vous ne pouvez pas utiliser @RequestBody et le besoin de créer manuellement 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();

    ...
}

où hachage est calculé de manière incrémentielle dans des procédés de overriden read de HashingInputStreamDecorator.

Vous pouvez également utiliser @RequestBody si vous créez un Filter pour appliquer le décorateur. Dans ce cas décorateur peut passer la valeur de hachage calculée à la méthode de gestionnaire comme un attribut de demande. Cependant, vous devez mapper ce filtre pour appliquer soigneusement seulement aux demandes de méthode spécifique.

Autres conseils

Dans votre grain de urlMapping vous pouvez déclarer la liste des intercepteurs supplémentaires:

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

Ces intercepteurs ont accès à HttpServletRequest, mais si vous lisez du flux les chances sont que le paramètre mappeur ne sera pas capable de le lire.

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) {
    ...
  }
}

Si je comprends bien, d'une manière commune utilisée avec JAX-RS (ce qui est un peu similaire à Spring MVC par rapport aux demandes de liaison) est d'abord « lier » dans un certain type brut intermédiaire (généralement octet [], mais chaîne également les), et de se lier à la main de celui objet, en utilisant un liant de données sous-jacent (Jackson). Je fais souvent ce pour pouvoir personnaliser entièrement la gestion des erreurs de liaison de données.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top