InputStream到servletInputStream

Gol*_*nes 10 java inputstream

我有这个InputStream:

InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
Run Code Online (Sandbox Code Playgroud)

如何将其转换为ServletInputStream?

我试过了:

ServletInputStream  servletInputStream = (ServletInputStream) inputStream;
Run Code Online (Sandbox Code Playgroud)

但是不行.

编辑:

我的方法是这样的:

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;

        }
 }
Run Code Online (Sandbox Code Playgroud)

我试图将我的所有请求转换为小写.

Kid*_*rla 23

我的建议:不要创建ByteArrayInputStream,只需使用从getBytes方法中获得的字节数组.这应该足以创建一个ServletInputStream.

最基本的解决方案

不幸的是,aksappy的回答只会覆盖该read方法.虽然这在Servlet API 3.0及更低版本中已经足够,但在更高版本的Servlet API中,还有三种方法需要实现.

这是我的类的实现,虽然它变得很长(由于Servlet API 3.1中引入的新方法),您可能想要考虑将其分解为嵌套甚至顶级类.

    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;
            }
        }
    };
Run Code Online (Sandbox Code Playgroud)

添加预期的方法

根据您的要求,您可能还想覆盖其他方法.正如romfret指出的那样,建议覆盖一些方法,例如closeavailable.如果您不实现它们,流将始终报告有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;
    }
Run Code Online (Sandbox Code Playgroud)

写一个更好的近距离方法

不幸的是,由于匿名类的性质,你很难编写一个有效的close方法,因为只要流的一个实例没有被Java垃圾收集,它就维护了对字节数组的引用,即使流已关闭.

但是,如果将类分解为嵌套或顶级类(或者甚至是具有从定义它的行调用的构造函数的匿名类),则myBytes可以是非final字段而不是final局部变量,你可以添加如下行:

myBytes = null;
Run Code Online (Sandbox Code Playgroud)

到你的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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

标记和重置

您可能还需要重写mark,markSupportedreset如果你想支持标记/复位.我不确定它们是否真的被你的容器调用过.

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)


aks*_*ppy 9

试试这个代码.

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
    ServletInputStream servletInputStream=new ServletInputStream(){
        public int read() throws IOException {
          return byteArrayInputStream.read();
        }
      }
Run Code Online (Sandbox Code Playgroud)

  • 如果重写此方法,则应覆盖其他方法(`close`等). (5认同)
  • ServletInputStream不是抽象的吗? (2认同)