從servlet到spring mvc

一:什麼是servlet

Java Servlet 簡稱servlet是運行在 Web 服務器或應用服務器上的程序,它是作爲來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務器上的數據庫或應用程序之間的中間層。

使用 Servlet,您可以收集來自網頁表單的用戶輸入,呈現來自數據庫或者其他源的記錄,還可以動態創建網頁。


二:WEB三大組件及Servlet實現

1.servlet;2.filter;3.listener;


原始版Servlet例子:

1.創建工程:servlet-xml image.png
2.創建servlet:

package com.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ServletDemo
 */
public class ServletDemo extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ServletDemo() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("GBK");
        response.getWriter().write("菜鳥教程:https://www.runoob.com/servlet/servlet-intro.html");
    }
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

3.web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <servlet-name>ServletDemo</servlet-name>
    <servlet-class>com.servlet.ServletDemo</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletDemo</servlet-name>
    <url-pattern>/ServletDemo</url-pattern>
  </servlet-mapping>
</web-app>

4.啓動tomcat,訪問http://localhost:8080/servlet-xml/ServletDemo
image.png


註解的Servlet例子

不用web.xml配置,用註解也可以使用servlet,查看servlet官方文檔:
image.png
大概意思是說框架提供了ServletContainerInitializer的實現,必須是綁定在META/INF/services目錄下,文件爲:javax.servlet.ServletContainerInitializer,文件裏包含ServletContainerInitializer的實現類的目的地,類路徑。

1.新建工程servlet-anno,也是 Dynamic web project。
2.新建javax.servlet.ServletContainerInitializer文件。
image.png
3.新建servlet:

package com.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OrderServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub
        resp.getWriter().write("testServlet...order");
    }

}

4.監聽器的實現:

package com.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * 監聽應用的啓動和停止
 */
public class OrderListener implements ServletContextListener {

    
    //監聽ServletContext銷燬
    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        System.out.println("OrderListener...contextDestroyed...");
    }

    //監聽ServletContext啓動初始化
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        ServletContext servletContext = arg0.getServletContext();
        System.out.println("OrderListener...contextInitialized...");
    }

}

5.過濾器:

package com.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class OrderFilter implements Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        // 過濾請求
        System.out.println("UserFilter...doFilter...");
        //放行
        arg2.doFilter(arg0, arg1);
        
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
        
    }

}

6.實現ServletContainerInitializer,即servlet容器初始化,主要是做三大組件的註冊。

package com.servlet;

import java.util.EnumSet;
import java.util.Set;

import javax.servlet.DispatcherType;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import com.service.TestService;

//容器啓動的時候會將@HandlesTypes指定的這個類型下面的子類(實現類,子接口等)傳遞過來;
//傳入感興趣的類型;
@HandlesTypes(value={TestService.class})
public class TestServletContainerInitializer implements ServletContainerInitializer{

    @Override
    public void onStartup(Set<Class<?>> arg0, ServletContext arg1) throws ServletException {
        System.out.println("感興趣的類型:");
        for (Class<?> claz : arg0) {
            System.out.println(claz);//當傳進來後,可以根據自己需要利用反射來創建對象等操作
        }
        //註冊servlet組件
        javax.servlet.ServletRegistration.Dynamic servlet = arg1.addServlet("orderServlet", new OrderServlet());
        //配置servlet的映射信息(路徑請求)
        servlet.addMapping("/orderTest");
        
        //註冊監聽器Listener
        arg1.addListener(OrderListener.class);
        
        //註冊Filter
        javax.servlet.FilterRegistration.Dynamic filter = arg1.addFilter("orderFilter", OrderFilter.class);
        //添加Filter的映射信息,可以指定專門來攔截哪個servlet
        filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        
    }

}

tomcat啓動加載應用的時候,會運行onStartup方法;
Set<Class<?>> arg0:感興趣的類型的所有子類型(對實現了
TestService接口相關的);
ServletContext arg1:代表當前Web應用的ServletContext;一個Web應用一個ServletContext;
1)、使用ServletContext註冊Web組件(Servlet、Filter、Listener)
2)、使用編碼的方式,在項目啓動的時候給ServletContext裏面添加組件;

