浅析 SpringMVC 原理和配置.

一、原理

Spring MVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序,将请求处理的逻辑和视图中的渲染实现解耦。

1、 DispatcherServlet Spring MVC 的核心 。 Spring MVC 中的请求页面都会委托给DispatcherServlet来执行处理。

2、DispatcherServlet需要知道将请求发送给哪个控制器,所以DispatcherServlet会查询一个或多个处理器映射(handler mapping) 来确定请求的下一站在哪里。

3、到了控制器(controller),请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。

4、控制器在处理完成后,通常会产生一些信息,这些信息称为模型(model)。但是这个模型到底是渲染哪个页面的呢?所以控制器还会返回视图相关的东西。Spring 有个思想就是前后端分离,为了和视图解耦,所以控制器只返回了视图名。即,这里控制器返回了模型和视图名(modelAndViews)。

tips: Model 实际上就是一个Map(也就是key-value对的集合),它会传递给视图,这样数据就能渲染到客户端了,当调用addAttribute()方法并且不指定key的时候,那么key会根据值的对象类型推断确定,比如 List,那么推断他的 key 就是 spittleList。如果你希望使用非Spring类型的话,那么可以用java.util.Map来代替Model。

5、MVC 要怎么依靠一个视图名找到对应的视图呢?答案就是 视图解析器(view resolver)。

6、视图解析器会返回一个视图(view),并将模型数据填充到对应的视图中。

7、视图 (比如 JSP)。最终会被相应的容器(比如Tomcat)解析成 HTML 页面,并响应用户的请求。

tips 实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个服务对象进行处理。

二、使用 Java 配置

按照传统的方式,像 DispatcherServlet 这样的Servlet会配置在web.xml文件中 ,但是,借助于Servlet 3规范和Spring 3.1的功能增强,这种方式已经不是唯一的方案了 。我们会使用Java将DispatcherServlet配置在Servlet容器中。开始前,我们先来理解下 DispatcherServlet 和 Servlet 监听器(也就是ContextLoaderListener) 这两个应用上下文 。

DispatcherServlet 上下文:当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类(即带有@configuration注解的配置类)中所声明的bean,主要是Web 组件中的 bean, 包括 控制器(controller)、映射器(handler mapping)、视图解析器(view resolver)等。

ContextLoaderListener 上下文:这个上下文 由 ContextLoaderListener 创建,主要负责加载应用中的其他 bean 。 这些 bean 通常是驱动应用后端的中间层和数据层组件。

实现:
我们通过继承 AbstractAnnotationConfigDispatcherServletInitializer 类来配置SpringMVC,以作为传统 XML 配置的替代方案。实际上, AbstractAnnotationConfigDispatcherServletInitializer 会 同时创建 DispatcherServlet 和 ContextLoaderListener 。当然,我们需要手动配置我们的映射路径、视图解析器 并启用组件扫描 以及一系列我们可以自定义的配置。当然,如果我们没有配置视图解析器,SpringMVC 会启用默认的视图解析器(通过查找 ID 与视图名称相匹配的Bean,并且这个Bena 要实现View 接口)。如果没有配置路径映射,DispatcherServlet会映射为应用的默认Servlet,所以它会处理所有的请求,包括对静态资源的请求,如图片和样式表等。

public class SplittrWebAppInitailzer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    /*返回会创建ContextLoaderListener 上下文*/
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    /*返回会创建 DispatcherServlet 上下文*/
    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    /*配置路径映射*/
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

最小但可用的SpringMVC配置
@Configuration
@ComponentScan(basePackages = {"com"},
        excludeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)
        })
public class RootConfig {
}

RootConfig.java
@Configuration
@EnableWebMvc //启用SpringMVC,当然也可以使用  注解驱动
@ComponentScan(basePackages = "com.controller")
public class WebConfig extends WebMvcConfigurerAdapter {

    /**
     * 在查找的时候,它会在视图名称上加一个特定的前缀和后缀
     * (例如,名为home的视图将会解析为/WEB-INF/pages/home.jsp)。
     *
     * @return
     */
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        /*设置是否把所有在上下文中定义的bean作为request属性可公开访问。
          这样在JSP 2.0中可使用${}来存取,JSTL中使用c:out。
          默认为false。*/
        resolver.setExposeContextBeansAsAttributes(true);
        resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class); //设置解析JSTL
        return resolver;
    }

    /**
     * 通过调用DefaultServlet-HandlerConfigurer的enable()方法,
     * 我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器
     * 中默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求
     *
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebConfig.java

测试:

    @RequestMapping(value = {"/","/home"},method = RequestMethod.GET)
    public String getHome(Model model){
        return "home";
    }

controller

添加自定义Servlet、Filter、Listener

public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("这是新建的Servlet");
    }
}

自定义Servlet类
public class MyServletInitializer implements WebApplicationInitializer {
    public void onStartup(ServletContext servletContext) throws ServletException {
        ServletRegistration.Dynamic myServlet = servletContext.addServlet("MyServlet", MyServlet.class);
        myServlet.addMapping("/myServlet");
    }
}

注册Servlet

注册Filter、Listener 也可以用类似的方式。但是, 如果你只是注册 Filter ,并且该 Filter 只会映射到 DispatcherServlet 上的话,那么在 AbstractAnnotationConfigDispatcherServletInitializer 中还有一种快捷方式。

public class MyFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("过滤器的工作");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

自定义Filter类
    protected Filter[] getServletFilters() {
        return new Filter[]{new MyFilter()};
    }

在AbstractAnnotationConfigDispatcherServletInitializer的继承上添加...

三、使用 XML 配置



    
    
        /images/small.gif
        /images/large.gif
    
    
    
    mvc
    
    
    mvc test
   
    
    
    
        contextConfigLocation
        classpath:applicationContext.xml
    
   
    
    
        encoding-filter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
    
    
        encoding-filter
        /*
    
   
    
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
    
        appServlet
        org.springframework.web.servlet.DispatcherServlet
        1
    
    
        appServlet
        /
    
    
    
    
        120
    
    
    
    
    
        htm
        text/html;charset=gb2312
    
    
        html
        text/html;charset=gb2312
    

    
    
        index.jsp
    
   
    
    
    
          404
          /NotFound.jsp
    
    
    
          java.lang.NullException
          /error.jsp
    

    

    
    
    
        
            ProtectedArea
            /resources/*
            <!--如果没有方法,表示禁止所有的HTTP方法访问对应的资源-->
            GET
        
        <!--哪些用户应该具有受保护资源的访问权
            如果没有  ,配置实际上是不起作用的。
            如果内容为空,表示所有的身份都被禁止访问-->
        
            ALL Role
        
    
    
    
    
    
        BASIC
    
    
    
        DIGEST
    
    
    
        CLIENT-CERT
    
    
    
        FORM
        
            /login.html
            /error.jsp
        
    

    
    
    
        ALL Role
    

tips web.xml 的加载顺序是:ServletContext -> context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。

四、结语

2017年最后一篇博文了,坚持在2017年的最后一个晚上写完。毕竟2017的事总不好意思拖一年呀!坚持写博客真是个好习惯,好记性毕竟不如白纸黑字来的牢靠啊,如果把记性比作网上搜索的话,博客就是自己的一份离线存储。

本来想好好回顾下2017,打一大堆满满的文字,装一个文艺的青年。真到落笔的时候,什么都不想写。敬往事一杯酒,悠悠岁月不回头!

祝大家新年快乐!2018!我来了……

博客园-原创精华区稿源:博客园-原创精华区 (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » 浅析 SpringMVC 原理和配置.

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录