how to clear contents of a PrintWriter after writi

2019-02-16 16:09发布

问题:

Good evening, i want to know how to clear the data written to a PrintWriter, i.e. is it possible to remove the data from a PrintWriter after printing?

here in this servlet i print some text to the response and at the line denoted by # i want to remove all the previously printed data and print new stuff:

protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    String uName = request.getParameter("uName");
    String uPassword = request.getParameter("uPassword");

    if (uName .equals("Islam")) {
        out.println("Valid-Name");
        if (uPassword !=null) {
            if (uPassword .equals("Islam")) {
                // # clear the writer from any printed data here
                out.println("Valid-password");
            } else {
                out.println("");
                out.println("InValid-password");
            }
        }
    } else {
        out.println("InValid-Name");

    }

}

Note: i tried out.flush() but the old printed text remains

回答1:

Create an in-memory PrintWriter using a StringWriter. You can get the underlying buffer from the StringWriter and clear it if you need to.

StringWriter sr = new StringWriter();
PrintWriter w = new PrintWriter(sr);

w.print("Some stuff");
// Flush writer to ensure that it's not buffering anything
w.flush();
// clear stringwriter
sr.getBuffer().setLength(0);

w.print("New stuff");

// write to Servlet out
w.flush();
response.getWriter().print(sr.toString());


回答2:

HttpServlteResponse.resetBuffer() will clear the buffered content. But yes, if the response is already flushed to the client it will throw IllegalStateException. Because it is illegal to clear after partial response is sent to the client.

resetBuffer........

void resetBuffer()
Clears the content of the underlying buffer in the response without clearing headers or status code. If the response has been committed, this method throws an IllegalStateException.

References:

Cause of Servlet's 'Response Already Committed'



回答3:

You can't do that with the original PrintWriter you get from the response, as that's backed by the actual OutputStream corresponding to the client connection. What you write there goes right to the browser via the wire (after some buffering), so you can't "take it back".

What you can do is write your message in some StringBuilder and once you know it's good to go, write it to the PrintWriter.

If you want this logic to be applied in multiple places (transparently), you can consider writing a filter that wraps the original response in an HttpServletResponseWrapper which returns a "fake" OutputStream or PrintWriter and performs this check prior to actually sending it over the wire.

public class CensorshipFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        CensorshipResponseWrapper wrapper = new CensorshipResponseWrapper(httpServletResponse);
        chain.doFilter(request, wrapper);
        String output = wrapper.sw.toString();
        if ( output.contains("Some forbidden pattern") ) { // your check goes here
            // throw exception or whatever
        } else { // write the whole thing
            httpServletResponse.getWriter().write(output);
        }
    }

    @Override
    public void destroy() {
    }

    static class CensorshipResponseWrapper extends HttpServletResponseWrapper {
        private final StringWriter sw = new StringWriter();

        public CensorshipResponseWrapper(HttpServletResponse response) {
            super(response);
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            // you may also fake the output stream, if some of your servlets use this method
            return super.getOutputStream();
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return new PrintWriter(sw);
        }
    }
}


回答4:

What ended up working for me was to change the logic of how I was outputting my data.

This is the data structure I was outputting that stored the results of a search using the text from a html form as input.

private final TreeMap<String, ArrayList<SearchResult>> searchResults;

So I was iterating over the contents of this data structure and printing it out to html.

public void writeSearchResultsToHtml(PrintWriter writer)
{
    try
    {
        JSONTreeWriter. writeSearchResultsToHtml(searchResults, writer);
    } catch (ArithmeticException | IllegalArgumentException | IOException | NoSuchElementException e)
    {
        System.err.println("Unable to write the search results builder to JSON to the file html.");
    }

    // clear results for next search otherwise
    // the next search will contain the previous
    // results, store them in history.
    searchResults.clear();
}

Clearing the data structure worked great given my servlet setup.

Here was my main serverlet loop logic:

public void startServer()
{
    // seed the database for testing
    crawler.startCrawl("http://cs.usfca.edu/~cs212/birds/birds.html");
    index.toJSON("index.json");

    // type of handler that supports sessions
    ServletContextHandler servletContext = null;

    // turn on sessions and set context
    servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
    servletContext.setContextPath("/");
    servletContext.addServlet(ViewServlet.class, "/");

    // default handler for favicon.ico requests
    DefaultHandler defaultHandler = new DefaultHandler();
    defaultHandler.setServeIcon(true);

    ContextHandler defaultContext = new ContextHandler("/favicon.ico");
    defaultContext.setHandler(defaultHandler);

    // setup handler order
    HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[]{defaultContext, servletContext});

    openWebBrowser();

    // setup jetty server
    Server server = new Server(portNumber);
    server.setHandler(handlers);
    try
    {
        server.start();
        server.join();
    } catch (Exception e)
    {
        e.printStackTrace();
    }
}