it-swarm.com.de

Wer legt den Inhaltstyp der Antwort in Spring MVC fest? (@ResponseBody)

Ich habe in meiner Annotation-gesteuerten Spring-MVC Java Webanwendung auf Jetty-Webserver ausgeführt (derzeit im Maven-Jetty-Plugin).

Ich versuche, etwas AJAX mit einer Controller-Methode zu unterstützen, die nur String-Hilfetext zurückgibt. Ressourcen sind in UTF-8-Codierung, ebenso wie der String, aber meine Antwort vom Server kommt mit

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

auch wenn mein browser sendet

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

Ich verwende irgendwie die Standardkonfiguration von spring

Ich habe einen Hinweis gefunden, um diese Bean zur Konfiguration hinzuzufügen, aber ich denke, dass sie nur nicht verwendet wird, weil er besagt, dass die Codierung nicht unterstützt wird und stattdessen eine Standard-Bean verwendet wird.

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

Mein Controller-Code lautet (Beachten Sie, dass diese Änderung des Antworttyps bei mir nicht funktioniert):

@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;
}
119
Hurda

Eine einfache Deklaration der StringHttpMessageConverter Bean reicht nicht aus, Sie müssen sie in AnnotationMethodHandlerAdapter einfügen:

<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>

Mit dieser Methode müssen Sie jedoch alle HttpMessageConverters neu definieren, und es funktioniert auch nicht mit <mvc:annotation-driven />.

Die vielleicht bequemste, aber hässlichste Methode ist es, die Instanziierung von AnnotationMethodHandlerAdapter mit BeanPostProcessor abzufangen:

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 " />
60
axtavt

Ich habe eine Lösung für Spring 3.1 gefunden. mit @ResponseBody Annotation verwenden. Hier ist ein Beispiel eines Controllers mit Json-Ausgabe:

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

}
158
Warrior

Beachten Sie, dass Sie in Spring MVC 3.1 den MVC-Namespace zum Konfigurieren von Nachrichtenkonvertern verwenden können:

<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>

Oder codebasierte Konfiguration:

@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 ...
  }
}
49

Nur für den Fall, dass Sie die Codierung auch folgendermaßen einstellen können:

@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);
}

Ich denke, dass die Verwendung von StringHttpMessageConverter besser ist.

44
digz6666

sie können zu RequestMapping manufact = "text/plain; charset = UTF-8" hinzufügen

@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);
}

siehe diesen Blog für mehr Details

19
Charlie Wu

Ich habe dieses Problem kürzlich bekämpft und im Frühjahr 3.1 eine viel bessere Antwort gefunden:

@RequestMapping(value = "ajax/gethelp", produces = "text/plain")

So einfach wie JAX-RS, wie es in allen Kommentaren heißt, könnte/sollte es sein.

10
dbyoung

Ich habe den Inhaltstyp in der MarshallingView in der ContentNegotiatingViewResolver Bean gesetzt. Es funktioniert leicht, sauber und reibungslos:

<property name="defaultViews">
  <list>
    <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
      <constructor-arg>
        <bean class="org.springframework.oxm.xstream.XStreamMarshaller" />     
      </constructor-arg>
      <property name="contentType" value="application/xml;charset=UTF-8" />
    </bean>
  </list>
</property>
4
Reto-san

Sie können Erzeugnisse verwenden, um den Typ der Antwort anzugeben, die Sie von der Steuerung senden. Dieses "produziert" Schlüsselwort ist am nützlichsten bei Ajax-Anfragen und war in meinem Projekt sehr hilfreich

@RequestMapping(value = "/aURLMapping.htm", method = RequestMethod.GET, produces = "text/html; charset=utf-8") 

public @ResponseBody String getMobileData() {

}

Danke digz6666, deine Lösung funktioniert bei mir mit geringfügigen Änderungen, da ich json verwende:

 responseHeaders.add ("Inhaltstyp", "application/json; Zeichensatz = utf-8"); 

Die Antwort von axtavt (die Sie empfohlen haben) funktioniert bei mir nicht. Auch wenn ich den richtigen Medientyp hinzugefügt habe:

 if (conv instanceof StringHttpMessageConverter) {
 ((StringHttpMessageConverter) conv) .setSupportedMediaTypes (
 Arrays.asList (
 new MediaType ("text", "html") , Charset.forName ("UTF-8")), 
 New MediaType ("application", "json", Charset.forName ("UTF-8"))); 
} 
4
redochka

Ich verwende den in web.xml konfigurierten CharacterEncodingFilter. Vielleicht hilft das ja.

    <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
3

wenn Sie dieses Problem mithilfe der folgenden Konfiguration beheben möchten:

<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>

