1.深入理解springMVC(对MVC模式的支持)

1.SpringMVC对控制器Controller的支持

SpringMVC控制器的核心是DispatcherServlet

DispatcherServlet的作用:

  • Model处理逻辑的查找(HandlerMapping)
  • Model处理逻辑的执行(Handler)
  • View的渲染


1.1 处理器controller的查找

1.1.1 直接URL映射Handler

该映射方式通过向spring注册SimpleUrlHandlerMapping类型的Bean来实现。

@Configuration
public class HandlerMappingConfig {

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping(){
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        // 设置url与handler的映射管理,构建一个map
        mapping.setUrlMap(Collections.singletonMap("/url1",Handler));
        return mapping;
    }
}
1.1.2 通过beanName(Handler)与URL映射

该映射方式如果Bean的name或者别名是以 / 开头的,那么这个bean会自动作为Handler的映射路径,URL为Bean的name或者别名,Handler为该Bean本身。
这个自动注册的逻辑发生在BeanNameUrlHanlerMapping中:

// 源码
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
    public BeanNameUrlHandlerMapping() {
    }

    protected String[] determineUrlsForHandler(String beanName) {
        List<String> urls = new ArrayList();
        // 判断beanName是否以/开头
        if (beanName.startsWith("/")) {
            urls.add(beanName);
        }

        String[] aliases = this.getApplicationContext().getAliases(beanName);
        String[] var4 = aliases;
        int var5 = aliases.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            if (alias.startsWith("/")) {
                urls.add(alias);
            }
        }

        return StringUtils.toStringArray(urls);
    }
}

注册方式有下面两种:
(1)在configuration注解类里面加入bean:

 	@Bean(name={"/url1","url2"})
    public HttpRequestHandler beanNameHandler(){
    	// 自己定义的handler
        return new BeanNameUrlRequestHandler();
    }

(2)使用Component注解来获取bean

@Component()
public class BeanNameUrlRequestHandler{
	...
}
1.1.3 RequestMapping映射

这种是最常用的映射使用方式,其Handler查找策略是通过RequestMappingHandlerMapping来实现的:



1.2 处理器执行

Handler的查找和执行是分开的,下面介绍几种常用的Handler:

1.2.1 HttpRequestHandler

这是一种最简单的Handler,其只有一个方法HandleRequest,传入HttpServletRequest和HttpServletResponse两个参数,而且没有返回值,要通过response对象将内容返回:

接口:

public interface HttpRequestHandler {
    void handleRequest(HttpServletRequest request, HttpServletResponse response);
}

使用:
(1) 首先建立一个HttpRequestHandler 的实现类

public class MyRequestHandler implements HttpRequestHandler {
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response){
        response.getWriter().write("hello httpRequestHandler");
    }
}

(2)使用相关mapping来使该handler能够被查找到:

@Configuration
public class HandlerMappingConfig {

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping(){
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        // 设置url与handler的映射管理,构建一个map
        mapping.setUrlMap(Collections.singletonMap("/url1",new MyRequestHandler()));
        return mapping;
    }
}

虽然该Handler并没有视图查找解析等流程,但是对于一些不需要解析的静态资源,就可以使用该handler来实现。

1.2.2 Controller接口的Handler

该Handler更接近于MVC定义的Controller,虽然同样只有handleRequest方法以及相同的参数,但是其返回值是ModelAndView对象,其中封装了Model和View

@Component("/myController")
public class MyController implements Controller {


    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
        Map<String,Object> model = new HashMap<>();
        model.put("name","123");
        return new ModelAndView("defaultView",model);
    }
}
1.2.3 RequestMapping定义的HandlerMethod

该类型的handler,首先通过RequestMappingHandlerMapping查找满足条件的@RequestMapping,然后将其标注的方法封装成HandlerMethod对象
HandlerMethod对象虽然也可以通过SimpleUrlHandlerMapping来结合使用,但是一般都是与RequestMappingHandlerMapping结合使用



1.3 拦截器Interceptor

在查找Handler的时候,HandlerMapping并不是返回Handler本身,而是返回Handler的执行链HandlerExecutionChain。该执行链中国封装的有需要应用到该Handler上的所有拦截器。

执行流程:

  • 在执行处理器handler之前,会先执行HandlerInterceptor的preHandle方法。如果该方法返回false,会中断处理流程。
  • 执行处理器Handler,执行完Handler后,有两种结果:正常执行完整和抛出异常。
  • 如果是正常执行完Handler,会执行拦截器的postHandle的方法;如果是抛出异常,则会跳过该方法
  • 不论是否产生异常,最终都会执行afterCompletion方法。



