Как Настроить Временные Метки Ошибок Spring, Не Вызывая Исключений?

#spring-boot

Вопрос:

Когда в моем бэкэнде возникают ошибки, SpringBoot возвращает результат json с ошибками.
Я хотел изменить метку времени в json, чтобы она была читаемой, поэтому я настроил атрибуты:

 @Component
public class CustomErrorAttributes extends DefaultErrorAttributes {

  private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
  private static final String TIMESTAMP = "timestamp";

  @Override
  public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {

    //Let Spring handle the error first
    Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);

    //Format amp; update timestamp
    Object timestamp = errorAttributes.get(TIMESTAMP);
    if(timestamp == null) {
      errorAttributes.put(TIMESTAMP, dateFormat.format(new Date()));
    } else {
      errorAttributes.put(TIMESTAMP, dateFormat.format((Date)timestamp));
    }

    return errorAttributes;
  }
}
 

Однако теперь, когда есть 404, из-за этой настройки возникает исключение:

E 23:21:36 88 [DispatcherServlet].log — Servlet.service() для сервлета [DispatcherServlet] выдал исключение
java.lang.Исключение ClassCastException: java.lang.Строка не может быть приведена к java.util.Date
в org.springframework.boot.autoconfigure.web.servlet.ошибка.Ошибка автоконфигурации$StaticView.render(ошибка автоконфигурации.java:224) ~[весенняя загрузка-автоконфигурация-2.1.4.РЕЛИЗ.jar:2.1.4.РЕЛИЗ]

Конфигурация ErrorMvcAutoConfiguration пытается проанализировать атрибут метки времени:

     @Override
    public void render(Map<String, ?> model, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        if (response.isCommitted()) {
            String message = getMessage(model);
            logger.error(message);
            return;
        }
        StringBuilder builder = new StringBuilder();
        Date timestamp = (Date) model.get("timestamp");
 

Как я могу настроить метку времени в ответе на ошибку, не влияя на другую стандартную обработку ошибок?

Ответ №1:

Похоже, вы работаете с устаревшей версией spring mvc.
И мы говорим о ErrorMvcAutoConfiguration.java
Там была ошибка: Смотрите здесь

Он был исправлен в фиксации d1d953819ac9f0c0ece5160b96899030cabda46c 12 сентября 2020 года в репозитории spring boot Филом Уэббом в версии 2.2.x, а также был объединен в версии 2.3.x и 2.4.x.

Так что теперь это выглядит так:

     private static class StaticView implements View {

        private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);

        private static final Log logger = LogFactory.getLog(StaticView.class);

        @Override
        public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            if (response.isCommitted()) {
                String message = getMessage(model);
                logger.error(message);
                return;
            }
            response.setContentType(TEXT_HTML_UTF8.toString());
            StringBuilder builder = new StringBuilder();
            // !!!note this line!!!!
            Object timestamp = model.get("timestamp");
            Object message = model.get("message");
            Object trace = model.get("trace");
            if (response.getContentType() == null) {
                response.setContentType(getContentType());
            }
            builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
                    "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
                     // !!! and this line !!!
                    .append("<div id='created'>").append(timestamp).append("</div>")
                    .append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
                    .append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
            if (message != null) {
                builder.append("<div>").append(htmlEscape(message)).append("</div>");
            }
            if (trace != null) {
                builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
            }
            builder.append("</body></html>");
            response.getWriter().append(builder.toString());
 

Сказав это, обычно люди настраивают страницу ошибок (по крайней мере, по моему опыту) и даже не используют это представление по умолчанию.

Об этом есть множество учебных пособий, вот одно из них