001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.web.servlet.error; 018 019import java.util.Collections; 020import java.util.List; 021import java.util.Map; 022 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025 026import org.springframework.boot.autoconfigure.web.ErrorProperties; 027import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace; 028import org.springframework.boot.web.servlet.error.ErrorAttributes; 029import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; 030import org.springframework.http.HttpStatus; 031import org.springframework.http.MediaType; 032import org.springframework.http.ResponseEntity; 033import org.springframework.stereotype.Controller; 034import org.springframework.util.Assert; 035import org.springframework.web.bind.annotation.RequestMapping; 036import org.springframework.web.servlet.ModelAndView; 037 038/** 039 * Basic global error {@link Controller}, rendering {@link ErrorAttributes}. More specific 040 * errors can be handled either using Spring MVC abstractions (e.g. 041 * {@code @ExceptionHandler}) or by adding servlet 042 * {@link AbstractServletWebServerFactory#setErrorPages server error pages}. 043 * 044 * @author Dave Syer 045 * @author Phillip Webb 046 * @author Michael Stummvoll 047 * @author Stephane Nicoll 048 * @see ErrorAttributes 049 * @see ErrorProperties 050 */ 051@Controller 052@RequestMapping("${server.error.path:${error.path:/error}}") 053public class BasicErrorController extends AbstractErrorController { 054 055 private final ErrorProperties errorProperties; 056 057 /** 058 * Create a new {@link BasicErrorController} instance. 059 * @param errorAttributes the error attributes 060 * @param errorProperties configuration properties 061 */ 062 public BasicErrorController(ErrorAttributes errorAttributes, 063 ErrorProperties errorProperties) { 064 this(errorAttributes, errorProperties, Collections.emptyList()); 065 } 066 067 /** 068 * Create a new {@link BasicErrorController} instance. 069 * @param errorAttributes the error attributes 070 * @param errorProperties configuration properties 071 * @param errorViewResolvers error view resolvers 072 */ 073 public BasicErrorController(ErrorAttributes errorAttributes, 074 ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) { 075 super(errorAttributes, errorViewResolvers); 076 Assert.notNull(errorProperties, "ErrorProperties must not be null"); 077 this.errorProperties = errorProperties; 078 } 079 080 @Override 081 public String getErrorPath() { 082 return this.errorProperties.getPath(); 083 } 084 085 @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) 086 public ModelAndView errorHtml(HttpServletRequest request, 087 HttpServletResponse response) { 088 HttpStatus status = getStatus(request); 089 Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes( 090 request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); 091 response.setStatus(status.value()); 092 ModelAndView modelAndView = resolveErrorView(request, response, status, model); 093 return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); 094 } 095 096 @RequestMapping 097 public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { 098 Map<String, Object> body = getErrorAttributes(request, 099 isIncludeStackTrace(request, MediaType.ALL)); 100 HttpStatus status = getStatus(request); 101 return new ResponseEntity<>(body, status); 102 } 103 104 /** 105 * Determine if the stacktrace attribute should be included. 106 * @param request the source request 107 * @param produces the media type produced (or {@code MediaType.ALL}) 108 * @return if the stacktrace attribute should be included 109 */ 110 protected boolean isIncludeStackTrace(HttpServletRequest request, 111 MediaType produces) { 112 IncludeStacktrace include = getErrorProperties().getIncludeStacktrace(); 113 if (include == IncludeStacktrace.ALWAYS) { 114 return true; 115 } 116 if (include == IncludeStacktrace.ON_TRACE_PARAM) { 117 return getTraceParameter(request); 118 } 119 return false; 120 } 121 122 /** 123 * Provide access to the error properties. 124 * @return the error properties 125 */ 126 protected ErrorProperties getErrorProperties() { 127 return this.errorProperties; 128 } 129 130}