2010-07-20 54 views
1

我正在試驗一個小型的web框架,並偶然發現了一個流問題。有像Response get(HttpServletRequest)這樣的處理程序方法。從框架的角度來看,響應應該爲響應主體提供輸入流。該框架讀取這些流並將數據寫入Servlet API的底層OutputStream。但是從用戶的角度來看,需要寫一個OutputStream。用InputStream連接OutputStream

框架的角度來看:

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; 
} 

的問題是,我不能沒有輸出創建的OutputStream目標(並且不想寫入ByteArray緩衝區)。

任何想法如何給用戶一個OutputStream而不需要像在Servlet API中那樣傳遞一個OutputStream?我想避免輸出參數。

回答

1

摘要/裝飾Request以及取而代之從Response

E.g.在你前面的控制器servlet:

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這需要雙方HttpServletRequestHttpServletResponse並把它傳遞,而不是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

當您給客戶端一個OutputStream時,它必須連接到某個東西,無論是緩衝區,套接字,文件或其他可以處理寫入到其中的數據的東西。

一個選項可能是將其設置爲PipedOutputStream,該PipedOutputStream在處理數據的另一個線程中連接到PipedInputStream。但是,如果處理線程無法跟上客戶端線程,則會遇到問題。

1

正如Jim Garrison所說,必須將OutputStream連接到某些東西......寫入它的字節必須放在某個地方,否則將被丟棄。

在我看來,你需要做的就是直接用Response包裝InputStream。有可能是在Response等的方法:

void setContent(InputStream content); 

然後,而不是寫一個OutputStream您提供,用戶可以提供他們想要什麼樣的InputStream和你的框架將剛剛複製到servlet OutputStream

你也可以讓他們提供一些實現一個類似於此的一些接口:

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

在這兩種情況下,你基本上是允許用戶提供一個回調以用於寫入OutputStream,讓你不要需要通過它。

我真的不知道這是否值得它只是爲了避免使用輸出參數,但這些都是選項。

相關問題