соединить OutputStream с InputStream - PullRequest
1 голос
/ 21 июля 2010

Я экспериментирую с небольшим веб-фреймворком и наткнулся на проблему с потоками.Есть методы-обработчики, такие как Response get(HttpServletRequest).С точки зрения фреймворков ответ должен предлагать входной поток для тела ответа.Каркас читает эти потоки и записывает данные в базовый OutputStream API сервлета.Но с точки зрения пользователя OutputStream необходим для записи.

Перспектива Framework:

public interface Response {
  InputStream getInputStream();
}

Перспектива пользователя:

public interface Response {
  InputStream getOutputStream();
}

Его следует использовать так:

public void get(HttpServletRequest request) {
  Response response = new Response(OK);
  response.getOutputStream().write(...);
  return response;
}

Проблема в том, что я не могу создать выходной поток без выходной цели (и не хочу записывать в буфер ByteArray).

Любая идея, как дать пользователюOutputStream, не передавая один, как в Servlet API?Я хотел бы избежать выходных параметров.

Ответы [ 3 ]

1 голос
/ 21 июля 2010

Как говорит Джим Гаррисон, OutputStream должно быть связано с чем-то ... записанные в нем байты должны куда-то уходить или же отбрасываться.

Мне кажется, вам нужно Response обернуть InputStream напрямую. На Response может быть метод вроде:

void setContent(InputStream content);

Затем, вместо записи в OutputStream, который вы предоставляете, пользователь может предоставить любой тип InputStream, который он пожелает, и ваша инфраструктура просто скопирует его в сервлет OutputStream.

Вы также можете позволить им предоставить что-то, реализующее некоторый интерфейс, подобный следующему:

interface OutputProducer {
   void writeTo(OutputStream out) throws IOException;
}

В обоих случаях вы в основном позволяете пользователю предоставлять обратный вызов для записи в OutputStream, чтобы вам не нужно было передавать его.

Я действительно не знаю, стоит ли что-то из этого, просто чтобы избежать использования выходного параметра, но это варианты.

1 голос
/ 21 июля 2010

Абстрагируйте / украсьте Request, а вместо этого получите Response.

например. в сервлете вашего фронт-контроллера:

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    Request request = new RequestImpl(req, res);
    Action action = ActionFactory.getAction(req); // Do whatever way you do to locate the `Action`.
    Response = action.get(request);
    // ...
}

где RequestImpl выглядит так:

public class RequestImpl implements Request {
    private HttpServletRequest request;
    private HttpServletResponse response;

    public RequestImpl(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    public Response newResponse(Status status) {
        return new ResponseImpl(response, status);
        // Add a boolean responseCreated to avoid creation of multiple responses? Illegal state!
    }

    public String getParameter(String name) { // Just another example of decorated method.
        return request.getParameter(name);
    }

    // ...
}

и ResponseImpl выглядят так:

public class ResponseImpl implements Response {
    private HttpServletResponse response;

    public ResponseImpl(HttpServletResponse response, Status status) {
        this.response = response;
        this.response.setStatus(status.getCode());
    }

    public OutputStream getOutputStream() {
        return response.getOutputStream();
    }

    // ...
}

который вы наконец-то используете, как это в вашем Action:

public ActionImpl implements Action {
    public Response get(Request request) {
        Response response = request.newResponse(OK);
        response.getOutputStream().write("body");
        return response;
    }
}

В качестве альтернативы, вы также можете создать Context, который принимает и HttpServletRequest и HttpServletResponse и передает его вместо Request. Это также меньше или больше того, что делает средняя структура MVC. Э.Г.

protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    Context context = new ContextImpl(req, res);
    Action action = ActionFactory.getAction(req); // Do whatever way you do to locate the `Action`.
    action.execute(context);
    context.render(); // Do here whatever you'd initially to do with the obtained Response.
}

с

public ActionImpl implements Action {
    public void execute(Context context) {
        context.getResponseOutputStream().write("body");
    }
}

Тем не менее, вместо того, чтобы изобретать, я бы посоветовал взглянуть и на существующие API. В зависимости от того, что вы хотите сделать, JSF, JAX-RS или JAX-WS могут быть тем, что вы на самом деле ищете. Если только это не для чисто хобби;)

1 голос
/ 21 июля 2010

Когда вы предоставляете клиенту OutputStream, он ДОЛЖЕН быть подключен к чему-либо, будь то буфер, сокет, файл или что-то еще, что может обрабатывать записанные в него данные.

Одним из вариантов может быть его установка в качестве PipedOutputStream, подключенного к PipedInputStream в другом потоке, который обрабатывает данные.Однако это может привести к проблемам, если поток обработки не успевает за потоком клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...