Использование пользовательского сообщения об ошибке Spring REST - PullRequest
0 голосов
/ 13 апреля 2020

Я хочу реализовать пользовательские страницы ошибок для кодов ошибок с сообщениями. Следуя инструкциям baeldung, я получил это на бэкэнде:

Пользовательское исключение:

 public class TicketNotFoundException extends RuntimeException
{
    public TicketNotFoundException(Long id)
    {
        super("Ticket not found with id: "+id);
    }
}

Пользовательский ответ:

public class CustomErrorResponse
{
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;
    private int status;
    private String error;
//getters setters
 }

Пользовательский обработчик исключений:

@ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler
{

    @ExceptionHandler(value = TicketNotFoundException.class)
    public ResponseEntity<CustomErrorResponse> customHandleNotFound(Exception ex)
    {
        CustomErrorResponse errors = new CustomErrorResponse();
        errors.setTimestamp(LocalDateTime.now());
        errors.setError(ex.getMessage());
        errors.setStatus(HttpStatus.NOT_FOUND.value());
        return new ResponseEntity<>(errors, HttpStatus.NOT_FOUND);
    }
}

И сам ответ работает:

{отметка времени: «2020-04-13 09:33:52», статус: 404, ошибка: «Билет не найден с идентификатором: 1» }

Внутренний терминал:

 Resolved [com.eggorko.ebt.ticket.TicketNotFoundException: Ticket not found with id: 1] 

Итак, мой вопрос: что мне делать на стороне клиента?

Контроллер клиента выглядит следующим образом:

@GetMapping("/{id}")
    public String ticket(@PathVariable Long id, Model model)
    {
        String url = "http://localhost:8080/api/ticket/";
        ResponseEntity<Ticket> ticket = restTemplate.getForEntity( url+ id, Ticket.class);

        model.addAttribute("ticket",ticket.getBody());
        model.addAttribute("title","Tickets");
        return "ticket";
    }

Я сделал этот бит на стороне клиента, но он не работает:

@Controller
public class MyErrorController implements ErrorController
{
    @RequestMapping("/error")
    public String handleError(HttpServletRequest  request)
    {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

        if (status != null) {
            Integer statusCode = Integer.valueOf(status.toString());

            if(statusCode == HttpStatus.NOT_FOUND.value()) {
                return "error-404";
            }
            else if(statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                return "error-500";
            }
        }
        return "error";
    }

    @Override
    public String getErrorPath()
    {
        return "/error";
    }
}

Это то, что я получил в терминале на клиенте:

2020-04-13 10:34:40.559 ERROR 12868 --- [nio-8081-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException$NotFound: 404 : [{"timestamp":"2020-04-13 10:34:40","status":404,"error":"Ticket not found with id: 1"}]] with root cause

И это переходит на страницу 500 ошибок вместо 404.

Я понимаю, почему это не работает. У меня нет ничего при обработке ошибки на стороне клиента, и она переходит к ошибке 500. Но я не знаю, что с этим делать.

ОБНОВЛЕНИЕ
Итак, я сделал это:

 String url = "http://localhost:8080/api/ticket/";
            try {
                ResponseEntity<Ticket> ticket = restTemplate.getForEntity(url + id, Ticket.class);
                model.addAttribute("ticket",ticket.getBody());
                model.addAttribute("title","Tickets");
            }catch (Exception e)
            {
                String msg = e.getMessage();
                model.addAttribute("message",msg);
                return "/error";
            }
   return "ticket";

И теперь, по крайней мере, я получаю страницу ошибки с реальным сообщением от бэкэнда. Но это решение работает вокруг MyErrorController. MyErrorController не запускается и в основном устарел.

1 Ответ

0 голосов
/ 13 апреля 2020

Вы возвращаете имя представления из своего MyErrorController, у вас есть страница ошибки errro. html или ошибка. jsp (какой суффикс вы используете для своего преобразователя представлений) в месте, которое вы указали в преобразователе представлений? Более того, вы используете одну и ту же страницу ошибок для всех кодов ошибок, вы можете создать несколько страниц ошибок для разных кодов ошибок, например error-404. jsp и error-500. jsp. Другой подход - вернуть ModelAndView вместо имени представления, вы можете сослаться на ссылку .

ОБНОВЛЕНИЕ

Хорошо, теперь я понимаю, кто вы пытаясь достичь, это дает 500, потому что вы не обрабатываете исключение в своем клиентском контроллере, когда вы делаете вызов шаблона rest, вы говорите, что я хочу получить ответ типа Ticket, но вы получаете ответ CustomErrorResponse, определите, какое исключение оно вызывает либо с помощью журнала консоли или перехвата исключения, а затем обработайте его и выполните обработку.

@GetMapping("/{id}")
    public String ticket(@PathVariable Long id, Model model)
    {
        String url = "http://localhost:8080/api/ticket/";
        try
        {
        ResponseEntity<Ticket> ticket = restTemplate.getForEntity( url+ id, 
        Ticket.class);
        }
        catch(Exception e)
        {
         // handel exception
        }

        model.addAttribute("ticket",ticket.getBody());
        model.addAttribute("title","Tickets");
        return "ticket";
    }

ИЛИ

Вы можете обернуть свой Ticket, а CustomErrorResponse является родительским классом, а затем использовать экземпляр чтобы определить, какой ответ вы получили

ResponseEntity<Parent> parent= restTemplate.getForEntity( url+ id, 
        Parent.class);
if(parent.getBody() instanceof Ticket)
{
//normal flow
}
else
{
//error
}

UPDATE2

ErrorController устарел, поскольку

String url = "http://localhost:8080/api/ticket/";
            try {
                ResponseEntity<Ticket> ticket = restTemplate.getForEntity(url + id, Ticket.class);
                model.addAttribute("ticket",ticket.getBody());
                model.addAttribute("title","Tickets");
            }catch (Exception e)
            {
                String msg = e.getMessage();
                model.addAttribute("message",msg);
                return "/error";
            }
   return "ticket";

возвращает ошибку просмотра. jsp (или. html) с моделью, она не перенаправляет на URL / ошибку, вы можете сделать это с помощью перенаправления см. , но я предлагаю не делать этого, ваш Erro rController означает исправление ошибки, произошедшей в вашем приложении, а не в каком-либо приложении, в котором вызывается ваше приложение, реализуйте соответствующую страницу ответа для такого условия.

Удачного кодирования!

...