天天看點

java restful中文亂碼_使用RestTemplate通路RESTful服務亂碼處理

在接口服務開發中,我們經常用到Spring模闆類RestTemplate通路restful服務。但RestTemplate進行中文亂碼問題比較麻煩。以我們項目Spring版本4.1.3.RELEASE為例,RestTemplate預設構造方法初始化的StringHttpMessageConverter的預設字元集是 ISO-8859-1,是以導緻RestTemplate請求的響應内容會出現中文亂碼。處理方法可如下:import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.util.Collections;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpRequest;

import org.springframework.http.client.ClientHttpRequestExecution;

import org.springframework.http.client.ClientHttpRequestInterceptor;

import org.springframework.http.client.ClientHttpResponse;

import org.springframework.http.converter.StringHttpMessageConverter;

import org.springframework.web.client.RestTemplate;

public class RestTemplateUtil {

public static RestTemplate getInstance() {

RestTemplate restTemplate = new RestTemplate();

// 設定編碼

restTemplate.getMessageConverters()

.set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

// 列印日志

restTemplate.setInterceptors(

Collections.singletonList(new LoggingClientHttpRequestInterceptor()));

return restTemplate;

}

}

class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {

private final static Logger LOGGER = LoggerFactory.getLogger(LoggingClientHttpRequestInterceptor.class);

@Override

public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)

throws IOException {

traceRequest(request, body);

ClientHttpResponse response = execution.execute(request, body);

traceResponse(response);

return response;

}

private void traceRequest(HttpRequest request, byte[] body) throws IOException {

LOGGER.debug("======================request begin========================================");

LOGGER.debug("URI         : {}", request.getURI());

LOGGER.debug("Method      : {}", request.getMethod());

LOGGER.debug("Headers     : {}", request.getHeaders());

LOGGER.debug("Request body: {}", new String(body, "UTF-8"));

LOGGER.debug("=====================request end===========================================");

}

private void traceResponse(ClientHttpResponse response) throws IOException {

//StringBuilder inputStringBuilder = new StringBuilder();

//try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8"))) {

//String line = bufferedReader.readLine();

//while (line != null) {

//inputStringBuilder.append(line);

//inputStringBuilder.append('\n');

//line = bufferedReader.readLine();

//}

//}

LOGGER.debug("=========================response begin=======================================");

LOGGER.debug("Status code  : {}", response.getStatusCode());

LOGGER.debug("Status text  : {}", response.getStatusText());

LOGGER.debug("Headers      : {}", response.getHeaders());

// WARNING: comment out in production to improve performance

LOGGER.debug("Response body: {}", "WARNING: comment out in production to improve performance");

LOGGER.debug("====================response end==============================================");

}

}

如果其他Spring版本無法按如上方法解決,可運用類加載機制,從根源上解決問題,即重寫org.springframework.http.converter.StringHttpMessageConverter.class,将DEFAULT_CHARSET的值改為Charset.forName("UTF-8")。以spring版本4.1.3.RELEASE為例:

package org.springframework.http.converter;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.nio.charset.Charset;

import java.util.ArrayList;

import java.util.List;

import org.springframework.http.HttpInputMessage;

import org.springframework.http.HttpOutputMessage;

import org.springframework.http.MediaType;

import org.springframework.util.StreamUtils;

*}),

* and writes with a {@code Content-Type} of {@code text/plain}. This can be overridden

* by setting the {@link #setSupportedMediaTypes supportedMediaTypes} property.

*

* @author Arjen Poutsma

* @since 3.0

*/

public class StringHttpMessageConverter extends AbstractHttpMessageConverter {

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

private final Charset defaultCharset;

private final List availableCharsets;

private boolean writeAcceptCharset = true;

public StringHttpMessageConverter() {

this(DEFAULT_CHARSET);

}

public StringHttpMessageConverter(Charset defaultCharset) {

super(new MediaType("text", "plain", defaultCharset), MediaType.ALL);

this.defaultCharset = defaultCharset;

this.availableCharsets = new ArrayList(Charset.availableCharsets().values());

}

public void setWriteAcceptCharset(boolean writeAcceptCharset) {

this.writeAcceptCharset = writeAcceptCharset;

}

@Override

public boolean supports(Class> clazz) {

return String.class.equals(clazz);

}

@Override

protected String readInternal(Class extends String> clazz, HttpInputMessage inputMessage) throws IOException {

Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());

return StreamUtils.copyToString(inputMessage.getBody(), charset);

}

@Override

protected Long getContentLength(String str, MediaType contentType) {

Charset charset = getContentTypeCharset(contentType);

try {

return (long) str.getBytes(charset.name()).length;

}

catch (UnsupportedEncodingException ex) {

// should not occur

throw new IllegalStateException(ex);

}

}

@Override

protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {

if (this.writeAcceptCharset) {

outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());

}

Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());

StreamUtils.copy(str, charset, outputMessage.getBody());

}

protected List getAcceptedCharsets() {

return this.availableCharsets;

}

private Charset getContentTypeCharset(MediaType contentType) {

if (contentType != null && contentType.getCharSet() != null) {

return contentType.getCharSet();

}

else {

return this.defaultCharset;

}

}

}