springmvc零xml配置原理

springmvc零xml配置原理与Servlet3.0SPI机制

这里引用另一位博主的文章,比较图文并茂一点,但是他的写法会导致一点问题,在文章结尾会说明。地址:https://blog.csdn.net/weixin_44051223/article/details/106127211

传统springmvc项目,如果要采用xml文件的方式配置,则需要web.xml、spring-mvc.xml文件。

web.xml文件用来引入springmvc的配置文件contextConfigLocation,以及spring环境org.springframework.web.context.ContextLoaderListener

web.xml:

  <!--  spring环境的初始化-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <!--      引入springmvc的配置文件-->
      <param-name>contextConfigLocation</param-name>
      <param-value>spring-mvc.xml</param-value>
    </init-param>
    <!--    加载顺序-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

 

spring-mvc.xml文件:

<!--启用spring的一些annotation -->
<context:annotation-config/>

<!-- 配置注解驱动 可以将request参数绑定到controller参数上 -->
<mvc:annotation-driven/>

<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP-->
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/view/"/><!--设置JSP文件的目录位置-->
<property name="suffix" value=".jsp"/>
<property name="exposeContextBeansAsAttributes" value="true"/>
</bean>

<!-- 自动扫描装配 -->
<context:component-scan base-package="com.XXX"/>

那么,现在提供一种方式,可以不用配置任何的xml文件,也同样能搭建起springmvc项目。

现在一起来看一下spring官网提供的文档描述:

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet-config

 

 

这里可以看到需要实现一个接口的onStartup方法

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    //实现0XML
    //类实现WebApplicationInitializer【spring官方提供的方法。用于加载spring容器】
    //tomcat启动时会调用onStartup方法?

    @Override
    public void onStartup(ServletContext servletContext) {
        //传入一个ServletContext:web上下文对象。web.xml能做的事她都能做

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("*.do");
    }

这里只是配置了一个DispatcherServlet,那试图解析器在哪里配置呢?再回到官方文档

 

 

其实这里就是用来配置视图解析器的地方

写一个AppConfig类,作为Springmvc的配置类,实现

WebMvcConfigurer
@Configuration
@ComponentScan("com")
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
 /***
     * 配置视图解析
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/page/", ".html");
    }
/**
     * 配置一个消息转换器[对象的转换]
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            System.out.println(converter);
        }
        FastJsonHttpMessageConverter converter
                = new FastJsonHttpMessageConverter();
        converters.add(converter);
    }

 

 

WebMvcConfigurer接口一共定义了若干方法,可以对照着官网学习配置。

此时就可以编写controller类来测试零xml配置的springmvc了

@Controller
public class TestController {


    /**
     * 访问普通的字符串,试图解析器会解析成对应的页面
     * @return
     */
    @RequestMapping("/str.do")
    public Object Test(){
        return "index";
    }

    /**
     * 因为返回值是一个对象,所以如果不做特殊处理,则试图解析器无法解析
     * 对象嵌套是一个难点
     * @param name
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/model.do")
    @ResponseBody
    public Object modeltest(String name, HttpServletRequest request, HttpServletResponse response){
        System.out.println("调用了modeltest");
        String req_name = request.getParameter("name");
        Map hashMap = new HashMap<>();
        hashMap.put("key", "value");
        return hashMap;
    }
}

 

启动Tomcat需要一个启动类:

public class Application {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, LifecycleException, ServletException {
//        Tomcat tomcat = new Tomcat();
//        tomcat.setPort(80);
//        //初始化一个context资源目录,并不会加载web的生命周期
//        //Context context = tomcat.addContext("/", System.getProperty("java.io.tmpdir"));
//        Context context = tomcat.addContext("/", Application.class.getResource("/").getPath().replaceAll("%20"," "));
//        //添加web生命周期监听器
//        context.addLifecycleListener((LifecycleListener)Class.forName(tomcat.getHost().getConfigClass()).newInstance());
//        tomcat.start();
//        tomcat.getServer().await();

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(80);
        //Context context = tomcat.addContext("/", System.getProperty("java.io.tmpdir"));
        tomcat.addWebapp("/",Application.class.getResource("/").getPath().replaceAll("%20"," "));
        //context.addLifecycleListener((LifecycleListener) Class.forName(tomcat.getHost().getConfigClass()).newInstance());
        //tomcat.addWebapp("/", System.getProperty("java.io.tmpdir"));
        tomcat.start();
        tomcat.getServer().await();



    }
}

这里有一点需要注意:

  如果使用引用文章的写法,即

  

Context context = tomcat.addContext("/", System.getProperty("java.io.tmpdir"));
context.addLifecycleListener((LifecycleListener) Class.forName(tomcat.getHost().getConfigClass()).newInstance());

 

会导致webapp目录下的页面与静态资源都无法访问。controller返回一个index,按道理是可以通过localhost/page/index.html访问到index.html页面。但是由于加载的是一个临时目录,所以访问不到项目的静态资源

//TODO Servlet3.0 SPI

 

posted @ 2021-01-12 00:25  Java民工陆小凤  阅读(190)  评论(0编辑  收藏  举报