啓動tomcat:
image.png
如圖啓動的時候打印出了3個感興趣的類即實現了TestService接口的;另外打印出了監聽器的日誌,即ServletContext啓動創建的時候。


訪問http://localhost:8080/servlet-anno/orderTest即可進入對應的servlet:即進入了過濾器
image.png


除了在ServletContainerInitializer註冊servlet還可以用註解@WebServle來加入組件:新增如下代碼並重啓tomcat

@WebServlet("/anno")
public class TestServlet  extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("servlet-anno....success");
    }
}

訪問http://localhost:8080/servlet-anno/anno也是OK的


三.Spring mvc

spring-mvc整合也是基於servlet的,基於註解版的servlet。

1.新建maven工程:加入依賴

      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>3.0-alpha-1</version>
            <scope>provided</scope>
        </dependency>

2.查看spring依賴包:

image.png

①可找到javax.servlet.ServletContainerInitializer文件爲:org.springframework.web.SpringServletContainerInitializer.


②即SpringServletContainerInitializer爲servlet容器的初始化類,容器啓動調用onStartup方法:查看代碼發現主要是做了把感興趣的類做一下判斷然後調用各自的onStartup方法。

這個感興趣的類是重點:@HandlesTypes(WebApplicationInitializer.class)
image.png

image.png


③WebApplicationInitializer在spring-web中有三個實現類:
a:AbstractContextLoaderInitializer--主要是註冊監聽器.
image.png
b:AbstractDispatcherServletInitializer--主要是DispatcherServlet容器初始化,如圖註冊servlet,filter步驟都和註解版servlet步驟類似。
image.png
c:AbstractAnnotationConfigDispatcherServletInitializer--提供了註解方式配置的dispatcherServlet初始化器,即如下2個方法:
1.getRootConfigClasses()根容器(存放service業務層,repositories數據庫dao層及事務控制相關處理);
2.getServletConfigClasses() 即servlet容器(存放controller,視圖解析,映射相關)。
image.png

如官網圖https://docs.spring.io/spring...
image.png


3.基於註解整合spring-mvc

新建一個初始化器:

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.enjoy.config.TestAppConfig;
import com.enjoy.config.TestRootConfig;


//web容器啓動的時候創建對象;調用方法來初始化容器以前前端控制器
public class TestWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    //獲取根容器的配置類;(Spring的配置文件)   父容器;
    @Override
    protected Class<?>[] getRootConfigClasses() {
        //指定配置類(配置文件)位置
        return new Class<?>[]{TestRootConfig.class} ;
    }

    //獲取web容器的配置類(SpringMVC配置文件)  子容器(servlet容器);
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{TestAppConfig.class} ;
    }

    //獲取DispatcherServlet的映射信息
    //  /:攔截所有請求(包括靜態資源(xx.js,xx.png)),但是不包括*.jsp;
    //  /*:攔截所有請求;連*.jsp頁面都攔截;jsp頁面是tomcat的jsp引擎解析的;
    @Override
    protected String[] getServletMappings() {
        // TODO Auto-generated method stub
        return new String[]{"/"};
    }

}

再來看看父容器TestRootConfig和servlet容器TestAppConfig配置類:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

//Spring的容器不掃描controller;父容器
@ComponentScan(value="com.enjoy",excludeFilters={
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
public class TestRootConfig {

}
import java.util.List;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


//SpringMVC只掃描Controller;子容器
//useDefaultFilters=false 禁用默認的過濾規則;
@ComponentScan(value="com.enjoy",includeFilters={
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
public class TestAppConfig   {
    
    
}

啓動tomcat,2個配置文件分別會掃描對應的類加載到spring的對應的根容器和servlet容器中,註解整合spring-mvc就完成啦!!!


4.註解定製和接管spring-mvc

xml配置的時候如下配置攔截器,視圖解析等。
image.png


若使用配置註解定製我們的springmvc,可看官網描述,加入@EnableWebMvc,來定製配置功能。
直接在servlet容器對應的配置裏面加入@EnableWebMvc並實現WebMvcConfigurer接口即可對對應需要配置的用代碼做配置,或者繼承WebMvcConfigurer的具體實現類。
image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章