1逞敷、錯(cuò)誤處理機(jī)制
- Spring Boot
/error
默認(rèn)提供映射狂秦,以合理的方式處理所有錯(cuò)誤,并在servlet容器中注冊為“全局”錯(cuò)誤頁面推捐。 - 對于機(jī)器客戶端裂问,它將生成一個(gè)
JSON
響應(yīng),其中包含錯(cuò)誤,HTTP狀態(tài)和異常消息的詳細(xì)信息堪簿。
對于瀏覽器客戶端痊乾,有一個(gè)“whitelabel
”錯(cuò)誤視圖,以HTML格式呈現(xiàn)相同的數(shù)據(jù)(要自定義它椭更,只需添加一個(gè)View解析為'錯(cuò)誤'的數(shù)據(jù))哪审。 - 要完全替換默認(rèn)行為,您可以實(shí)現(xiàn)
ErrorController
并注冊該類型的bean
定義虑瀑,或者只是添加類型的bean ErrorAttributes以使用現(xiàn)有機(jī)制但替換內(nèi)容湿滓。
1)、SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制
2)舌狗、如果定制錯(cuò)誤響應(yīng):
1. 如何定制錯(cuò)誤的頁面叽奥;
1)有模板引擎的情況下;error/狀態(tài)碼;
- 【將錯(cuò)誤頁面命名為 錯(cuò)誤狀態(tài)碼.html 放在模板引擎文件夾里面的error文件夾下】把夸,發(fā)生此狀態(tài)碼的錯(cuò)誤就會(huì)來到 對應(yīng)的頁面而线;
- 我們可以使用4xx和5xx作為錯(cuò)誤頁面的文件名來匹配這種類型的所有錯(cuò)誤,精確優(yōu)先(優(yōu)先尋找精確的狀態(tài)
碼.html)恋日; - 頁面能獲取的信息;
- timestamp:時(shí)間戳
- status:狀態(tài)碼
- error:錯(cuò)誤提示
- exception:異常對象
- message:異常消息
- errors:JSR303數(shù)據(jù)校驗(yàn)的錯(cuò)誤都在這里
2)沒有模板引擎(模板引擎找不到這個(gè)錯(cuò)誤頁面)嘹狞,靜態(tài)資源文件夾下找岂膳;
3)以上都沒有錯(cuò)誤頁面,就是默認(rèn)來到SpringBoot默認(rèn)的錯(cuò)誤提示頁面磅网;
2. 如何定制錯(cuò)誤的json數(shù)據(jù)谈截;
1)自定義異常處理&返回定制json數(shù)據(jù);
- 自定義異常
public class UserNotExistException extends RuntimeException {
public UserNotExistException() {
super("用戶不存在");
}
}
- 沒有自適應(yīng)效果...
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String,Object> handleException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
return map;
}
}
@ControllerAdvice 的聲明內(nèi)容
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component
- 設(shè)置什么情況下調(diào)用異常
@ResponseBody
@RequestMapping("/hello")
public String hello(@RequestParam("user") String user){
if(user.equals("aaa")){
throw new UserNotExistException();
}
return "Hello World";
}
3)轉(zhuǎn)發(fā)到/error進(jìn)行自適應(yīng)響應(yīng)效果處理
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//傳入我們自己的錯(cuò)誤狀態(tài)碼 4xx 5xx
/**
* Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user.notexist");
map.put("message","用戶出錯(cuò)啦");
request.setAttribute("ext",map);
//轉(zhuǎn)發(fā)到/error
return "forward:/error";
}
}
3. 將我們的定制數(shù)據(jù)攜帶出去涧偷;
- 出現(xiàn)錯(cuò)誤以后簸喂,會(huì)來到
/error
請求,會(huì)被BasicErrorController
處理燎潮,響應(yīng)出去可以獲取的數(shù)據(jù)是由getErrorAttributes
得到的(是AbstractErrorController(ErrorController)
規(guī)定的方法)喻鳄;
? 1. 完全來編寫一個(gè)ErrorController
的實(shí)現(xiàn)類【或者是編寫AbstractErrorController
的子類】,放在容器中确封;【不方便】
? 2. 頁面上能用的數(shù)據(jù)除呵,或者是json
返回能用的數(shù)據(jù)都是通過errorAttributes.getErrorAttributes
得到; 容器中DefaultErrorAttributes.getErrorAttributes()爪喘;
默認(rèn)進(jìn)行數(shù)據(jù)處理的颜曾;
- 給容器中加入我們自己定義的
ErrorAttributes
//給容器中加入我們自己定義的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
//返回值的map就是頁面和json能獲取的所有字段
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company","atguigu");
//我們的異常處理器攜帶的數(shù)據(jù)
Map<String,Object> ext = (Map<String, Object>) requestAttributes.getAttribute("ext", 0);
map.put("ext",ext);
return map;
}
}
8、配置嵌入式Servlet容器
1秉剑、如何定制和修改Servlet容器的相關(guān)配置泛豪;
1)修改和server有關(guān)的配置(ServerProperties
【也是EmbeddedServletContainerCustomizer】);
server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
//通用的Servlet容器設(shè)置
server.xxx
//Tomcat的設(shè)置
server.tomcat.xxx
2) 編寫一個(gè)EmbeddedServletContainerCustomizer
:嵌入式的Servlet容器的定制器;來修改Servlet容器的
配置
@Bean //一定要將這個(gè)定制器加入到容器中
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
//定制嵌入式的Servlet容器相關(guān)的規(guī)則
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
2诡曙、注冊Servlet三大組件【Servlet
吕粹、Filter
、Listener
】
ServletRegistrationBean
FilterRegistrationBean
ServletListenerRegistrationBean
前提是自己也要編寫Servlet
岗仑、
Filter匹耕、
Listener`方法【下面就不示范這三個(gè)類的編寫了】
ServletRegistrationBean
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
return registrationBean;
}
FilterRegistrationBean
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
ServletListenerRegistrationBean
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
3、使用內(nèi)置的Servlet容器
目前支持3中servlet容器
- tomcat
- jetty
- undertow
- 排除默認(rèn)使用的
Tomcat
<!-- 引入web模塊 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排除tomcat -->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
- 引入
- jetty
<!--引入其他的Servlet容器-->
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
- undertow
<!--引入其他的Servlet容器-->
<dependency>
<artifactId>spring-boot-starter-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
3荠雕、使用外置的Servlet容器
步驟
1)添加服務(wù)
- 必須在創(chuàng)建的時(shí)候稳其,創(chuàng)建
war
項(xiàng)目
- 添加Tomcat服務(wù)
-
打開配置界面
- 配置服務(wù)器
-
選擇服務(wù)器
-
配置服務(wù)器
-
部署運(yùn)行項(xiàng)目
- 配置項(xiàng)目
webapp
中的文件
- 打開配置頁面
- 配置 webapp 文件夾 和 web.xml 文件
2)必須編寫一個(gè)SpringBootServletInitializer的子類,并調(diào)用configure方法
- 通過擴(kuò)展SpringBootServletInitializer(例如在一個(gè)被調(diào)用的類中Application)創(chuàng)建可部署的war 炸卑,并添加Spring Boot @SpringBootApplication注釋既鞠。
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// Customize the application or call application.sources(...) to add sources
// Since our example is itself a @Configuration class (via @SpringBootApplication)
// we actually don't need to override this method.
return application;
}
}
請記住,無論你放入什么sources
只是一個(gè)SpringApplicationContext
盖文,通常任何已經(jīng)有效的東西都應(yīng)該在這里工作嘱蛋。可能有一些bean
可以在以后刪除五续,讓Spring Boot為它們提供自己的默認(rèn)值洒敏,但應(yīng)該可以先得到一些工作。
靜態(tài)資源可以移動(dòng)到類路徑根目錄中/public
(/static
或/resources
或 /META-INF/resources
)疙驾。相同messages.properties
(Spring Boot會(huì)在類路徑的根目錄中自動(dòng)檢測到這一點(diǎn))凶伙。
4、使用外置Servlet容器
1)目錄結(jié)構(gòu)
實(shí)例:
2)jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>HELLO</h1>
<a href="/hello" ><h2>success</h2></a>
</body>
</html>
3)視圖解析器配置
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
4)控制器
@Controller
public class controller {
@GetMapping("/hello")
public String success(Model model) {
model.addAttribute("hello", "你好它碎!");
return "success";
}
}
5)轉(zhuǎn)發(fā)至的jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>success</h1>
</body>
</html>