sie sollten sicherstellen, dass Ihre * .xml-Datei nur ein mvc: annotation-driven Tag enthält. Andernfalls ist die Konfiguration möglicherweise nicht wirksam.

2
Lich
package com.your.package.spring.fix;

import Java.io.UnsupportedEncodingException;
import Java.net.URLDecoder;
import Java.net.URLEncoder;

/**
 * @author Szilard_Jakab (JaKi)
 * Workaround for Spring 3 @ResponseBody issue - get incorrectly 
   encoded parameters     from the URL (in example @ JSON response)
 * Tested @ Spring 3.0.4
 */
public class RepairWrongUrlParamEncoding {
    private static String restoredParamToOriginal;

    /**
    * @param wrongUrlParam
    * @return Repaired url param (UTF-8 encoded)
    * @throws UnsupportedEncodingException
    */
    public static String repair(String wrongUrlParam) throws 
                                            UnsupportedEncodingException {
    /* First step: encode the incorrectly converted UTF-8 strings back to 
                  the original URL format
    */
    restoredParamToOriginal = URLEncoder.encode(wrongUrlParam, "ISO-8859-1");

    /* Second step: decode to UTF-8 again from the original one
    */
    return URLDecoder.decode(restoredParamToOriginal, "UTF-8");
    }
}

Nachdem ich eine Menge Workaround für dieses Problem ausprobiert habe, habe ich mir das überlegt und es funktioniert einwandfrei.

2
Szilard Jakab

Die einfache Möglichkeit, dieses Problem in Spring 3.1.1 zu lösen, besteht darin, folgende Konfigurationscodes in servlet-context.xml

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

Sie müssen nichts überschreiben oder implementieren.

2
AdaroMu

wenn keines der oben genannten Verfahren für Sie funktioniert hat, versuchen Sie, Ajax-Anfragen für "POST" und nicht für "GET" zu stellen, dann hat das für mich gut funktioniert ... keines der oben genannten Verfahren hat funktioniert. Ich habe auch den CharacterEncodingFilter.

2
Marius

Laut link "Wenn keine Zeichenkodierung angegeben ist, erfordert die Servlet-Spezifikation, dass eine Kodierung nach ISO-8859-1 verwendet wird." Wenn Sie Spring 3.1 oder höher verwenden, verwenden Sie die folgende Konfiguration zu Setzen Sie charset = UTF-8 auf den Antworttext
@ RequestMapping (value = "Ihre Zuordnungs-URL", erzeugt = "text/plain; charset = UTF-8")

1
public final class ConfigurableStringHttpMessageConverter extends AbstractHttpMessageConverter<String> {

    private Charset defaultCharset;

    public Charset getDefaultCharset() {
        return defaultCharset;
    }

    private final List<Charset> availableCharsets;

    private boolean writeAcceptCharset = true;

    public ConfigurableStringHttpMessageConverter() {
        super(new MediaType("text", "plain", StringHttpMessageConverter.DEFAULT_CHARSET), MediaType.ALL);
        defaultCharset = StringHttpMessageConverter.DEFAULT_CHARSET;
        this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
    }

    public ConfigurableStringHttpMessageConverter(String charsetName) {
        super(new MediaType("text", "plain", Charset.forName(charsetName)), MediaType.ALL);
        defaultCharset = Charset.forName(charsetName);
        this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
    }

    /**
     * Indicates whether the {@code Accept-Charset} should be written to any outgoing request.
     * <p>Default is {@code true}.
     */
    public void setWriteAcceptCharset(boolean writeAcceptCharset) {
        this.writeAcceptCharset = writeAcceptCharset;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return String.class.equals(clazz);
    }

    @Override
    protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
        Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
        return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
    }

    @Override
    protected Long getContentLength(String s, MediaType contentType) {
        Charset charset = getContentTypeCharset(contentType);
        try {
            return (long) s.getBytes(charset.name()).length;
        }
        catch (UnsupportedEncodingException ex) {
            // should not occur
            throw new InternalError(ex.getMessage());
        }
    }

    @Override
    protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
        if (writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
        }
        Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
        FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
    }

    /**
     * Return the list of supported {@link Charset}.
     *
     * <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses.
     *
     * @return the list of accepted charsets
     */
    protected List<Charset> getAcceptedCharsets() {
        return this.availableCharsets;
    }

    private Charset getContentTypeCharset(MediaType contentType) {
        if (contentType != null && contentType.getCharSet() != null) {
            return contentType.getCharSet();
        }
        else {
            return defaultCharset;
        }
    }
}

Beispielkonfiguration:

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <util:list>
                <bean class="ru.dz.mvk.util.ConfigurableStringHttpMessageConverter">
                    <constructor-arg index="0" value="UTF-8"/>
                </bean>
            </util:list>
        </property>
    </bean>
0
Igor Kostomin