因为我们没有去使用前后端分离,所以使用thymeleaf来渲染视图。先自定义一个controller,里面的方法作用就是设置视图和一个数据模型。
package com.csc.contorller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info")
public ModelAndView info(){
ModelAndView mv = new ModelAndView();
mv.setViewName("userInfo");
mv.addObject("username","小明");
return mv;
}
}
同时使用thymeleaf的语法,把对应的数据模型获取。
Title
可以看见,浏览器输出的内容就是我们之前设置的数据模型。
自定义的拦截器。
package com.csc.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义的拦截器
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor...preHandle...执行了...");
//true:放行 false:拦截
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor...postHandle...执行了...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor...afterCompletion...执行了...");
}
}
还需要在配置类里面配置拦截器。
package com.csc.config;
import com.csc.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置类
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor);
}
}
自定义的异常处理器,为了方便展示效果,使用ModelAndView来返回进行视图的展示。
package com.csc.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/**
* 自定义的全局异常处理器
*/
@ControllerAdvice
public class MyGlobalExceptionHandle {
@ExceptionHandler({Exception.class}) //处理所有异常
public ModelAndView handleException(Exception ex){
ex.printStackTrace();
ModelAndView mv = new ModelAndView();
mv.setViewName("error");
return mv;
}
}
异常error.html。
Title
服务器异常
服务器异常
服务器异常
服务器异常
至此,准备工作就已经完成。
找到doDispatch()方法,这里面就是核心的SpringMVC的执行流程。
2.步入进去发现,在循环迭代添加HandlerMapping对象。
3.直接看handlerMappings对象,可以看见非常清楚,这几个就是我们自己写的contoller里面的路径,以及对应的方法,也是用Map储存的。
4.步过,可以看mappedHandler对象的HandlerMethod有了对应的方法,以及还有自定义的拦截器,由此,HandlerExecutionChain对象就获取到了。
2.步入进去,可以看见HandlerAdapter有许多处理适配器,其中就有熟悉的参数解析器和结果返回处理器。
2.步入进去,就是循环把所有的拦截器的preHandle方法执行,直到返回值为false的时候停止。也可以看见控制台输出的内容就是自定义的拦截器的preHandle方法执行输出的内容。
1.找到对应的代码,因为ha就是前面获取的HandlerAdapter对象。
2.在controller层打上断点,验证是否就是真正执行的该方法,发现就是在这。
3.放行,回到刚刚的位置,可以发现mv就已经有了视图的数据模型。
1.可以看见该方法名字就是对应的执行拦截器的后置处理器。
3.如果有异常,就会执行自定义的异常处理方法,并返回对应的视图。
2.步入this.render(mv, request, response)进去。可以看见代码比较清晰,就是把mv里面的视图和数据模型通过视图解析器解析,然后通过response对象响应。
这个render方法里面的render方法就是真正渲染视图的方法。
1.这个mappedHandler.triggerAfterCompletion()就是执行拦截器afterCompletion方法。
2.步入进去,这个方法就是执行所有拦截器的afterCompletion方法。
参考了黑马程序员的图片,如下图所示: