'How to save all the request attributes when the error is displayed (like Hibernate validator does )?

Here are two examples. What I do in both of them:

I get Dishes -> Show them on a Page -> User can choose a Dish, input an address -> if a bindingResults has errors [No dishes were chosen] -> the error is displayed on the page but the dishes are still visible.

That means that Hibernate validator somehow manages to save dishes ( that were added to model when the page is reloaded ).

Let me show this in a code. First - Spring Boot Project to show Hibernate validaor.

Put dishes to view

    @GetMapping("/menu")
    public String returnMenuSorted(
           List<Dish> dishes = dishService.findAllDishesSorted(sortField, sortDir);
        model.addAttribute("dishList", dishes);
    return "menu";
}

Process order

    @PostMapping
    public String saveOrder(@Valid @ModelAttribute OrderCreationDto order,
                            BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            return "menu";
        }
// else save order and return menu page.
}

And I print dishes with thymeleaf

                <div th:each="dish : ${dishList}">
// show for each image, name, description
</div>

Here is an example, enter image description here

Let me try to place an order with no dishes selected ( trigger bindingResult fail ).

enter image description here

As you can see, it triggers fail, page reloads and all dishes are still present..

Now let me do the same in Servlet

Put dishes to view

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
           List<Dish> dishes = dishDao.findAllDishesSorted(sortField, sortDir);
                List<DishResponseDto> dishResponseDtos = toDishResponseDtoList(dishes);
            req.setAttribute("dishes", dishResponseDtos);
            req.getRequestDispatcher("/WEB-INF/jsp/menu.jsp").forward(req, resp);
}

Process Order ( if order has no dishes selected - pass attribute "error" to view ).

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
            Map<Long, Integer> dishQuantityMap = ControllerUtil.getOrderMap(req);

        Map<String, String> viewAttributes = new HashMap<>();

    if (!OrderValidator.ifDishOrdered(dishQuantityMap)) {
            viewAttributes.put("error", Constraints.ORDER_WITHOUT_DISHES);
            isOrderValid.setValue(false);
        }

        if (!isOrderValid.booleanValue()) {
            pasErrorsToView(MENU_VIEW_PATH, req, resp, viewAttributes);
        } else {
  // save order and redirect
        }
}

Helper method that sets all provided attributes in a map to request and forwards to the page.

  public static void pasErrorsToView(String viewPath, HttpServletRequest request,
                                       HttpServletResponse response,
                                       Map<String, String> viewAttributes) throws ServletException, IOException {
        for(Map.Entry<String, String> entry : viewAttributes.entrySet())
            request.setAttribute(entry.getKey(), entry.getValue());
        request.getRequestDispatcher(viewPath).forward(request, response);
    }

Now let's test it out. enter image description here Let's place an order with no dishes selected. enter image description here

It works, but all the dishes disappears. How can I do the same in Servlets like Hibernate validator does ( save all the model attributes when error is displayed ).



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source