资料参考:https://mp.weixin.qq.com/s?__biz=Mzg2NTAzMTExNg==&mid=2247483993&idx=1&sn=abdd687e0f360107be0208946a7afc1d&scene=19#wechat_redirect
在开发中我们一般使用注解方式进行开发
主要是看一下这里的注释,是处理请求并返回一个ModelAndView对象,DispatcherServlet将渲染该对象。 一个null的返回值并不是一个错误:它表示这个对象自己完成了请求处理,没有ModelAndView可以渲染。
在AbstractController类中实现了Controller类,handleRequest实现如下
@Override @Nullable public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { if (HttpMethod.OPTIONS.matches(request.getMethod())) { response.setHeader("Allow", getAllowHeader()); return null; } // Delegate to WebContentGenerator for checking and preparing. checkRequest(request); prepareResponse(response); // Execute handleRequestInternal in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return handleRequestInternal(request, response); } } } return handleRequestInternal(request, response); }过程可以大致看一下,首先是设置header的allow,允许资源可以用哪些HTTP方法进行请求,比如Allow: GET, HEAD,Allow:*,接着委托给WebContentGenerator进行检查和准备,然后如果需要,在同步块中执行handleRequestInternal,否则直接执行handleRequestInternal方法。
handleRequestInternal方法的实现
/** * Retrieves the URL path to use for lookup and delegates to * {@link #getViewNameForRequest}. Also adds the content of * {@link RequestContextUtils#getInputFlashMap} to the model. */ @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) { String viewName = getViewNameForRequest(request); if (logger.isTraceEnabled()) { logger.trace("Returning view name '" + viewName + "'"); } return new ModelAndView(viewName, RequestContextUtils.getInputFlashMap(request)); }getViewNameForRequest获取视图的名字,再进行logger.trace,最后创建ModelAndView对象返回。
但是在真正用的时候我们是只重写handleRequest,封装Model,返回ModelAndView就行了。
public class HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //ModelAndView 模型和视图 ModelAndView mv = new ModelAndView(); //封装对象,放在ModelAndView中。Model mv.addObject("msg","HelloSpringMVC!"); //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp return mv; } }说明:
实现接口Controller定义控制器是较老的办法缺点:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;(网站开发随便就是几十个接口,创建几十个类是不能接受的)@Controller注解类型用于声明Spring类的实例是一个控制器(被spring接管,注解@Contronller的类下面的所有的String方法,返回值都会被视图解析器解析,如果可以跳转就跳转),Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。<context:component-scan base-package="com.kuang.controller"/>
Controller注解的定义,很简单里面用的就就一个value
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { @AliasFor( annotation = Component.class ) String value() default ""; }注解本质就只是一个接口,程序处理的难点是在反射,而框架把这些处理内容隐藏起来了,除非阅读源码很难接触到。