背景
有时候java web项目中,我们需要使用httpServletRequest.getInputStram()方式获取请求报文(例如在filter中),有几种不同的方式
第一种(传统方式readLine)
public static String getBodyStringFromRequest1(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName(CHARSET)));
// 保存每行的读取内容
String line = "";
// 读取每一行的内容,如果line为null,说明读取完了
while ((line = reader.readLine()) != null) {
// 将读取的内容添加到stringBuffer中
sb.append(line);
// 使用readLine方法返回的字符串不包含换行符
// 根据需要判断是否添加换行符
// 不同的操作系统换行符不一样
// 当前场景只是为了获取报文,不需要添加换行符
// sb.append(System.getProperty("line.separator"));
}
} catch (IOException e) {
LOGGER.error("getBodyStringFromRequest ioException, exception is:", e);
} finally {
// 注意关闭流的顺序,遵循先打开的后关闭原则进行处理
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
LOGGER.error("reader.close ioException");
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
LOGGER.error("inputStream.close ioException");
}
}
}
return sb.toString();
}
API明确说了,该方法返回的不包括换行符的每行数据,或者当流已经读到结束时返回null。现在网上各种错误的说法!!!
public String readLine() throws IOException
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return
('\r'), or a carriage return followed immediately by a linefeed.
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of
the stream has been reached
第二种(使用try-with-resources进行优化+readLine)
public static String getBodyStringFromRequest2(ServletRequest request) {
StringBuilder sb = new StringBuilder();
try (InputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName(CHARSET)));
) {
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
// 根据需要判断是否添加换行符
// 不同的操作系统换行符不一样
// 当前场景只是为了获取报文,不需要添加换行符
// sb.append(System.getProperty("line.separator"));
}
} catch (IOException e) {
LOGGER.error("getBodyStringFromRequest ioException, exception is:", e);
}
return sb.toString();
}
在java文档中,对于try-with-resources有如下描述:
In this example, the try-with-resources statement contains two declarations that are separated by a semicolon:
ZipFile and BufferedWriter. When the block of code that directly follows it terminates, either normally or because
of an exception, the close methods of the BufferedWriter and ZipFile objects are automatically called in this
order. Note that the close methods of resources are called in the opposite order of their creation.
意思就是:在此示例中,try-with-resources语句包含以分号分隔的两个声明:ZipFile和BufferedWriter。当直接跟随它的代码块正常或由
于异常而终止时,将按 BufferedWriter 和 ZipFile 对象的close方法顺序自动调用。请注意,资源的关闭方法按其创建的相反顺序调用。
第三种(使用IOUtils工具类IOUtils.toString)
导入jar包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
public static String getBodyStringFromRequest3(ServletRequest request) {
String body = null;
try (InputStream inputStream = request.getInputStream();) {
body = IOUtils.toString(inputStream, "UTF-8");
} catch (IOException e) {
LOGGER.error("getBodyStringFromRequest ioException, exception is:", e);
}
return body;
}
下图可以很清晰的看到,使用IOUtils.toString方法转成的字符串中包含有换行符