Spring Boot Framework - SpringMVC topic

A, SpringMVC history of

  2004  Spring Framework 1.0 final officially come out, then only contains a complete project, he put all the functions are concentrated in one project, which contains the core of the IOC, AOP, but also includes other many features such as: JDBC, Mail, ORM , transactions, and other regular tasks. Spring team advance the vision, when the first version already supports many third-party frameworks, such as: Hibernate, ibatis, template engine, etc., for later laid the foundation for rapid development.

  Spring 2.x adds support for annotations, support for annotation-based configuration.

  Spring 3.x support the class-based configuration.

  Spring 4.x full support for jdk1.8, and the introduction of RestController comment until today still is the programming interface of choice.

  Now the recent GA release Spring 5.2.1, Spring is moving forward, getting steady.

Second, the overall architecture

  

   Interceptors are introduced (blocker), similar to the filter Filter Servlet Development, for pre- and post-processor, the AOP will essentially meet all the features of crosscutting concerns into the interceptor can achieve, Intercepter for page processing is handler (Controller), allows program developers to customize the processing performed on a request path chain.

   Introducing the HandlerMapping (router), defined Spring MVC routing mechanism, the mapping request to the address corresponding to the Controller and Action.

   HandlerAdapter is introduced (adapter), which is a core class, method call handler, a data processing request, encapsulating return data.

   Introducing ViewResolver (view resolver), the name of a logical view as a real view resolved, for the SPRINGMVC View objects are presented to the client View object itself rather ViewResolver is the logical view of the object name resolution View object.

Third, the classification overview

1, intercept

a) Interface Source introduced

. 1  public  interface HandlerInterceptor from {
 2  
. 3      / ** 
. 4       * This method is called before the request service processor, the Interceptor is SPRINGMVC chain 
 5           calls * type, or in an application can be simultaneously in a single request there are multiple Interceptor          
 6           *. Each Interceptor calls will in turn execute the order in accordance with its declaration, and the first to be executed are 
 7           * preHandle method Interceptor in, so you can do some pre-initialization in this method 
 8           * operation or a current request pretreatment, can also be some judgment in this method to determine ask 
 9           if * seeking to continue. The return value is a Boolean value of Boolean type, when it returns to 
 10           * When to false, indicating the end of the request, and the subsequent Interceptor Controller will no longer performed; when returned 
 . 11           * The return value is true will continue with the next call preHandle a method of Interceptor, if you have a 
 12          * The last time Interceptor method would be to call Controller current request.
13 is       * / 
14      default  Boolean The preHandle (the HttpServletRequest Request, Response the HttpServletResponse, Object Handler)
 15              throws Exception {
 16  
. 17          return  to true ;
 18 is      }
 . 19  
20 is      / ** 
21 is       * this method, after the current request is processed, the method is called after Controller execution, but 
 22           * it will be called before the view returns were rendered DispatcherServlet, so we can in this 
 23           manipulate objects after ModelAndView * Controller processing method. postHandle side 
 24           direction with preHandle * method is invoked is the opposite, that the first statement of the Interceptor 
 25          * PostHandle method but will after the execution.
26 is       * / 
27      default  void The postHandle (the HttpServletRequest Request, Response the HttpServletResponse, Object Handler,
 28              @Nullable ModelAndView ModelAndView) throws Exception {
 29      }
 30  
31 is      / ** 
32       * This method also requires a current corresponding to the Interceptor preHandle method returns a value of only to true 
 33           * will be executed. As the name implies, the method after the entire request, i.e. in the DispatcherServlet 
 34 is           * a corresponding view after rendering performed. The main role of this method is that the resources for clean-up work.
35       * / 
36      default  void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
37             @Nullable Exception ex) throws Exception {
38     }
39 
40 }

b) the sample program

  1 package com.pine.property.manage.service.common;
  2 
  3 import java.util.List;
  4 
  5 import javax.servlet.http.HttpServletRequest;
  6 import javax.servlet.http.HttpServletResponse;
  7 
  8 import org.springframework.beans.factory.annotation.Autowired;
  9 import org.springframework.web.servlet.HandlerInterceptor;
 10 import org.springframework.web.servlet.ModelAndView;
 11 
 12 import com.baiyyy.core.common.AuthConstant;
 13 import com.baiyyy.core.common.BizException;
 14 import com.baiyyy.core.common.StatusCode;
 15 import com.baiyyy.core.service.IBaseService;
 16 import com.baiyyy.core.util.CookieUtil;
 17 import com.baiyyy.core.util.JedisUtil;
 18 import com.baiyyy.core.util.StringUtil;
 19 import com.pine.property.manage.entity.Account;
 20 import com.pine.property.manage.entity.Menu;
 21 import com.pine.property.manage.service.auth.message.FunctionData;
 22 /**
 23  * 1、每次请求延长登录缓存时间
 24  * 2、验证url访问权限
 25  * @author pinenut
 26  * @date 2018年2月22日
 27  */
 28 @Component
 29 public class AuthIntercepter implements HandlerInterceptor{
 30 
 31     @Autowired
 32     public HttpServletRequest request;
 33     
 34     private IBaseService<List<FunctionData>, Account> userAuthService;
 35     
 36     public boolean preHandle(HttpServletRequest httpRequest,
 37             HttpServletResponse response, Object handler) throws Exception {
 38 
 39         String currentUrl = httpRequest.getServletPath();
 40         
 41         //1、校验url权限
 42         this.authUrl(currentUrl);
 43         //2、更新用户cookie时间
 44         String cookieId = CookieUtil.getCookie(httpRequest.getCookies(), AuthConstant.SESSION_ID);
 45         JedisUtil.getInstance().STRINGS.setEx(cookieId, CommonConstant.USER_LOGIN_CONFIG_TIME_OUT, JedisUtil.getInstance().STRINGS.get(cookieId));
 46         
 47         
 48         return true;
 49         
 50     }
 51     
 52     /**
 53      * 校验url访问权限
 54      * @author liuqingsong
 55      * @date 2018年2月22日
 56      */
 57     private void authUrl(String currentUrl){
 58         List<FunctionData> functionDataList = this.userAuthService.process(null);
 59         boolean authed = false;
 60         for(FunctionData item : functionDataList){
 61             if(item.getMenuList() == null || item.getMenuList().size() == 0){
 62                 //只有一级菜单
 63                 if(currentUrl.toLowerCase().contains(item.getFunctionEntry().toLowerCase())){
 64                     authed = true;
 65                     break;
 66                 }
 67             }
 68             else{
 69                 //多级菜单
 70                 for(Menu menu : item.getMenuList()){
 71                     if(currentUrl.toLowerCase().contains(menu.getMenuUrl().toLowerCase())){
 72                         authed = true;
 73                         break;
 74                     }
 75                 }
 76                 if(authed){
 77                     break;
 78                 }
 79             }
 80         }
 81         
 82         if(!authed){
 83             throw new BizException(StatusCode.FAILURE_LOGIC, "用户无此功能权限!");
 84         }
 85     }
 86     
 87 
 88     @Override
 89     public void postHandle(HttpServletRequest request,
 90             HttpServletResponse response, Object handler,
 91             ModelAndView modelAndView) throws Exception {
 92         // TODO Auto-generated method stub
 93         
 94     }
 95 
 96     @Override
 97     public void afterCompletion(HttpServletRequest request,
 98             HttpServletResponse response, Object handler, Exception ex)
 99             throws Exception {
100         // TODO Auto-generated method stub
101         
102     }
103 
104     public IBaseService<List<FunctionData>, Account> getUserAuthService() {
105         return userAuthService;
106     }
107 
108     public void setUserAuthService(
109             IBaseService<List<FunctionData>, Account> userAuthService) {
110         this.userAuthService = userAuthService;
111     }
112     
113     
114     
115 }

 c) sequentially performs multiple interceptors

2, Handler Mapping

a) springmvc default implementation HandlerMapping 

 

For example in the following UserController

package com.baiyyy.basic.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
/*
 * 通用页面
 * @author Administrator
 *
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {

     * 登陆页面
     * @return
     */
    @RequestMapping(value = "/loginFrame", method = RequestMethod.GET)
    public ModelAndView loginFrame(){
        ModelAndView result = new ModelAndView("login");
        return result;
    }
}

 

实现类 继承父类 说明 使用
ControllerClassNameHandlerMapping AbstractUrlHandlerMapping 根据类名访问 Controller
访问地址: http://ip:port/项目名/user;注:类的首字母要小写
ControllerBeanNameHandlerMapping AbstractUrlHandlerMapping 根据 Bean 名访问 Controller
访问地址: http://ip:port/项目名/userController;
BeanNameUrlHandlerMapping AbstractUrlHandlerMapping 利用 BeanName 来作为 URL 使用
<bean id="userController" name="/users" 
class="com.qunar.web.controller.UserController"></bean>
访问地址: http://ip:port/项目名/users;
注:bean name属性必须要以“/”开头
SimpleUrlHandlerMapping AbstractUrlHandlerMapping 可以将 URL 与处理器的定义分离,还可以对 URL 进行统一的映射管理
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/userlist.htm">userController</prop>
        </props>
    </property>
</bean>
访问地址: http://ip:port/项目名/userlist.htm;
 
 RequestMappingHandlerMapping  AbstractHandlerMethodMapping  @RequestMapping注解定义url  
