首页 > 代码库 > SpringMVC笔记

SpringMVC笔记

导入SpringMVC只需要加入jar包就行了。
然后在web.xml文件里配置一下DispatcherServlet,设置下需要拦截的URL即可。

  1. <!-- 配置 SpringMVC 的 DispatcherServlet -->
  2. <servlet>
  3. <servlet-name>springDispatcherServlet</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <init-param>
  6. <param-name>contextConfigLocation</param-name>
  7. <param-value>classpath:springmvc.xml</param-value>
  8. </init-param>
  9. <load-on-startup>1</load-on-startup>
  10. </servlet>
  11. <!-- Map all requests to the DispatcherServlet for handling -->
  12. <servlet-mapping>
  13. <servlet-name>springDispatcherServlet</servlet-name>
  14. <url-pattern>/</url-pattern>
  15. </servlet-mapping>


一些必要的SpringMVC文件配置:
        
  1. <!-- 配置自动扫描的包 -->
  2. <context:component-scan base-package="com.atguigu.springmvc"></context:component-scan>
  1. <!-- 配置视图解析器 -->
  2. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  3. <property name="prefix" value="/WEB-INF/views/"></property>
  4. <property name="suffix" value=".jsp"></property>
  5. </bean>

        有多种视图解析器: 待补
    视图解析器详解:
        试图解析的流程:
            
  1. 不管目标方法返回的是什么类型是String、ModelAndView还是View都,SpringMVC都会把它转换为ModelAndView类型,
  2. 然后通过视图解析器得到真正的物理视图,一个View对象,然后调用renderview得到响应结果。
  3. InternalResourceViewResolver是支持InternalResourceView的视图解析器        
  1. InternalResourceViewResolver
  2.     ? JSP 是最常见的视图技术,可以使用
  3. InternalResourceViewResolver 作为视图解析器:
技术分享

自定义视图:
    自定义视图继承自View,完成getContentType方法(返回内容类型),和render方法(渲染视图)
  1. @Component
  2. public class HelloView implements View{
  3. @Override
  4. public String getContentType() {
  5. return "text/html";
  6. }
  7. @Override
  8. public void render(Map<String, ?> model, HttpServletRequest request,
  9. HttpServletResponse response) throws Exception {
  10. response.getWriter().print("hello view, time: " + new Date());
  11. }
  12. }

然后在SpringMVC里配置
  1. <!-- 配置视图 BeanNameViewResolver 解析器: 使用视图的名字来解析视图 -->
  2. <!-- 通过 order 属性来定义视图解析器的优先级, order 值越小优先级越高 -->
  3. <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
  4. <property name="order" value="100"></property>
  5. </bean>

然后handler直接返回helloview的view名字,因为此时BeanNameViewResolver的优先级比较高所以先由这个视图解析器解析。
  1. @RequestMapping("/testView")
  2. public String testView(){
  3. System.out.println("testView");
  4. return "helloView";
  5. }




待补。。。
    
  1. default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
  2. 它会对进入 DispatcherServlet 的请求进行筛查, 如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的
  3. Servlet 处理. 如果不是静态资源的请求,才由 DispatcherServlet 继续处理
  4. 一般 WEB 应用服务器默认的 Servlet 的名称都是 default.
  5. 若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
  6. <mvc:default-servlet-handler/>

  1. <mvc:annotation-driven></mvc:annotation-driven>

    这个一般都是必加的。他的加入可以防止RequestMapping不会失效
  1. ? <mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping
  2. 、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。
  3. ? 还将提供以下支持:
  4. – 支持使用 ConversionService 实例对表单参数进行类型转换
  5. – 支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化
  6. – 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
  7. – 支持使用 @RequestBody 和 @ResponseBody 注解


 

SpringMVC的常用注解:

            @Controller 
                标记目标方法类。这个类将为请求处理器
            

            @RequestMapping
                注解为控制器指定可以处理哪些URL请求
           
             —义处:提供初求映射信息。相WEB 用的根目
             —方法:提供分映射信息。相义处URL。若
                类义处@RequestMapping方法处标记URL 于 
                WEB 用的根目 


            ? @RequestMapping 除了可以使用URL 映射求外,
                还可以使用求方法、求参数及映射
            ? @RequestMapping 的 valuemethodparams 及 heads
                分表示求 URL求方法、求参数及的映射条
                件,他
系,合使用多个条件可让请求映射
                更加精
