InputStream 到 servletInputStream
InputStream to servletInputStream
我有这个输入流:
InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
如何将其转换为 ServletInputStream?
我试过:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
但是不工作。
编辑:
我的方法是这样的:
private static class LowerCaseRequest extends HttpServletRequestWrapper {
public LowerCaseRequest(final HttpServletRequest request) throws IOException, ServletException {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream servletInputStream;
StringBuilder jb = new StringBuilder();
String line;
String toLowerCase = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(super.getInputStream()));
while ((line = reader.readLine()) != null) {
toLowerCase = jb.append(line).toString().toLowerCase();
}
InputStream inputStream = new ByteArrayInputStream(toLowerCase.getBytes(StandardCharsets.UTF_8));
servletInputStream = (ServletInputStream) inputStream;
return servletInputStream;
}
}
我正在尝试将所有请求转换为小写。
试试这个代码。
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream=new ServletInputStream(){
public int read() throws IOException {
return byteArrayInputStream.read();
}
}
你只能投这样的东西:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
如果您尝试转换的 inputStream 实际上已经是 ServletInputStream。如果它是 InputStream 的其他实现,它会报错。您不能将一个对象转换为它不是的对象。
在 Servlet 容器中,您可以从 ServletRequest 获取 ServletInputStream:
ServletInputStream servletInputStream = request.getInputStream();
那么,你到底想做什么?
编辑
我很好奇您为什么要将请求转换为小写 - 为什么不让您的 servlet 不区分大小写?换句话说,您可以将请求数据小写的代码复制到您的 servlet 中,然后它可以在那里处理它...总是寻找最简单的解决方案!
我的建议:不要创建 ByteArrayInputStream
,只需使用已经从 getBytes
方法获得的字节数组。这应该足以创建 ServletInputStream
.
最基本的解决方案
不幸的是,aksappy 的回答只覆盖了 read
方法。虽然这在 Servlet API 3.0 及以下版本中可能就足够了,但在更高版本的 Servlet API 中,您必须实现 三个 更多方法。
这是我对 class 的实现,尽管它变得很长(由于 Servlet API 3.1 中引入的新方法),您可能需要考虑将其分解为嵌套甚至顶级 class.
final byte[] myBytes = myString.getBytes("UTF-8");
ServletInputStream servletInputStream = new ServletInputStream() {
private int lastIndexRetrieved = -1;
private ReadListener readListener = null;
@Override
public boolean isFinished() {
return (lastIndexRetrieved == myBytes.length-1);
}
@Override
public boolean isReady() {
// This implementation will never block
// We also never need to call the readListener from this method, as this method will never return false
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
}
return i;
} else {
return -1;
}
}
};
添加预期的方法
根据您的要求,您可能还想覆盖其他方法。正如 romfret 指出的那样,建议重写某些方法,例如 close
和 available
。如果不实现它们,流将始终报告有 0 个字节可供读取,并且 close
方法不会对流的状态产生任何影响。您可能无需覆盖 skip
即可逃脱,因为默认实现只会多次调用 read
。
@Override
public int available() throws IOException {
return (myBytes.length-lastIndexRetrieved-1);
}
@Override
public void close() throws IOException {
lastIndexRetrieved = myBytes.length-1;
}
编写更好的关闭方法
不幸的是,由于匿名 class 的性质,您将很难编写有效的 close
方法,因为只要流的一个实例不是垃圾- 由 Java 收集,它保持对字节数组的引用,即使流已关闭。
但是,如果您将 class 分解为嵌套或顶级 class(或者甚至是匿名的 class 以及您从其中调用的构造函数它已定义),myBytes
可以是非最终字段而不是最终局部变量,您可以添加一行:
myBytes = null;
您的 close
方法,这将允许 Java 释放字节数组占用的内存。
当然,这需要你写一个构造函数,比如:
private byte[] myBytes;
public StringServletInputStream(String str) {
try {
myBytes = str.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("JVM did not support UTF-8", e);
}
}
标记并重置
如果您想支持 mark/reset,您可能还想覆盖 mark
、markSupported
和 reset
。我不确定它们是否真的被你的容器调用过。
private int readLimit = -1;
private int markedPosition = -1;
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void mark(int readLimit) {
this.readLimit = readLimit;
this.markedPosition = lastIndexRetrieved;
}
@Override
public synchronized void reset() throws IOException {
if (markedPosition == -1) {
throw new IOException("No mark found");
} else {
lastIndexRetrieved = markedPosition;
readLimit = -1;
}
}
// Replacement of earlier read method to cope with readLimit
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
readLimit = -1;
}
if (readLimit != -1) {
if ((lastIndexRetrieved - markedPosition) > readLimit) {
// This part is actually not necessary in our implementation
// as we are not storing any data. However we need to respect
// the contract.
markedPosition = -1;
readLimit = -1;
}
}
return i;
} else {
return -1;
}
}
我有这个输入流:
InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
如何将其转换为 ServletInputStream?
我试过:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
但是不工作。
编辑:
我的方法是这样的:
private static class LowerCaseRequest extends HttpServletRequestWrapper {
public LowerCaseRequest(final HttpServletRequest request) throws IOException, ServletException {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream servletInputStream;
StringBuilder jb = new StringBuilder();
String line;
String toLowerCase = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(super.getInputStream()));
while ((line = reader.readLine()) != null) {
toLowerCase = jb.append(line).toString().toLowerCase();
}
InputStream inputStream = new ByteArrayInputStream(toLowerCase.getBytes(StandardCharsets.UTF_8));
servletInputStream = (ServletInputStream) inputStream;
return servletInputStream;
}
}
我正在尝试将所有请求转换为小写。
试试这个代码。
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream=new ServletInputStream(){
public int read() throws IOException {
return byteArrayInputStream.read();
}
}
你只能投这样的东西:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
如果您尝试转换的 inputStream 实际上已经是 ServletInputStream。如果它是 InputStream 的其他实现,它会报错。您不能将一个对象转换为它不是的对象。
在 Servlet 容器中,您可以从 ServletRequest 获取 ServletInputStream:
ServletInputStream servletInputStream = request.getInputStream();
那么,你到底想做什么?
编辑
我很好奇您为什么要将请求转换为小写 - 为什么不让您的 servlet 不区分大小写?换句话说,您可以将请求数据小写的代码复制到您的 servlet 中,然后它可以在那里处理它...总是寻找最简单的解决方案!
我的建议:不要创建 ByteArrayInputStream
,只需使用已经从 getBytes
方法获得的字节数组。这应该足以创建 ServletInputStream
.
最基本的解决方案
不幸的是,aksappy 的回答只覆盖了 read
方法。虽然这在 Servlet API 3.0 及以下版本中可能就足够了,但在更高版本的 Servlet API 中,您必须实现 三个 更多方法。
这是我对 class 的实现,尽管它变得很长(由于 Servlet API 3.1 中引入的新方法),您可能需要考虑将其分解为嵌套甚至顶级 class.
final byte[] myBytes = myString.getBytes("UTF-8");
ServletInputStream servletInputStream = new ServletInputStream() {
private int lastIndexRetrieved = -1;
private ReadListener readListener = null;
@Override
public boolean isFinished() {
return (lastIndexRetrieved == myBytes.length-1);
}
@Override
public boolean isReady() {
// This implementation will never block
// We also never need to call the readListener from this method, as this method will never return false
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
}
return i;
} else {
return -1;
}
}
};
添加预期的方法
根据您的要求,您可能还想覆盖其他方法。正如 romfret 指出的那样,建议重写某些方法,例如 close
和 available
。如果不实现它们,流将始终报告有 0 个字节可供读取,并且 close
方法不会对流的状态产生任何影响。您可能无需覆盖 skip
即可逃脱,因为默认实现只会多次调用 read
。
@Override
public int available() throws IOException {
return (myBytes.length-lastIndexRetrieved-1);
}
@Override
public void close() throws IOException {
lastIndexRetrieved = myBytes.length-1;
}
编写更好的关闭方法
不幸的是,由于匿名 class 的性质,您将很难编写有效的 close
方法,因为只要流的一个实例不是垃圾- 由 Java 收集,它保持对字节数组的引用,即使流已关闭。
但是,如果您将 class 分解为嵌套或顶级 class(或者甚至是匿名的 class 以及您从其中调用的构造函数它已定义),myBytes
可以是非最终字段而不是最终局部变量,您可以添加一行:
myBytes = null;
您的 close
方法,这将允许 Java 释放字节数组占用的内存。
当然,这需要你写一个构造函数,比如:
private byte[] myBytes;
public StringServletInputStream(String str) {
try {
myBytes = str.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("JVM did not support UTF-8", e);
}
}
标记并重置
如果您想支持 mark/reset,您可能还想覆盖 mark
、markSupported
和 reset
。我不确定它们是否真的被你的容器调用过。
private int readLimit = -1;
private int markedPosition = -1;
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void mark(int readLimit) {
this.readLimit = readLimit;
this.markedPosition = lastIndexRetrieved;
}
@Override
public synchronized void reset() throws IOException {
if (markedPosition == -1) {
throw new IOException("No mark found");
} else {
lastIndexRetrieved = markedPosition;
readLimit = -1;
}
}
// Replacement of earlier read method to cope with readLimit
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
readLimit = -1;
}
if (readLimit != -1) {
if ((lastIndexRetrieved - markedPosition) > readLimit) {
// This part is actually not necessary in our implementation
// as we are not storing any data. However we need to respect
// the contract.
markedPosition = -1;
readLimit = -1;
}
}
return i;
} else {
return -1;
}
}