139 votes

Qui définit le type de contenu de la réponse dans Spring MVC (@ResponseBody)

J'ai une application web Java Spring MVC pilotée par des annotations et exécutée sur un serveur web jetty (actuellement dans le plugin maven jetty).

J'essaie de mettre en place un support AJAX avec une méthode de contrôleur renvoyant un texte d'aide sous forme de chaîne. Les ressources sont en encodage UTF-8 et la chaîne aussi, mais ma réponse du serveur vient avec

content-encoding: text/plain;charset=ISO-8859-1 

même lorsque mon navigateur envoie

Accept-Charset  windows-1250,utf-8;q=0.7,*;q=0.7

J'utilise en quelque sorte la configuration par défaut de Spring

J'ai trouvé une astuce pour ajouter ce bean à la configuration, mais je pense qu'il n'est tout simplement pas utilisé, parce qu'il dit qu'il ne supporte pas l'encodage et qu'un encodage par défaut est utilisé à la place.

<bean class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />
</bean>

Le code de mon contrôleur est le suivant (notez que ce changement de type de réponse ne fonctionne pas pour moi) :

@RequestMapping(value = "ajax/gethelp")
public @ResponseBody String handleGetHelp(Locale loc, String code, HttpServletResponse response) {
    log.debug("Getting help for code: " + code);
    response.setContentType("text/plain;charset=UTF-8");
    String help = messageSource.getMessage(code, null, loc);
    log.debug("Help is: " + help);
    return help;
}

179voto

Warrior Points 571

J'ai trouvé une solution pour Spring 3.1. en utilisant l'annotation @ResponseBody. Voici un exemple de contrôleur utilisant la sortie Json :

@RequestMapping(value = "/getDealers", method = RequestMethod.GET, 
produces = "application/json; charset=utf-8")
@ResponseBody
public String sendMobileData() {

}

7 votes

+1. Cela m'a également permis de résoudre le problème, mais seulement après être passé à l'utilisation de <mvc:annotation-driven/> dans applicationContext. (Au lieu de <bean class=" [...] DefaultAnnotationHandlerMapping"/> qui est de toute façon obsolète dans Spring 3.2...)

0 votes

Est-ce que cela produit du application/xml si c'est annoté de cette façon ?

2 votes

@Hurda : Il est évident que vous pouvez spécifier n'importe quel type de contenu en changeant la valeur de l'attribut produces attribut.

60voto

axtavt Points 126632

Simple déclaration de la StringHttpMessageConverter n'est pas suffisant, il faut l'injecter dans le fichier AnnotationMethodHandlerAdapter :

<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <array>
            <bean class = "org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
            </bean>
        </array>
    </property>
</bean>

Cependant, en utilisant cette méthode, vous devez redéfinir tous les HttpMessageConverter et ne fonctionne pas non plus avec les <mvc:annotation-driven /> .

Ainsi, la méthode la plus pratique, mais la plus laide, consiste à intercepter l'instanciation de l'élément AnnotationMethodHandlerAdapter con BeanPostProcessor :

public class EncodingPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String name)
            throws BeansException {
        if (bean instanceof AnnotationMethodHandlerAdapter) {
            HttpMessageConverter<?>[] convs = ((AnnotationMethodHandlerAdapter) bean).getMessageConverters();
            for (HttpMessageConverter<?> conv: convs) {
                if (conv instanceof StringHttpMessageConverter) {
                    ((StringHttpMessageConverter) conv).setSupportedMediaTypes(
                        Arrays.asList(new MediaType("text", "html", 
                            Charset.forName("UTF-8"))));
                }
            }
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String name)
            throws BeansException {
        return bean;
    }
}

-

<bean class = "EncodingPostProcessor " />

10 votes

Cela ressemble à un sale coup. Je ne l'aime pas mais je l'utilise. Les développeurs du framework Spring devraient travailler sur ce cas !

0 votes

Où se trouve la ligne <bean class = "EncodingPostProcessor " /> ?

1 votes

@zod : En DispatcherServlet ( ...-servlet.xml )

52voto

Rossen Stoyanchev Points 1925

Notez que dans Spring MVC 3.1, vous pouvez utiliser l'espace de noms MVC pour configurer les convertisseurs de messages :

<mvc:annotation-driven>
  <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
      <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>

Ou configuration basée sur un code :

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

  private static final Charset UTF8 = Charset.forName("UTF-8");

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
    stringConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", UTF8)));
    converters.add(stringConverter);

    // Add other converters ...
  }
}

0 votes

Cela fonctionne en quelque sorte, sauf que 1) cela pollue la réponse avec un Accept-Charset qui énumère probablement tous les codages de caractères connus, et 2) lorsque la demande comporte un Accept l'en-tête supportedMediaTypes du convertisseur n'est pas utilisée Ainsi, par exemple, lorsque je fais la demande en tapant directement l'URL dans un navigateur, la réponse est de type Content-Type: text/html à la place.

3 votes

Vous pouvez simplifier, car "text/plain" est de toute façon la valeur par défaut : <bean class="org.springframework.http.converter.StringHttpMessageC‌​onverter"><construct‌​or-arg value="UTF-8" /></bean>

0 votes

Cette réponse doit être considérée comme la bonne. De plus, la façon dont @IgorMukhin définit le bean StringHttpMessageConverter fonctionne. Cette réponse est utilisée pour définir les types de contenu de la réponse pour tous les servlets. Si vous avez seulement besoin de définir le type de contenu de la réponse pour une méthode de contrôleur particulière, utilisez plutôt la réponse de Warrior (utilisez l'argument produit dans @RequestMapping).

45voto

digz6666 Points 1109

Au cas où, vous pouvez également définir l'encodage de la manière suivante :

@RequestMapping(value = "ajax/gethelp")
public ResponseEntity<String> handleGetHelp(Locale loc, String code, HttpServletResponse response) {
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "text/html; charset=utf-8");

    log.debug("Getting help for code: " + code);
    String help = messageSource.getMessage(code, null, loc);
    log.debug("Help is: " + help);

    return new ResponseEntity<String>("returning: " + help, responseHeaders, HttpStatus.CREATED);
}

Je pense que l'utilisation de StringHttpMessageConverter est préférable.

0 votes

C'est également la solution si vous obtenez l'erreur the manifest may not be valid or the file could not be opened. dans IE 11. Merci digz !

20voto

Charlie Wu Points 2308

Vous pouvez ajouter produces = "text/plain;charset=UTF-8" à RequestMapping

@RequestMapping(value = "/rest/create/document", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String create(Document document, HttpServletRespone respone) throws UnsupportedEncodingException {

    Document newDocument = DocumentService.create(Document);

    return jsonSerializer.serialize(newDocument);
}

2 votes

Ce code ne serait pas compilé ; vous retournez quelque chose à partir d'une méthode void.

2 votes

Désolé, mauvais bug, c'est corrigé maintenant

3 votes

C'est une mauvaise réponse. Selon la documentation de Spring : Les types de média produisibles de la demande mappée, en réduisant le mappage primaire. Le format est une séquence de types de médias ("text/plain", "application/*"), une demande n'étant mappée que si l'acceptation correspond à l'un de ces types de médias. Les expressions peuvent être annulées en utilisant l'opérateur " !", comme dans "!text/plain", qui correspond à toutes les demandes dont l'acceptation est différente de "text/plain".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X