化。

                列如:
            技术分享
        ? @PathVariable 可以将 URL 中占位符参数定到控
          制器理方法的入参中URL 中的 {xxx} 占位符可以通
          @PathVariable("xxx") 定到操作方法的入参中。

          例如:
  1. @RequestMapping("/delete/{id}")
  2. public String delete(@PathVariable("id") Interger id){
  3. ...
  4. }




        @RequestParam
               将URL中的请求参数的值传递给请求方法    
    – value:参数名
    – required:是否必。默认为 true, 表示求参数中必包含对应
    的参数,若不存在,将抛出
        例如:
  1. @RequestMapping("/xxx")
  2. public String delete(@RequestParam(value="userName",required=false) String userName,
  3. @RequestParam("age") int age){
  4. ...
  5. }

    这种类似的有
            @RequestHeader
            @CookieValue
  1. public String handle(@CookieValue(value="sessionId",required=false) String
  2. sessionID)
        就不详细介绍了



        Spring MVC 会按求参数名和 POJO 属性名行自配,自动为该对象填充属性支持级联属性
        如:dept.deptIddept.address.tel

        
        @ModelAndView
  1. 控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
  1. Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
  2. 如果方法的入参为 Map Model 型,Spring MVC 会将隐含模型的引用传
  3. 递给这些入参。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数
  4. 据,也可以向模型中添加新的属性数据.
  1. 在方法定义上使用 @ModelAttribute 注解:Spring MVC在调用目标处理方法前,会先逐个调用在方法级上标注了
  2. @ModelAttribute 的方法
    
  1. /**
  2. * 运行流程:
  3. * 1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中. 键为: user
  4. * 2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.
  5. * 3. SpringMVC 把上述对象传入目标方法的参数.
  6. *
  7. * 注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!
  8. *
  9. * SpringMVC 确定目标方法 POJO 类型入参的过程
  10. * 1. 确定一个 key:
  11. * 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
  12. * 2). 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值.
  13. * 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
  14. * 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到.
  15. * 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰,
  16. * 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所
  17. * 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常.
  18. * 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则
  19. * 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
  20. * 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
  21. *
  22. * 源代码分析的流程
  23. * 1. 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.
  24. * 2. 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性
  25. * 1). 创建 WebDataBinder 对象:
  26. * ①. 确定 objectName 属性: 若传入的 attrName 属性值为 "", 则 objectName 为类名第一个字母小写.
  27. * *注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则 attrName 值即为 @ModelAttribute
  28. * 的 value 属性值
  29. *
  30. * ②. 确定 target 属性:
  31. * > 在 implicitModel 中查找 attrName 对应的属性值. 若存在, ok
  32. * > *若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中
  33. * 获取 attrName 所对应的属性值. 若 session 中没有对应的属性值, 则抛出了异常.
  34. * > 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key
  35. * 和 attrName 相匹配, 则通过反射创建了 POJO 对象
  36. *
  37. * 2). SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性.
  38. * 3). *SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel.
  39. * 近而传到 request 域对象中.
  40. * 4). 把 WebDataBinder 的 target 作为参数传递给目标方法的入参.
  41. */


    
    @SessionAttributes 
         
  1. /**
  2. * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),
  3. * 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)
  4. *
  5. * 注意: 该注解只能放在类的上面. 而不能修饰放方法.

  6. */

    
数据定流程 :
        
  1. ? 1. Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创
  2. 建 DataBinder 实例对象

  3. ? 2. DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式
  4. 化工作。将 Servlet 中的请求信息填充到入参对象中

  5. ? 3. 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果
  6. BindingData 对象


  7. ? 4. Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参

        其运行流程如下图所示:
技术分享
 

数据格式化:
  1. <mvc:annotation-driven/> 默认创建的ConversionService 实例即为
  2. FormattingConversionServiceFactroyBean
  3. ? FormattingConversionServiceFactroyBean 内部已经注册了 :
  4.     – NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性
  5.         使用 @NumberFormat 注解
  6.     – JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型
  7.         的属性使用 @DateTimeFormat 注解
例如:
    
  1. @DateTimeFormat(pattern="yyyy/MM/dd")
  2. private Date birthday;
  3. @NumberFormat(pattern="#,###.##")





自定义类转换  
            待补。。。。



    @InitBinder 
  1. ? 由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定

  2. ? @InitBinder方法不能有返回值,它必须声明为void。

  3. ? @InitBinder方法的参数通常是是 WebDataBinder
例如:
        
  1. @InitBinder
  2. public void initBinder(WebDataBinder dataBinder){
  3. dataBinder.setDisallowedFields("xxx");
  4. }

    

