spring boot 二 servlet listenerfilter interceptor
一般做web開發,使用controller就可以滿足大部分的需要,但是有的時候也會用到servlet listener filter 和interceptor等,spring boot中取消了繁雜的xml配置,但是功能並沒有減少,所以要對於這些需求,也有相應的解決辦法。
servlet
我們知道spingMVC的主servlet 是DispatcherServlet,其默認的url-pattern爲“/”,當然springboot也是,spring boog中添加servlet有兩種方法,代碼註冊Servlet和註解自動註冊Servlet,spring boot中filter和listener的添加同樣也是這兩種方法。不過springboot大量使用註解,來簡化配置,應該是比較推薦使用註解來自動註冊Servlet吧
第一種,通過註解自動註冊Servlet,先在啓動類上加上註解@ServletComponentScan,來掃描算定義的servlet,
啓動類示例:
@SpringBootApplication
@ServletComponentScan
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
示例DemoServlet2.java
@WebServlet(urlPatterns="/gaox/hello",description="測試")
public class DemoServlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponseresp)
throws ServletException, IOException {
// TODO Auto-generatedmethod stub
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("hello ,baby !");
}
}
run as 啓動類啓動,在瀏覽器中輸入http://localhost:8080/gaox/hello,結果:
第二種,通過代碼來註冊servlet,新建一個普通的類繼承HttpServlet,重寫service或doGet 、doPost方法,示例DemoServlet.java:
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
// TODO Auto-generatedmethod stub
request.setCharacterEncoding("utf-8");
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
response.getWriter().print("測試一下");
}
}
然後把自己自定義的Servlet、監聽器、過濾器,在啓動的時候註冊到容器中,示例:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
/**
* 註冊自定義的servlet
* @return
*/
@Bean
public ServletRegistrationBean getServletRegistrationBean(){
return new ServletRegistrationBean(new DemoServlet(),"/gaox/demo");
}
/**
* 註冊自定義的監聽器
* @return
*/
@Bean
public ServletListenerRegistrationBeangetServletListenerRegistrationBean(){
return new ServletListenerRegistrationBean(newDemoListener3());
}
/**
* 註冊自定義的過濾器
* @return
*/
@Bean
public FilterRegistrationBean getFilterRegistrationBean(){
FilterRegistrationBean registrationBean=newFilterRegistrationBean();
registrationBean.setFilter(new DemoFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}}
run as 啓動類啓動,在瀏覽器中輸入http://localhost:8080/gaox/demo,結果:
listener
在java web應用中,listener監聽器似乎是必不可少的,常常用來監聽servletContext、httpSession、servletRequest等域對象的創建、銷燬以及屬性的變化等等,可以在這些事件動作前後進行一定的邏輯處理。
而我暫時先說其中三個用來監聽域對象的,分別是servletContextListener、httpSessionListener、servletRequestListener。 這三個接口寫法上實際是差不多的,都有兩個分別代表了該域對象創建時調用和銷燬時調用的方法,這三個對象最大的區別應該就是作用域不一樣。 servletContext在整個應用啓動到結束中生效,啓動系統時創建這個對象,整個過程中這個對象是唯一的。 httpSession則是在一個session會話中生效,在一個session被創建直到失效的過程中都起作用,不過一個啓動的應用中httpSession對象可以有多個,比如同一臺電腦兩個瀏覽器訪問,就會創建兩個httpSession對象。 而servletRequest是在一個request請求被創建和銷燬的過程中生效,每發起一次請求就會創建一個新的servletRequest對象,比如刷新瀏覽器頁面、點擊應用的內鏈等等。
監聽器以及過慮器的添加與servlet的添加一樣,也是兩種方法,通過代碼註冊與註解自動註冊,方法很類似,其實就是註冊的方式不同,一種是用註解,別一種就是代碼,兩種訪求的共同點就是都要繼承或實現相應的接口,新建一個實例,然後就是用不同的方式注入到容器裏。上面已經在代碼中體現了怎麼把servlet、listener、filter用代碼注入到容器中,這裏只貼出用註解怎麼註冊listener、filter,如果想用代碼來註冊,那就把相應的解去掉,然後在啓動的時候用代碼把自己自定義的listener、filter實例添加進去即可。
DemoListener.java:
@WebListener
public class DemoListener implements HttpSessionListener {
private Loggerlog=Logger.getLogger(DemoListener2.class);
@Override
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generatedmethod stub
log.info("會話範圍內的監聽器創建/HttpSessionListener");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// TODO Auto-generatedmethod stub
log.info("會話範圍內監聽器被銷燬/HttpSessionListener");
}
}
DemoListener2.java
@WebListener
public class DemoListener2 implements ServletContextListener {
private Loggerlog=Logger.getLogger(DemoListener2.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generatedmethod stub
log.info("全局的監聽器初始化/ServletContextListener");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generatedmethod stub
log.info("全局監聽器被銷燬/ServletContextListener");
}
}
DemoListener3.java
@WebListener
public class DemoListener3 implements ServletRequestListener {
private Loggerlog=Logger.getLogger(DemoListener2.class);
@Override
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generatedmethod stub
log.info("請求作用域內監聽器結束被銷燬/ServletRequestListener");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
// TODO Auto-generatedmethod stub
log.info("請求作用域內被初始化/ServletRequestListener");
}
}
Filter
@WebFilter(urlPatterns="/*",filterName="demoFilter")
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig)throws ServletException {
// TODO Auto-generatedmethod stub
System.out.println("過濾器初始化");;
}
@Override
public void doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generatedmethod stub
System.out.println("通過過濾器");
chain.doFilter(request,response);
}
@Override
public void destroy() {
// TODO Auto-generatedmethod stub
System.out.println("過濾器衩銷燬");
}
}
執行結果:
HandlerInterceptor的功能跟過濾器類似,但是提供更精細的的控制能力:在request被響應之前、request被響應之後、視圖渲染之前以及request全部結束之後。我們不能通過攔截器修改request內容,但是可以通過拋出異常(或者返回false)來暫停request的執行。
配置攔截器也很簡單,Spring提供了基礎類WebMvcConfigurerAdapter,我們只需要重寫
addInterceptors方法添加註冊攔截器。實現自定義攔截器只需要3步:
1、創建我們自己的攔截器類並實現 HandlerInterceptor接口。
2、創建一個Java類繼承WebMvcConfigurerAdapter,並重寫 addInterceptors方法。
2、實例化我們自定義的攔截器,然後將對像手動添加到攔截器鏈中(在addInterceptors方法中添加)。
MyInterceptor.java:
public class MyInterceptor implements HandlerInterceptor{
private Loggerlog=Logger.getLogger(MyInterceptor.class);
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Objectarg2, Exception arg3)
throws Exception {
// TODO Auto-generatedmethod stub
log.info("1>>>MyInterceptor1>>>>>>>在整個請求結束之後被調用,也就是在DispatcherServlet渲染了對應的視圖之後執行(主要是用於進行資源清理工作)");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponsearg1,
Object arg2, ModelAndViewarg3) throws Exception {
// TODO Auto-generatedmethod stub
log.info("1>>>MyInterceptor1>>>>>>>請求處理之後進行調用,但是在視圖被渲染之前(Controller方法調用之後)");
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
// TODO Auto-generatedmethod stub
log.info("1>>>MyInterceptor1>>>>>>>在請求處理之前進行調用(Controller方法調用之前)");
return true;// 只有返回true纔會繼續向下執行,返回false取消當前請求
}
}
MyInterceptor2.java
public class MyInterceptor2 implements HandlerInterceptor{
private Loggerlog=Logger.getLogger(MyInterceptor2.class);
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Objectarg2, Exception arg3)
throws Exception {
// TODO Auto-generatedmethod stub
log.info("2>>>MyInterceptor1>>>>>>>在整個請求結束之後被調用,也就是在DispatcherServlet渲染了對應的視圖之後執行(主要是用於進行資源清理工作)");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponsearg1,
Object arg2, ModelAndViewarg3) throws Exception {
// TODO Auto-generatedmethod stub
log.info("2>>>MyInterceptor1>>>>>>>請求處理之後進行調用,但是在視圖被渲染之前(Controller方法調用之後)");
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
// TODO Auto-generatedmethod stub
log.info("2>>>MyInterceptor1>>>>>>>在請求處理之前進行調用(Controller方法調用之前)");
return true;// 只有返回true纔會繼續向下執行,返回false取消當前請求
}
}
CustomMVCConfiguration.java:
@Configuration
public class CustomMVCConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// TODO Auto-generatedmethod stub
super.addInterceptors(registry);
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
}
}
run as 啓動類後,在瀏覽器中輸入http://localhost:8081/gaox/test3
結果:
有興趣可以到碼雲上獲取源碼仔細研究:https://gitee.com/fox9916/springboot_demo.git