首页 > 技术文章 > 【Spring】30、Spring,SpringMVC用法汇总

wangzhongqiu 2017-12-20 11:49 原文

SpringMVC的工作原理图:

springMVC中的几个组件:

前端控制器(DispatcherServlet):接收请求,响应结果,相当于电脑的CPU。

处理器映射器(HandlerMapping):根据URL去查找处理器

处理器(Handler):(需要程序员去写代码处理逻辑的)

处理器适配器(HandlerAdapter):会把处理器包装成适配器,这样就可以支持多种类型的处理器,类比笔记本的适配器(适配器模式的应用)

视图解析器(ViewResovler):进行视图解析,多返回的字符串,进行处理,可以解析成对应的页面

1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4、处理器Handler(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。

5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

6、视图View(需要工程师开发jsp...)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)

核心架构的具体流程步骤如下:

第一步:用户发起请求到前端控制器(DispatcherServlet)

第二步:前端控制器请求处理器映射器(HandlerMappering)去查找处理器(Handle):通过xml配置或者注解进行查找

第三步:找到以后处理器映射器(HandlerMappering)像前端控制器返回执行链(HandlerExecutionChain)

第四步:前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)

第五步:处理器适配器去执行Handler

第六步:Handler执行完给处理器适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回ModelAndView

第八步:前端控制器请求视图解析器(ViewResolver)去进行视图解析

第九步:视图解析器像前端控制器返回View

第十步:前端控制器对视图进行渲染

第十一步:前端控制器向用户响应结果

filter过滤器

过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个HTML页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter:用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。

Filter 有如下几个用处

  1.  在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 
  2.  根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。 
  3.  在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 
  4.  根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

自定义数据绑定---HandlerMethodArgumentResolver:

自定义一个CurrentUserHandlerMethodArgumentResolver实现HandlerMethodArgumentResolver

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor;
        Object arg = null;
        String[] paramValues = webRequest.getParameterValues(parameter.getParameterName());
        if (paramValues != null) {
            arg = paramValues.length >= 1 ? paramValues[0] : null;
        }

        ParamCheck paramCheck = parameter.getParameterAnnotation(ParamCheck.class);
        if(null != paramCheck){
            try {
                this.doCheck(arg, paramCheck, parameter.getParameterName(),parameter.getParameterType().getSimpleName());
            } catch (RuntimeException e) {
                LOGGER.error(e);
            }
            return arg;
        }
        
        EntityCheck entityCheck = parameter.getParameterAnnotation(EntityCheck.class);
        if(null != entityCheck){
            arg = this.buildEntityFromParam(parameter, webRequest);
            try {
                this.doCheck(arg, entityCheck, parameter,webRequest);
            } catch (RuntimeException e) {
                LOGGER.error(e);
            }
            return arg;
        }
        return arg;
    }

controller中接收参数,加上自定义注解 @EntityCheck

    @RequestMapping(value = "/test")
    @ResponseBody
    public ModelMap test(@EntityCheck String str) {
        ModelMap mm = new ModelMap();
        try {
            mm.addAttribute("message", "success");
            mm.addAttribute("status", "0");
        } catch (Exception e) {
            e.printStackTrace();
            mm.addAttribute("message", "failure");
            mm.addAttribute("status", "1");
        }
        return mm;
    }

 springMVC对异常处理的支持

处理优先级,当发生异常的时候,SpringMVC会如下处理:

(1)SpringMVC会先从配置文件找异常解析器HandlerExceptionResolver

(2)如果找到了异常异常解析器,那么接下来就会判断该异常解析器能否处理当前发生的异常

(3)如果可以处理的话,那么就进行处理,然后给前台返回对应的异常视图

(4)如果没有找到对应的异常解析器或者是找到的异常解析器不能处理当前的异常的时候,就看当前的Controller中有没有提供对应的异常处理器,如果提供了就由Controller自己进行处理并返回对应的视图

(5)如果配置文件里面没有定义对应的异常解析器,而当前Controller中也没有定义的话,那么该异常就会被抛出来。

    <!--错误处理器-->
    <bean id="exceptionHandler" class="wangzhongqiu.spring.springmvc.resolver.MobileExceptionHandler"/>
public class MobileExceptionHandler implements HandlerExceptionResolver {

    private static Log logger = LogFactory.getLog(MobileExceptionHandler.class);

    private static final Log LOGGER = LogFactory.getLog(MobileExceptionHandler.class);
    private static final int DEFAULT_STATUS_CODE = 1000;
    private static final int UPLOAD_SIZE_EXCEEDED = 300601;
    private static final String SPLIT = "";

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ex.printStackTrace();
        ModelAndView mav = new ModelAndView();
        Map<String, Object> model = new HashMap();
        // 默认异常信息 “请求失败,请稍后再试”
        int status = DEFAULT_STATUS_CODE;
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        try {
            // 必选参数丢失
            if (ex instanceof MissingServletRequestParameterException
                    || ex instanceof HttpRequestMethodNotSupportedException || ex instanceof TypeMismatchException) {
                status = 1001;
            } else if (ex instanceof MaxUploadSizeExceededException) {
                LOGGER.error("上传头像图片大小超过系统限制", ex);
                status = UPLOAD_SIZE_EXCEEDED;
            }
            model.put("message", "错误");
            model.put("status", status);
            view.setAttributesMap(model);
            mav.setView(view);
        } catch (Exception e) {
            LOGGER.error(e);
        }
        return mav;
    }
}