HttpMessageConverter<T>  :
        负责求信息转换为一个象(T),象(T为响应信息

    技术分享
 其中HttpInputMessage就是输入流
        HttpOutputMessage就是输出流

  1. 如图所示,通俗的讲,就是将输入流变成java对象,把java对象变成输出流。
使用以下2个注解即可使用HttpMessageConverter
                   -- @ResponseBody
                   -- @RequsetBody     

  1. @ResponseBody
  2. @RequestMapping("/testHttpMessageConverter")
  3. public String testHttpMessageConverter(@RequestBody String body){
  4. System.out.println(body);
  5. return "helloworld! " + new Date();
  6. }


   文件上传:
        查看视频即可,很简单。


   自定义拦截器:
        接口继承自HandlerInterceptor,实现其抽象方法
        需要在springmvc.xml文件里进行配置: 具体配置如下所示
        
  1. <mvc:interceptors>
  2. <!-- 配置自定义的拦截器 -->
  3. <bean class="com.atguigu.springmvc.interceptors.FirstInterceptor"></bean>
  4. <!-- 配置拦截器(不)作用的路径 -->
  5. <mvc:interceptor>
  6. <mvc:mapping path="/emps"/>
  7. <bean class="com.atguigu.springmvc.interceptors.SecondInterceptor"></bean>
  8. </mvc:interceptor>
  9. </mvc:interceptors>
其中要实现的3个接口如下
  1. /**
  2. * 该方法在目标方法之前被调用.
  3. * 若返回值为 true, 则继续调用后续的拦截器和目标方法.
  4. * 若返回值为 false, 则不会再调用后续的拦截器和目标方法.
  5. *
  6. * 可以考虑做权限. 日志, 事务等.
  7. */
  8. @Override
  9. public boolean preHandle(HttpServletRequest request,
  10. HttpServletResponse response, Object handler) throws Exception {
  11. System.out.println("[FirstInterceptor] preHandle");
  12. return true;
  13. }
  1. /**
  2. * 调用目标方法之后, 但渲染视图之前.
  3. * 可以对请求域中的属性或视图做出修改.
  4. */
  5. @Override
  6. public void postHandle(HttpServletRequest request,
  7. HttpServletResponse response, Object handler,
  8. ModelAndView modelAndView) throws Exception {
  9. System.out.println("[FirstInterceptor] postHandle");
  10. }
  1. /**
  2. * 渲染视图之后被调用. 释放资源
  3. */
  4. @Override
  5. public void afterCompletion(HttpServletRequest request,
  6. HttpServletResponse response, Object handler, Exception ex)
  7. throws Exception {
  8. System.out.println("[FirstInterceptor] afterCompletion");
  9. }

当存在多个拦截器的时候,调用的顺序:
    技术分享
 

    异常处理:
        
  1. Spring MVC 通过 HandlerExceptionResolver 处理程序
  2. 的异常,包括 Handler 映射、数据绑定以及目标方法执行
  3. 时发生的异常。
    其有几个实现类,常见的如下:
            ExceptionHandlerExceptionResolver 
            ResponseStatusExceptionResolver 
            DefaultHandlerExceptionResolver 



ExceptionHandlerExceptionResolver
    在控制器里(handler)中通过标记@ExceptionHandler 的异常处理方法,只能作用于这个Handler中,并不能全局。
  1. /**
  2. * 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象
  3. * 2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值
  4. * 3. @ExceptionHandler 方法标记的异常有优先级的问题.
  5. * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常,
  6. * 则将去 @ControllerAdvice 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
  7. */
  8. @ExceptionHandler({ArithmeticException.class})
  9. public ModelAndView handleArithmeticException(Exception ex){
  10. System.out.println("出异常了: " + ex);
  11. ModelAndView mv = new ModelAndView("error");
  12. mv.addObject("exception", ex);
  13. return mv;
  14. }

如要全局要声明成一个类:
    并且用@ControllerAdvice修饰
    例如:
  1. @ControllerAdvice
  2. public class SpringMVCTestExceptionHandler {
  3. @ExceptionHandler({ArithmeticException.class})
  4. public ModelAndView handleArithmeticException(Exception ex){
  5. ...
  6. }
  7. }


            其余略:可翻看佟刚的SpringMVC的PPT。


SpringMVC的运行流程:
        技术分享
 

  1. HandlerExecutionChain:里面包含了handler的目标方法和拦截器
  2. 通过HandlerMapping获取。
  3. HandlerMapping定义了请求到处理器的映射。
  4. HandlerAdapter处理请求到目标方法中很多的处理在里面操作。

        





来自为知笔记(Wiz)


SpringMVC笔记