Java Servlet parse request body multithread

2019-08-09 01:38发布

问题:

I've implemented a asynchronous Servlet, which needs to parse the body of request and store the parsed result in cache. Should I implement the parseBody() function in Servlet or implement a new class, which will do the parsing? What is the best practice?

Here is my current code snippet:

public class DocFeedServlet extends FeedServlet {

private static final Logger LOGGER = LoggerFactory.getLogger(DocFeedServlet.class);
private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();


public void init(ServletConfig config) throws ServletException {
    super.init(config);
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    final AsyncContext asyncContext = req.startAsync();
    asyncContext.start(new Runnable() {
        @Override
        public void run() {
            String bodyStr = getBody(req);
            if (bodyStr.isEmpty()) {
                resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                asyncContext.complete();
                return;
            }

            int ignoreTime = Integer.parseInt(req.getParameter(Constant.PARAM_IGNORE_TIME));

            List<MockDocCacheKeyVal> mockDocCacheKeyVals = new ArrayList<>();
            List<String> docUpdateFields = new ArrayList<>();
            List<List<String>> docKeepFields = new ArrayList<List<String>>();
            List<String> uuidsToRemove = new ArrayList<>();

            int parseRet = parseBody(bodyStr, mockDocCacheKeyVals, docUpdateFields, docKeepFields, uuidsToRemove, ignoreTime);

            if (parseRet != 0) {
                resp.setStatus(HttpServletResponse.SC_OK);
            } else {
                resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
            asyncContext.complete();
        }
    });
}

protected int parseBody(String body, List<MockDocCacheKeyVal> mockDocCacheKeyVals, List<String> docUpdateFields, List<List<String>> docKeepFields, List<String> uuidsToRemove, int ignoreTime) {
    try {
        ObjectReader reader = OBJECTMAPPER.reader(new TypeReference<List<Document>>() { });
        List<Document> documents = reader.readValue(body);
        for (Document doc : documents) {
            if (doc.getAction() != null && doc.getAction().equalsIgnoreCase(Constant.DOC_FEED_ACTION_DELETE)) {
                if (doc.getUuid() != null) {
                    uuidsToRemove.add(doc.getUuid());
                }
                continue;
            }
            if (doc.getA() != null) {

            } else if (doc.getB() != null) {

            } else {
                DocumentUtils.pruneWeightSet(doc.getC(), cPruneSize);
                DocumentUtils.pruneWeightSet(doc.getD(), dPruneSize);
                DocumentUtils.pruneWeightSet(doc.getE(), ePruneSize);
            }
        }
        return documents.size();
    } catch (Exception e) {
        LOGGER.error(e.getMessage());
    }
    return 0;
}
}

Thanks.

回答1:

Asynchronous Request Body read is accomplished with the HttpServletRequest.getInputStream().setReadListener(ReadListener) concepts introduced in Servlet 3.1

You will only read based on events from your ReadListener, and you will only read enough to not block. (so no reading multi-megabyte buffers!).

This API is what you are looking for, however there be land mines here, so be sure you fully understand the API before you finish it.