ControllerClassNameHandlerMapping类详解 - HandlerMapping系列六

ControllerClassNameHandlerMapping通过声明在Web应用程序环境中的控制器类型来注册处理器映射的。它从控制器的类型转换出控制器所服务的URL Pattern。这个转换规则是,把点号分割的具有包前缀的类名替换成斜线(/)分割的具有包前缀的字符串,再加上前缀和后缀构成URL Pattern,然后,使用得到的Pattern匹配请求的URL,如果匹配成功,则使用匹配的Bean作为处理器返回。

ControllerClassNameHandlerMapping源码

public class ControllerClassNameHandlerMapping extends AbstractControllerUrlHandlerMapping {  
    // 控制器名的后缀  
    private static final String CONTROLLER_SUFFIX = "Controller";  
  
    // 通过类型映射的路径是否保持大写字母的存在  
    private boolean caseSensitive = false;  
    private String pathPrefix;  
    private String basePackage;  
    public void setPathPrefix(String prefixPath) {  
        this.pathPrefix = prefixPath;  
          
        // 一个路径应该保证有斜线(/)开头,但是没有斜线(/)结尾  
        if (StringUtils.hasLength(this.pathPrefix)) {  
            if (!this.pathPrefix.startsWith("/")) {  
                this.pathPrefix = "/" + this.pathPrefix;  
            }  
            if (this.pathPrefix.endsWith("/")) {  
                this.pathPrefix = this.pathPrefix.substring(0, this.pathPrefix.length() - 1);  
            }  
        }  
    }  

    public void setBasePackage(String basePackage) {  
        this.basePackage = basePackage;  
          
        // 设置缺省的包前缀  
        if (StringUtils.hasLength(this.basePackage) && !this.basePackage.endsWith(".")) {  
            this.basePackage = this.basePackage + ".";  
        }  
    }  
  
    //根据beanClass来获取url
    @Override  
    protected String[] buildUrlsForHandler(String beanName, Class beanClass) {  
        // 仅仅使用类名进行映射  
        return generatePathMappings(beanClass);  
    }  
  
    protected String[] generatePathMappings(Class beanClass) {  
        // 产生路径前缀  
        StringBuilder pathMapping = buildPathPrefix(beanClass);  
          
        // 取得不包含包名的类名  
        String className = ClassUtils.getShortName(beanClass);  
          
        // 如果以控制器后缀(Controller)结尾,则移除控制器后缀  
        String path = (className.endsWith(CONTROLLER_SUFFIX) ?  
                className.substring(0, className.lastIndexOf(CONTROLLER_SUFFIX)) : className);  
          
        if (path.length() > 0) {  
            // 如果保持路径大小写,则把类名的第一个字符小写  
            if (this.caseSensitive) {  
                pathMapping.append(path.substring(0, 1).toLowerCase()).append(path.substring(1));  
            }  
            // 否则使所有路径字符变成小写  
            else {  
                pathMapping.append(path.toLowerCase());  
            }  
        }  
          
        // 如果是多行为控制器类型,则加URL本身和所有的子URL  
        if (isMultiActionControllerType(beanClass)) {  
            return new String[] {pathMapping.toString(), pathMapping.toString() + "/*"};  
        }  
        // 否则只加URL本身  
        else {  
            return new String[] {pathMapping.toString() + "*"};  
        }  
    }  
    private StringBuilder buildPathPrefix(Class beanClass) {  
        StringBuilder pathMapping = new StringBuilder();  
          
        // 第一部分是路径前缀  
        if (this.pathPrefix != null) {  
            pathMapping.append(this.pathPrefix);  
            pathMapping.append("/");  
        }  
        else {  
            pathMapping.append("/");  
        }  
          
        // 第二部分是包名中逗点替换成斜线的结果  
        if (this.basePackage != null) {  
            String packageName = ClassUtils.getPackageName(beanClass);  
            if (packageName.startsWith(this.basePackage)) {  
                String subPackage = packageName.substring(this.basePackage.length()).replace('.', '/');  
                pathMapping.append(this.caseSensitive ? subPackage : subPackage.toLowerCase());  
                pathMapping.append("/");  
            }  
        }  
        return pathMapping;  
    }  
} 

总结

ControllerClassNameHandlerMapping 作用是将MyController这样的名字, 自动映射成 /my/** 这样的URL

版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。