访问地址: http://ip:port/项目名/user/loginFrame;

 b)自定义handlerMapping

package com.baiyyy.core.common;

import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;

/**
 * 定义restful接口handlermapping路由机制
 * 默认以Controller/Action作为url,访问地址不区分大小写
 * @author pinenut
 * @date   2016-06-23
 */
public class RestfulHandlerMethodMapping extends AbstractHandlerMapping implements InitializingBean {
    
    private final Map<String, HandlerMethod> urlMap = new LinkedHashMap<String, HandlerMethod>();
    
    @Override
    public void afterPropertiesSet() throws Exception {
        this.initHandlerMethods();
    }

    @Override
    protected Object getHandlerInternal(HttpServletRequest request)
            throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request).toLowerCase();
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        HandlerMethod handlerMethod = this.urlMap.get(lookupPath);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    
    private void initHandlerMethods(){
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
        
        Map<String, Object> controllerBeans = this.getApplicationContext().getBeansWithAnnotation(RestController.class);
        for(Map.Entry<String, Object> controller : controllerBeans.entrySet()){
            Object handler = controller.getValue();
            Class<?> clazz = handler.getClass();
            Method[] methodList = clazz.getDeclaredMethods();
            for(Method method : methodList){
                HandlerMethod handlerMethod = new HandlerMethod(handler, method);
                
                String url =  ("/" + clazz.getSimpleName().replaceAll("Controller", "") + "/" + method.getName()).toLowerCase();
                
                logger.debug(url);
                this.urlMap.put(url, handlerMethod);
            }
        }
    }

    protected HandlerMethod createHandlerMethod(Object handler, Method method) {
        HandlerMethod handlerMethod;
        if (handler instanceof String) {
            String beanName = (String) handler;
            handlerMethod = new HandlerMethod(beanName,
                    getApplicationContext().getAutowireCapableBeanFactory(), method);
        }
        else {
            handlerMethod = new HandlerMethod(handler, method);
        }
        return handlerMethod;
    }
    
    
}

 

 

3、HandlerAdapter

a) springmvc默认实现的HandlerAdapter 如下

 

 

 

实现类 说明 使用场景 
RequestMappingHandlerAdapter 可以执行 HadnlerMethod 类型的 Handler  主要是适配注解类处理器
HttpRequestHandlerAdapter 可以执行 HttpRequestHandler 类型的 Handler  主要是适配静态资源处理器
SimpleControllerHandlerAdapte 可以执行 Controller 类型的 Handler  适配实现了Controller接口或Controller接口子类的处理器

 

4、ViewResolver

 

 

 a) InternalResourceViewResolver

<!-- 视图渲染 -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 视图前缀 -->
        <property name="prefix" value="/WEB-INF/view/"></property>
        <!-- 视图后缀 -->
        <property name="suffix" value=".jsp"></property>
        <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
        <property name="order" value="1"/>
    </bean>

  InternalResourceViewResolver也是使用的最广泛的一个视图解析器。我们可以把InternalResourceViewResolver解释为内部资源视图解析器,这就是InternalResourceViewResolver的一个特性。InternalResourceViewResolver会把返回的视图名称都解析为InternalResourceView对象,InternalResourceView会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher在服务器端把请求forword重定向到目标URL。比如在InternalResourceViewResolver中定义了prefix=/WEB-INF/,suffix=.jsp,然后请求的Controller处理器方法返回的视图名称为test,那么这个时候InternalResourceViewResolver就会把test解析为一个InternalResourceView对象,先把返回的模型属性都存放到对应的HttpServletRequest属性中,然后利用RequestDispatcher在服务器端把请求forword到/WEB-INF/test.jsp。这就是InternalResourceViewResolver一个非常重要的特性,我们都知道存放在/WEB-INF/下面的内容是不能直接通过request请求的方式请求到的,为了安全性考虑,我们通常会把jsp文件放在WEB-INF目录下,而InternalResourceView在服务器端跳转的方式可以很好的解决这个问题。下面是一个InternalResourceViewResolver的定义,根据该定义当返回的逻辑视图名称是test的时候,InternalResourceViewResolver会给它加上定义好的前缀和后缀,组成“/WEB-INF/test.jsp”的形式,然后把它当做一个InternalResourceView的url新建一个InternalResourceView对象返回。

b) BeanNameViewResolver

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

<bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">
    <property name="url" value="/index.jsp"/>
</bean>
@RequestMapping("/test")
public String testXmlViewResolver() {
    return "test";
}

  通过把返回的逻辑视图名称去匹配定义好的视图bean对象,BeanNameViewResolver要求视图bean对象都定义在Spring的application context中。

四、总体流程

  

    

 

Guess you like

Origin www.cnblogs.com/pinenut/p/11851734.html