2.SpringMVC对模型(Model)的支持

2.1 Model模型的相关类型

  • Map接口
  • Model接口:提供了添加属性、合并属性等功能,虽然该接口没有实现Map,但是可以使用asMap方法来将其转换成map
  • ModelMap接口:继承与LinkedHashMap类,该接口的所有方法都是通过Map的put方法来实现添加属性操作
  • RedirectAttributes接口:继承自Model接口,该接口为重定向参数提供了特殊方式,通过addFlashAttribute添加重定向可以使用的Model参数。

2.2 模型的使用

1.声明Map的类型参数

  	@RequestMapping("/testUrl")
    public String mapParams(Map<String,Object> map){

        map.put("name",123);
        return "defaultView";
    }

2.声明Model的类型参数

	@RequestMapping("/testUrl")
    public String modelParams(Model model){
        model.addAttribute("name",123);
        return "defaultView";
    }

3.声明ModelMap类型参数
ModelMap自身是Map类型,但是其也可以使用Model开放的接口方法来操作数据

	@RequestMapping("/testUrl")
    public String modelMapParams(ModelMap modelMap){
        modelMap.put("name",123);
        modelMap.addAttribute("name",123);
        return "defaultView";
    }

4.自己创建Model并返回

	@RequestMapping("/defaultView")
    public Map createModel(){
        Map<String,Object> model = new HashMap<>();
        model.put("name",123);
        return model;
    }

这里由于返回的是model对象而不是view,所以视图名称来源于路径url,这里的url是/defaultView,所以视图名称也就是defaultView。

5.@ModelAttribute方式
该方式同样会取返回值放入model中,属性名称是@ModelAttribute注解声明的名称,值是方法的返回值。

6.直接返回ModelAndView

 	@RequestMapping("/testUrl")
    public ModelAndView createMV(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("/defaultView");
        mv.addObject("name",123);
        return mv;
    }



3.SpringMVC对视图的支持

3.1 视图类型

(1)内部资源视图InternalResourceView:该视图代表内部的资源。创建该视图的时候,需要传入URL来表示内部资源的路径。常见资源类型有:静态资源、JSP视图和转发视图
这三种视图跳转都是通过获取对应路径RequestDispatcher来实现的。

转发视图为例:

 	@RequestMapping("/testUrl")
    public String forwardView(Model model){
    	// 在转发前,springmvc通过request.setAttribute将model中的属性放在了request中
        model.addAttribute("name",123);
        return "forward:forwardTargetView";
    }

	@RequestMapping("/forwardTargetView")
    public String targetView(HttpServletRequest request,Model model){
    	// 转发共享request,但是model是独立的
        String name = (String)request.getAttribute("name");
        model.addAttribute("name",name + 123);
        return "defaultView"
    }

(2)重定向视图

	@RequestMapping("/testRedirect")
    public String redirectView(RedirectAttributes model){
        model.addAttribute("name",123);
        return "redirect:redirectTargetView";
    }


3.2 视图查找解析

SpringMVC提供了ViewResolver接口来通过视图名称查找并解析视图,该接口有resolveViewName方法来返回View视图。

public interface ViewResolver {
	/**
	* params: 
	* 	viewName: 视图名称
	* 	locale:地区参数,国际化
	*/
    View resolveViewName(String viewName, Locale locale throws Exception;
}
3.2.1 通过BeanName来查找视图

这种方式来查找view视图需要声明为spring容器的bean,该解析方式是通过BeanNameViewResolver来执行的,该方式要求声明的bean实现view接口。

// 会匹配/testUrl的ViewName
@Component("testUrl")
public class CustomerView implements View {
    @Override
    public String getContentType() {
        return MediaType.TEXT_HTML_VALUE;
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Object name = model.get("name");
        response.getWriter().write("name is " + name);
    }
}
3.2.2 模板引擎解析视图(以Thymeleaf为例)

每种模板引擎都会有自己的视图解析器,在引入spring-boot-starter-freemarler后,自动生成ThymeleafViewResolver到SpringMVC中。默认情况下该解析器会以classpath:/templates/为前缀,以.html为后缀,这两个属性可以通过下面方式进行修改

spring.thymeleaf.prefix = 视图前缀
spring.thymeleaf.suffix = 视图后缀
3.2.3 内部资源视图解析
3.2.4 直接指定视图
 	@RequestMapping("/testUrl")
    public View returnView(Model model){
        model.addAttribute("name",123);
        return new CustomerView();--->实现了View接口的视图对象
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值