InputStream в servletInputStream
у меня есть этот InputStream:
InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
как я могу преобразовать это в ServletInputStream?
Я пробовал:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
но не работают.
EDIT:
мой метод это:
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;
}
}
Im пытается преобразовать весь мой запрос в нижний регистр.
3 ответов
попробуйте этот код.
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream=new ServletInputStream(){
public int read() throws IOException {
return byteArrayInputStream.read();
}
}
мой совет: не создавать 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;
}
}
};
добавление ожидаемых методов
в зависимости от ваших требований вы также можете переопределить другие методы. Как отметил ромфре, рекомендуется переопределить некоторые методы, такие как 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;
}
написание лучшего метода закрытия
к сожалению, из - за природы анонимного класса вам будет трудно написать эффективный close
метод, потому что до тех пор, пока один экземпляр потока не был собран мусор Java, он поддерживает ссылку на массив байтов, даже если поток был закрыт.
однако, если вы разложите класс на вложенный или класс верхнего уровня (или даже анонимный класс с конструктором, который вы вызываете из строки, в которой он определен),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;
}
}
Вы можете только бросить что-то вроде этого:
ServletInputStream servletInputStream = (ServletInputStream) inputStream;
Если inputStream, который вы пытаетесь бросить, на самом деле уже является ServletInputStream. Он будет жаловаться, если это какая-то другая реализация InputStream. Вы не можете бросить объект на то, чем он не является.
в контейнере сервлетов вы можете получить ServletInputStream из ServletRequest:
ServletInputStream servletInputStream = request.getInputStream();
Итак, что вы на самом деле пытаетесь сделать?
редактировать
я заинтригован почему вы хотите преобразовать свой запрос в нижний регистр-почему бы просто не сделать ваш сервлет нечувствительным к регистру? Другими словами, ваш код в нижнем регистре запроса данные могут быть скопированы в ваш сервлет, затем обработать их... всегда ищите самое простое решение!