springboot中的RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping的使用方法

springboot中的HandlerMapping

在上篇文章中已經說明HandlerMapping的作用是根據當前請求request獲取一個包含當前請求處理器handlerHandlerExecutionChain對象。handlerHandlerApapter適配後,可以將handler轉換爲一個特定的對象,以此確定哪個類的哪個個方法來處理該請求。springboot中默認註冊的HandlerMapping有:RequestMappingHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,RouterFunctionMapping,在這裏我們只說前三種。


RequestMappingHandlerMapping

這個就是我們常見的基於註解的映射方式,例如:

@Controller
@RequestMapping("/testA")
public class MappingTest1 {
    @ResponseBody
    @RequestMapping("/index")
    public String index(){
        return "RequestMappingHandlerMapping test!";
    }
}

對於加上上面的註解後,簡單解釋一下我們直接可以訪問localhost/testA/index的原因:在RequestMappingHandlerMapping的源碼中有一段代碼如下:

protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
		AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

springboot在初始化RequestMappingHandlerMapping時,會掃描容器中的bean,判斷它上面是否存在@Controller@RequestMapping兩種註解,通過上面的方法,判斷該bean是否是一個handler,如果是,則會將其註冊到RequestMappingHandlerMapping,用來處理和它匹配的請求。通過上面的方法我們還可以發現,@Controller註解不是必須的,我們還可以寫成下面的方式:

@Component
@RequestMapping("/testA")
public class MappingTest1 {
    @ResponseBody
    @RequestMapping("/index")
    public String index(){
        return "RequestMappingHandlerMapping test!";
    }
}
SimpleUrlHandlerMapping

這種方式直接通過簡單的url匹配的方式將其映射到一個處理器。首先像容器註冊一個自定義的SimpleUrlHandlerMapping

@Configuration
public class MyConfig extends SimpleUrlHandlerMapping{

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping(){

        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        Properties properties = new Properties();
        properties.setProperty("simpleUrl","mappingTest2");
        simpleUrlHandlerMapping.setMappings(properties);
		
		//設置該handlermapping的優先級爲1,否則會被默認的覆蓋,導致訪問無效
        simpleUrlHandlerMapping.setOrder(1);
		
        return simpleUrlHandlerMapping;
    }
}

定義一個名稱爲mappingTest2bean,並實現org.springframework.web.servlet.mvc.Controller接口

@Component("mappingTest2")
public class MappingTest2 implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.getWriter().write("SimpleUrlHandlerMapping test!");
        return null;
    }
}

在這個例子中,我們訪問localhost/simpleUrl就會直接進入容器中名稱爲mappingTest2beanhandleRequest方法。

BeanNameUrlHandlerMapping

這個最簡單:直接以bean的名稱作爲訪問路徑,但有個硬性條件就是bean的名稱必須以/開始。

@Component("/mappingTest3")
public class MappingTest3 implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.getWriter().write("BeanNameUrlHandlerMapping test!");
        return null;
    }
}

在該例子中,訪問方式爲localhost/mappingTest3
爲什麼必須以bean的名稱必須以/開頭呢,我們看BeanNameUrlHandlerMapping的源碼可以發現,它判斷是否是一個handler的依據就是該bean的名稱是否以/開頭。如下:

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {

	/**
	 * Checks name and aliases of the given bean for URLs, starting with "/".
	 */
	@Override
	protected String[] determineUrlsForHandler(String beanName) {
		List<String> urls = new ArrayList<>();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = obtainApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		return StringUtils.toStringArray(urls);
	}

}

上面的兩個例子都實現了Controller接口,爲什麼要實現Controller接口,必須要實現Controller嗎?這個後面再進行分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章