简介###
客户端两个,针对两类用户,渲染的H5页面各有不同,报错处理页面也存在区别;将所有服务放置同一个Web项目,需要在报错的时候指向不同的错误页面;
最开始的想法是通过区分服务路径,最终证明此方法可行,如下是实现步骤。
启动类定义EmbeddedServletContainerCustomizer对象###
这里定义的error page 路径与MainsiteErrorController相关联;
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new EmbeddedServletContainerCustomizer(){
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
container.addErrorPages(new ErrorPage(java.lang.Throwable.class,"/error/500"));
}
};
}
实现ErrorController接口###
@Controller
@RequestMapping(value = "error")
@EnableConfigurationProperties({ ServerProperties.class })
public class MainsiteErrorController implements ErrorController {
private static final String REQUEST_PATH_KEY = "path";
private static final Logger logger = LoggerFactory.getLogger(MainsiteErrorController.class);
private ErrorAttributes errorAttributes;
@Autowired
private ServerProperties serverProperties;
/**
* 初始化ExceptionController
*
* @param errorAttributes
*/
@Autowired
public MainsiteErrorController(ErrorAttributes errorAttributes) {
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
this.errorAttributes = errorAttributes;
}
/**
* 定义404的ModelAndView
*
* @param request
* @param response
* @return
*/
@RequestMapping(produces = "text/html", value = "404")
public ModelAndView errorHtml404(HttpServletRequest request, HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
return new ModelAndView(this.getTerminalErrorPageByRequestURL(model, "404"), model);
}
/**
* 定义404的JSON数据
*
* @param request
* @return
*/
@RequestMapping(value = "404")
@ResponseBody
public ResponseEntity<Map<String, Object>> error404(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
/**
* 定义500的ModelAndView
*
* @param request
* @param response
* @return
*/
@RequestMapping(produces = "text/html", value = "500")
public ModelAndView errorHtml500(HttpServletRequest request, HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
return new ModelAndView(this.getTerminalErrorPageByRequestURL(model, "500"), model);
}
/**
* 定义500的错误JSON信息
*
* @param request
* @return
*/
@RequestMapping(value = "500")
@ResponseBody
public ResponseEntity<Map<String, Object>> error500(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
/**
* Determine if the stacktrace attribute should be included.
*
* @param request
* the source request
* @param produces
* the media type produced (or {@code MediaType.ALL})
* @return if the stacktrace attribute should be included
*/
protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
ErrorProperties.IncludeStacktrace include = this.serverProperties.getError().getIncludeStacktrace();
if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
return true;
}
if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
return getTraceParameter(request);
}
return false;
}
/**
* 获取错误的信息
*
* @param request
* @param includeStackTrace
* @return
*/
private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
}
/**
* 是否包含trace
*
* @param request
* @return
*/
private boolean getTraceParameter(HttpServletRequest request) {
String parameter = request.getParameter("trace");
if (parameter == null) {
return false;
}
return !"false".equals(parameter.toLowerCase());
}
/**
* 获取错误编码
*
* @param request
* @return
*/
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
try {
return HttpStatus.valueOf(statusCode);
} catch (Exception ex) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
private String getTerminalErrorPageByRequestURL(Map<String, Object> model, String errorCode) {
String path = ((String) model.get(REQUEST_PATH_KEY));
String terminalErrorPage = path.startsWith(GenericConstants.STUDENT_TERMINAL_TYPE)
? GenericConstants.STUDENT_TERMINAL_TYPE.concat("/").concat(errorCode) : errorCode;
terminalErrorPage = "errorpage/" + terminalErrorPage;
logger.debug("errorPage -> {}", terminalErrorPage);
return terminalErrorPage;
}
/**
* 实现错误路径,暂时无用
*
* @see ExceptionMvcAutoConfiguration#containerCustomizer()
* @return
*/
@Override
public String getErrorPath() {
return "";
}
}
其中较为关键的方法是getTerminalErrorPageByRequestURL方法,该方法会根据请求的path找到各客户端请求前缀(通过前缀区分提供给不同客户端的服务,以此报错时指向不同的错误页面)
这是基于Thymeleaf+SpringBoot实现的网站http://www.hqast.com/