使用BeanNameAutoProxyCreator创建代理

BeanNameAutoProxyCreator是自动代理创建器的三种(BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator)之一.

它是根据拦截器和设置的Bean的名称表达式做匹配来创建代理.

    <bean id="exposerProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">
            <list>
                <value>databaseInterceptor</value>
                <value>suspendAutoRepayInterceptor</value>
            </list>
        </property>
        <property name="beanNames">
            <list>
                <value>*Controller</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/>
    </bean>
    <bean id="databaseInterceptor" class="wangzhongqiu.spring.springmvc.interceptor.DatabaseInterceptor"/>
    <bean id="suspendAutoRepayInterceptor" class="wangzhongqiu.spring.springmvc.interceptor.SuspendAutoRepayInterceptor"/>
public class DatabaseInterceptor implements MethodInterceptor {
    private static final Logger DB_INC_LOG = LoggerFactory.getLogger(DatabaseInterceptor.class);

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        try {
            Method method = methodInvocation.getMethod();
            if (method != null && method.getAnnotation(ReadOnlyDataSource.class) != null) {
                DataSourceProvider.setDataSource(AvailableDataSources.READ);
                DB_INC_LOG.info("The method 【" + method.getName() + "】 will use read-only datasource.");
            }
            return methodInvocation.proceed();
        } finally {
            DataSourceProvider.clearDataSource();
        }
    }
}

BeanNameAutoProxyCreator是一个BeanPostProcessor.它在Bean实例化随后,调用回调org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization进行后期处理来完成代理的创建.

BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。

BeanFactory是个 Factory ,实际上是实例化,配置和管理众多bean的容器, FactoryBean 是个 Bean 。在 Spring 中,所有的 Bean 都是由 BeanFactory( 也就是 IOC 容器 ) 来进行管理的。但对 FactoryBean 而言,这个 Bean 不是简单的 Bean ,而是一个能生产或者修饰对象生成的工厂 Bean, 它的实现与设计模式中的工厂模式和修饰器模式类似。

如果一个类实现了FactoryBean接口,那么getBean得到的不是他本身了,而是它所产生的对象,如果我们希望得到它本身,只需要加上&符号即可。

public class PersonFactoryBean implements FactoryBean<Person>{  
      
    private String personInfo;  
      
    public Person getObject() throws Exception {  
        Person person =  new  Person () ;      
        String []  infos =  personInfo.split ( "," ) ;  
        person.setName(infos[0]);  
        person.setAddress(infos[1]);  
        person.setAge(Integer.parseInt(infos[2]));  
        return person;  
    }  
  
    public Class<Person> getObjectType() {  
        return Person.class;  
    }  
  
    public boolean isSingleton() {  
        return true;  
    }  
} 
<bean id="personFactory" class="com.hik.MavenTest.PersonFactory">  
    <property name="personInfo" value="gh2,address2,22"></property>  
</bean>   

context包增加了ApplicationContext,它以一种更加面向框架的方式增强了BeanFactory的功能。多数用户可以以一种完全的声明式方式来使用ApplicationContext,甚至不用去手工创建它

Context包的基础是位于org.springframework.context包中的ApplicationContext接口。它是由BeanFactory接口集成而来,提供BeanFactory所有的功能。

====================相关文章=============================

HttpServlet详解

Spring ContextLoaderListener与DispatcherServlet所加载的applicationContext的区别

ApplicationContext ,ApplicationContextAware,Listener,Event 的关系解读

<load-on-startup>0</load-on-startup>配置

========================================================

SpringMVC 过滤器Filter使用解析

spring MVC  拦截器和<mvc:annotation-driven />的详解

Spring MVC  handlerMapping和handlerAdapter

Spring MVC HandlerInterceptorAdapter的使用

SpringMVC拦截器的配置

spring mvc路径匹配原则

Spring MVC  自定义数据绑定---HandlerMethodArgumentResolver

springMVC对异常处理的支持

========================================================

spring aop  使用BeanNameAutoProxyCreator创建代理

Spring的BeanFactoryPostProcessor和BeanPostProcessor

BeanPostProcessor

Spring代理。BeanNameAutoProxyCreator 与 ProxyFactoryBean

========================================================

BeanFactory 和 ApplicationContext的区别

BeanFactory 和FactoryBean的区别

Spring框架中的单例Beans是线程安全的么

========================================================

Java的位运算符详解实例——与(&)、非(~)、或(|)、异或...

===================未完成================================

ProxyFactoryBean

ServletContextAware

推荐阅读