在這個程序中我們還可以讓這個程序成為一個受應用服務管理的Servlet程序。可以將注解改成@WebServlet("/others/servlet")。只是換成這個注解還并不能生效,還需要在啟動類(任何配置類上)添加@ServletComponentScan注解。
環(huán)境:Springboot2.4.12
概述
當一個請求過來后Spring是如何進行處理的?下面簡單的羅列下請個的過程中核心組件
SpringMVC處理的流程:
- DispatcherServlet 所有請求的入口
- HandlerMApping 將請求地址與處理程序關聯(lián)
- HandlerAdapter 真正處理程序,如執(zhí)行上一步中對應的處理程
- HandlerMethodArgumentResolver 對參數(shù)進行解析,這里面還涉及到很多其它東西
- HanlderMethodReturnValueHandler 對返回值進行輸出處理
- ViewResolver 結果HandlerAdapter返回的有ModelAndView則會應用視圖解析器
常規(guī)Controller定義
@RestController
@RequestMapping("/users")
public class UsersController {
@GetMapping("/save")
public Object save(Users users) {
return users ;
}
}
上面這個Controller接口是我們最常的定義方法,對于絕大多數(shù)人來說或許也就知道這樣去定義Controller接口,而這種定義Controller方式基本上已經可以滿足我們日常的所有操作了。接下來看看其它的定義Controller方法
HttpRequestHandler
@Component("/others/chrh")
public class ControllerHttpRequestHandler implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter() ;
out.print("<h1>你好,HttpRequestHandler</h1>") ;
out.close() ;
}
}
定義一個類實現(xiàn)HttpRequestHandler接口即可,注意這里注解@Component("/others/chrh")使用的以‘/’ 開頭,為什么這么定義?在概述中說到HandlerMapping是用來將請求地址與處理程序關聯(lián)起來,在常規(guī)中都是使用@RequestMapping定義接口請求地址,那在這里我們是不能用該注解的,但是又要讓容器知道我們這個接口就必須使用'/'開頭,這樣就會有一個 BeanNameUrlHandlerMapping的HandlerMapping將我們這個Bean進行收集保存起來,以 /others/chrh為key,Bean對象為value保存到Map中。
測試
圖片
Controller接口
定義一個Bean實現(xiàn)該即可
@Component("/others/custom")
public class CustomController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter() ;
out.print("<h1>Controller接口</h1>") ;
out.close() ;
return null ;
}
}
Bean的名稱還是以'/' 開頭,那么還是由BeanNameUrlHandlerMapping與之關聯(lián)
測試
圖片
繼承HttpServlet
這里的判斷依據(jù)就是你的這個Bean是否是Servlet接口類型(有沒有實現(xiàn)Servlet接口)。
@Component("/others/servlet")
public class ControllerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter() ;
out.print("<h1>你好 HttpServlet</h1>") ;
out.close() ;
}
}
這樣看起來就是個標準的Servlet程序。
如果你只是這樣,那這可運行不起來,你還需要注冊一個
SimpleServletHandlerAdapter。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public SimpleServletHandlerAdapter simpleServletHandlerAdapter() {
return new SimpleServletHandlerAdapter() ;
}
}
測試
圖片
在這個程序中我們還可以讓這個程序成為一個受應用服務管理的Servlet程序。可以將注解改成@WebServlet("/others/servlet")。只是換成這個注解還并不能生效,還需要在啟動類(任何配置類上)添加@ServletComponentScan注解。
以上就是在SpringMVC中支持的幾種接口定義處理方式。
下一篇文章會對上面幾種實現(xiàn)的方式進行源碼分析,一個請求是如何知道使用哪個HandlerMapping的,找到了HandlerMapping又是怎么確定由哪個HandlerAdapter處理的(在上面的例子中,每一種實現(xiàn)他們的實現(xiàn)方法都不一樣,所以一定的需要不同的HandlerAdapter進行處理);通過源碼的分析,讓你知其然,知其所以然。關注我讓你對Spring源碼不再畏懼。