Весна mvc тимьян. Как показать страницу ошибки whitelabel как модальную или всплывающую или тостовую - PullRequest
2 голосов
/ 19 февраля 2020

У меня проблема с отображением ошибок в приложении Spring mvc. Итак, позвольте мне описать более подробно о проблеме.

Я уже знаю, что делать, если я хочу показать пользовательскую страницу ошибки вместо стандартной страницы ошибки белой метки. Я читал об этом здесь и смотрел несколько уроков по youtube . Это просто, но проблема в том, что пользователь всегда будет перенаправлен на новую страницу, содержащую описание ошибки.

Я хочу отобразить все свои исключения бэкэнда в указанном формате c в виде модального окна или предупреждающего сообщения или тост, как показано здесь , но для тимьяна. Лучшее решение - модальные страницы, потому что это дает мне больше гибкости в отображении контента. Но модальный может быть вызван при использовании JavaScript на стороне интерфейса, как использовать исключения контроллера в качестве триггера для открытия модальной страницы (без использования AJAX, если это возможно)?

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

@GetMapping
public ModelAndView throwException() throws Exception {
    throw new Exception("Oops :( something went wrong");
}

что-то подобное должно отображаться окно ошибки

Пожалуйста, помогите мне найти решение. Большое спасибо за ваше внимание.

PS, если это сложно или невозможно, я хочу знать, как минимум, как показать сообщение об ошибке от контроллера + некоторые кнопки или поля ввода, связанные с ошибкой на текущей (той же) странице, без перенаправления к новому?

1 Ответ

1 голос
/ 20 февраля 2020

TL; DR

Легкого выхода нет. Если бы я был тобой, я бы использовал общие страницы ошибок c. Вы можете настроить их для различных типов ошибок.

Инструменты, не отвечающие вашей проблеме.

IMO Описанная вами проблема лучше подходит для SPA (одностраничного приложения), написанного на любом современном каркас внешнего интерфейса с java бэкэндом, предоставляющим REST API. Обычно enpoint возвращает json, содержащий фактические запрошенные данные. Но в случае любой ошибки вы можете просто вернуть код 4xx с описанием ошибки в качестве полезной нагрузки. Тогда логи презентации c в javascript могут отображать все что угодно без перезагрузки страницы.

Поскольку вы решили использовать тимилиф, который является движком шаблонов, вы должны принять его ограничения. Большинство вызовов к контроллеру - это запрос на просмотр. Spring and Thymeleaf берет файл шаблона, заполняет его данными модели и отправляет обратно всю страницу в ваш браузер. Если этот процесс завершится неудачно во время сбора данных, страница не будет правильно отображена. Поэтому самое разумное, что нужно сделать - перенаправить на страницу с ошибкой.

Разумный выход

Если страницы ошибок generi c отпугивают вас, можно предпринять дополнительные усилия. Вместо общей обработки ошибок c вы можете обрабатывать исключения в каждом методе контроллера. В случае ошибки вы можете указать другую модель с ошибками, которая будет использоваться для заполнения шаблона. Это дает вам гибкость в том, как отображается ошибка. Это будет зависеть от того, как вы подготовили шаблон.

Например:

Просмотр. html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>Data:</h1>
    <div th:if="${actualData}">
        <p th:text="${actualData}"></p>
    </div>
    <!-- Instead of div below, you could supply a modal and pice of javascript opening it -->
    <div th:if="${errorData}">
        <h3>Error occurred:</h3>
        <p th:text="${errorData}"></p>
    </div>
</body>
</html>

MyController. java

@Controller
class MyController {

    @GetMapping("/view")
    public String view(Model model) {
        try {
            model.addAttribute("actualData", mayThrowExceptionDataFetch());
        } catch(Exception e) {
            model.addAttribute("errorData", e.getMessage());
        }
        return "view";
    }

    private String mayThrowExceptionDataFetch() {
        // Either return a value or throw an exception
    }
}

Таким образом, представление всегда будет возвращаться. Даже при возникновении ошибки она обрабатывается и отображается.

Необоснованный выход

Важное примечание: Это только демонстрационная версия. Конечно, я бы не попробовал это в работе.

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

  1. Интерфейс: подписаться на конечную точку событий отправки сервера (источник ошибок).
  2. Бэкэнд: при перехвате исключения отменить запрос так что сервер ничего не возвращает.
  3. Backend: отправьте сообщение, содержащее описание ошибки, клиенту-зависимому.
  4. Frontend: получите событие, предупредите его как-нибудь.

Затем я создаю эту рабочую демонстрацию, которая действительно не вызывает перезагрузки страницы, но отображает ошибку:

index. html

<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
</head>
<body>
    <a th:href="@{/exception}">Click for exception</a>
    <script>
        var sse = new EventSource('http://localhost:8080/sse');
        sse.onmessage = function (evt) {
            alert(evt.data);
        };
    </script>
</body>
</html>

MyService. java

@Service
public class MyService {

    private final SseEmitter emitter = new SseEmitter();

    public SseEmitter getEmitter() {
        return emitter;
    }
}

MyExceptionHandler. java

@ControllerAdvice
public class MyExceptionHandler {

    private final MyService service;

    @Autowired
    public MyExceptionHandler(MyService service) {
        this.service = service;
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.CONTINUE) // I don't figure out how to abort request
    public ResponseEntity<Void> handle(Exception ex) {
        try {
            service.getEmitter().send(SseEmitter.event().data(ex.getMessage()));
        } catch (IOException e) {
            // TODO
        }
    }
}

MyController. java

@Controller
public class MyController {

    private final MyService service;

    @Autowired
    public MyCtrl(MyService service) {
        this.service = service;
    }

    @GetMapping("/sse")
    public SseEmitter sse() {
        return service.getEmitter();
    }

    @GetMapping("/index")
    public String index() {
        return "index";
    }

    @GetMapping("/exception")
    public String exception() {
        throw new RuntimeException("Oops :o");
    }
}

Все вышеперечисленное - это проект весенней загрузки с зависимостями spring-boot-starter-thymeleaf и spring-boot-starter-web. Запустите приложение, go до localhost:8080/index, затем нажмите на ссылку. Предупреждение должно появляться без перезагрузки страницы.

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