springmvc2详细笔记

1.Controller接口及其实现类
Controller是控制器/处理器接口,只有一个方法handleRequest,用于进行请求的功能处理(功能处理方法),处理完请求后返回ModelAndView对象(Model模型数据部分和 View视图部分)。
如果想直接在处理器/控制器里使用response向客户端写回数据,可以通过返回null来告诉DispatcherServlet我们已经写出响应了,不需要它进行视图解析
Spring默认提供了一些Controller接口的实现类以方便我们使用,在Eclipse中选择Controller接口然后右键open type Hierarchy即可查看该接口的实现类,每个实现类都有自己特殊的功能,这里以实现类AbstractController为例简单介绍下。
查看AbstractController类中代码可知,我们写一个Controller的时候可以继承AbstractController然后实现handleRequestInternal方法即可。提供了【可选】的会话(session)的串行化访问功能,例如:
public class HelloWorldController extends AbstractController{
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
String name = request.getParameter(“name”);
//ModelAndView对象中包括了要返回的逻辑视图,以及数据模型
ModelAndView mv = new ModelAndView();
//设置视图名称,可以是字符串 也可以是视图对象
mv.setViewName(“hello”);
//设置数据模型
mv.addObject(“name”, name);
return mv;
}
}



直接通过response写响应,例如:
public class HelloWorldController extends AbstractController{
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.getWriter().write(“Hello World!!”);
return null;
}
}
强制请求方法类型,例如:
//只支持post和get方法
当前请求的session前置条件检查,如果当前请求无session将抛出HttpSessionRequiredException异常,例如:
//在进入该控制器时,一定要有session存在,否则抛出HttpSessionRequiredException异常。



2.处理器拦截器/控制器拦截器
SpringMVC的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
1)常见应用场景
1、日志记录
2、权限检查
3、性能监控
4、通用行为 例如读取用户cookie

2)拦截器接口
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
}

      preHandle方法
           预处理回调方法,实现处理器的预处理,第三个参数为的处理器(本次请求要访问的那个Controller)
           返回值:true表示继续流程(如调有下一个拦截器或处理器)
           false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应
      postHandle方法
           后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理,modelAndView也可能为null。    
      afterCompletion方法
           整个请求处理完毕回调方法,即在视图渲染完毕时回调

 3)拦截器适配器
      有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor 接口的话,三个方法必须实现,此时spring 提供了一个HandlerInterceptorAdapter 适配器(适配器模式),允许我们只实现需要的回调方法。
      在HandlerInterceptorAdapter中,对HandlerInterceptor 接口中的三个方法都进行了空实现,其中preHandle方法的返回值,默认是true

 4)测试一个拦截器
拦截器代码:
          public class MyInterceptor1 extends HandlerInterceptorAdapter{
               @Override
               public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                         throws Exception {
                    System.out.println("MyInterceptor1 preHandle");
                    return true;
               }
               @Override
               public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                         ModelAndView modelAndView) throws Exception {
                    System.out.println("MyInterceptor1 postHandle");
               }
               @Override
               public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                         throws Exception {
                    System.out.println("MyInterceptor1 afterCompletion");
               }
          }

      配置文件:(注意此配置在文件中的配置顺序,要写在配置文件的上面)
      <bean name="handlerInterceptor1" class="com.briup.web.interceptor.MyInterceptor1"/>
      <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
           <property name="interceptors">
                <list>
                     <ref bean="handlerInterceptor1"/>
                </list>
           </property>
      </bean>         

 5)测试俩个拦截器
      俩个拦截器的代码和上面类似,只是每个输出的内容不同
      配置文件:
      <bean name="handlerInterceptor1" class="com.briup.web.interceptor.MyInterceptor1"/>
      <bean name="handlerInterceptor2" class="com.briup.web.interceptor.MyInterceptor2"/>

      <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
           <property name="interceptors">
                <list>
                     <ref bean="handlerInterceptor1"/>
                     <ref bean="handlerInterceptor2"/>
                </list>
           </property>
      </bean>

      访问一个测试的Controller查看结果:
      MyInterceptor1 preHandle
      MyInterceptor2 preHandle
      TestController执行
      MyInterceptor2 postHandle
      MyInterceptor1 postHandle
      MyInterceptor2 afterCompletion
      MyInterceptor1 afterCompletion
     
      注意:<list>标签中引用拦截器的顺序会影响结果输出的顺序


 6)如果Controller等采用的注解配置,那么拦截器需要mvc标签进行配置
      注意:每个<mvc:interceptor>只能配置一个拦截器
      <mvc:interceptors>
           <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <ref bean="handlerInterceptor1"/>
           </mvc:interceptor>
      </mvc:interceptors>

      例如1: 注意/*和/**的区别
          <mvc:interceptors>
               <!-- 下面所有的mvc映射路径都会被这个拦截器拦截 -->
               <bean class="com.briup.web.interceptor.MyInterceptor1" />
               <mvc:interceptor>
                    <mapping path="/**"/>
                    <exclude-mapping path="/admin/**"/>
                    <bean class="com.briup.web.interceptor.MyInterceptor2" />
               </mvc:interceptor>
               <mvc:interceptor>
                    <mapping path="/secure/*"/>
                    <bean class="com.briup.web.interceptor.MyInterceptor3" />
               </mvc:interceptor>
          </mvc:interceptors>
    
 7)拦截器是单例
      因此不管多少用户请求多少次都只有一个拦截器实现,即线程不安全。

所以在必要时可以在拦截器中使用ThreadLocal,它是和线程绑定,一个线程一个ThreadLocal,A 线程的ThreadLocal只能看到A线程的ThreadLocal,不能看到B线程的ThreadLocal。

 8)登录检查
       public class LoginInterceptor extends HandlerInterceptorAdapter{
               @Override
               public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                         throws Exception {
                    //请求到登录页面放行
                    if(request.getServletPath().startsWith("/login")) {
                         return true;
                    }
                    //如果用户已经登录放行
                    if(request.getSession().getAttribute("username") != null) {
                         return true;
                    }
                    //其他没有登录的情况则重定向到登录页面
                    response.sendRedirect(request.getContextPath() + "/login");
                    return false;
               }
          }
 注意:推荐能使用servlet规范中的过滤器Filter实现的功能就用Filter实现,因为HandlerInteceptor只有在SpringWebMVC环境下才能使用,因此Filter是最通用的、最先应该使用的。

3.基于注解的SpringMVC
1)用于支持注解的配置
在Spring中,
处理器类可以使用 @Controller注解
如果在处理器上使用 @Controller注解,那么还需要在配置文件中指定哪个包下面的类使用了该注解: <context:component-scan base-package=“com.briup.web.controller”></context:component-scan>
业务逻辑层可以使用 @Service注解
数据持久层可以使用 @Repository注解

 2)基于注解的Controller
      使用注解后,就不需要再实现特定的接口,任意一个javaBean对象都可以当做处理器对象,对象中任意一个方法都可以作为处理器方法。
      只需    在类上加上 @Controller注解  方法上加上 @RequestMapping注解
 3)基于注解的Controller的返回值
      1.返回ModelAndView,和之前一样

      2.返回String,表示跳转的逻辑视图名字,模型可以通过参数传过来
           @Controller
           public class HomeController {
                @RequestMapping("/home")
                public String home(Model model){
                     model.addAttribute("msg", "hello world");
                     return "index";
                }
           }
     
      3.声明返回类型为void
           可以通过参数获取request和response,分别使用服务器内部跳转和重定向,自己来决定要跳转的位置。
           @Controller
           public class HomeController {
                @RequestMapping("/home")
                public void home(HttpServletRequest request,HttpServletResponse response){
                     String username = request.getParameter("username");
                     response.setContentType("text/html;charset=utf-8");
                     response.getWriter().write("hello world! "+username);
                     //或者使用servlet的方式进行跳转/重定向
                    
                }
           }

5.Spring2.5中引入注解对控制器/处理器(controller/handler)支持
@Controller
用于标识是处理器类;
@RequestMapping
请求到处理器功能方法的映射规则;
@RequestParam
请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute
请求参数到命令对象的绑定;
@InitBinder
自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;

6.Spring3引入了更多的注解,其中包含了对RESTful架构风格的支持
@CookieValue
cookie数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader
请求头数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody
请求的body体的绑定
@ResponseBody
处理器功能处理方法的返回值作为响应体
@ResponseStatus
定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler
注解式声明异常处理器;
@PathVariable
请求URI 中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful架构风格的URI;

7.Spring3中引入的mvc命名空间
mvc这个命名空间是在Spring3中引入的,其作用是用来支持mvc的配置
需要在中声明出这个命名空间及其对应的schemaLocation中的值
mvc:annotation-driven
自动注册基于注解风格的映射器和适配器:
在spring2.5中是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter
在spring3中是RequestMappingHandlerMapping和RequestMappingHandlerAdapter.
同时还支持各种数据的转换器.

 <mvc:interceptors>
      配置自定义的处理器拦截器,例如:
      <mvc:interceptors>
           <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <ref bean="handlerInterceptor1"/>
           </mvc:interceptor>
      </mvc:interceptors>
 <mvc:view-controller>
      收到相应请求后直接选择相应的视图,例如:
      <mvc:view-controller path="/hello" view-name="test"></mvc:view-controller>
 <mvc:resources>
      逻辑静态资源路径到物理静态资源路径的对应.例如:
      <mvc:resources mapping="/images/**" location="/images/"/> 
      <mvc:resources mapping="/js/**" location="/js/"/> 
      <mvc:resources mapping="/css/**" location="/css/"/>
 <mvc:default-servlet-handler>
      当在web.xml中DispatcherServlet使用<url-pattern>/</url-pattern> 映射的时候,会静态资源也映射了,如果配置了这个mvc标签,那么再访问静态资源的时候就转交给默认的Servlet来响应静态文件,否则报404 找不到静态资源错误。

8.@Controller和@RequestMapping注解
1)声明处理器—在类的上面加上@Controller
2)映射处理器中的【功能处理方法】—在方法的上面加上@Controller

 3)@RequestMapping也可以写在处理器类上
 @RequestMapping("/test")
 @Controller
 public class HomeController {
      @RequestMapping("/home")
      public ModelAndView home(){
           ModelAndView mv = new ModelAndView("index");
           return mv;
      }
 }
 表明该方法映射的url路径为/test/home

9.请求映射
假设浏览器发送了一个请求如下:
http协议的请求格式如下:
---------------------------------
请求方法 URL 协议版本号
请求头信息
请求头信息
请求头信息

回车换行
请求正文
---------------------------------
从格式中我们可以看到【请求方法、URL、请求头信息、请求正文】这四部分一般是可变的,因此我们可以把请求中的这些信息在处理器的【功能处理方法】中进行的映射,因此请求的映射分为如下几种:
URL路径映射
使用URL映射到处理器的功能处理方法;
请求方法映射限定
例如限定功能处理方法只处理GET请求;
请求参数映射限定
例如限定只处理包含username参数的请求;
请求头映射限定
例如限定只处理"Accept=application/json"的请求。

10.URL路径映射
1)普通URL路径映射
@RequestMapping(value="/test")
@RequestMapping("/hello")
注解中只出现一个参数且参数名为value的话,可以将参数名去掉
@RequestMapping(value={"/test", “/user/hello”})
多个URL路径可以映射到同一个处理器的功能处理方法。

 2)URI模板模式映射
      @RequestMapping(value="/users/{userId}")
           {XXX}占位符, 请求的URL可以是"/users/123456"或"/users/abcd",之后可以通过@PathVariable可以提取URI模板模式中的{XXX}中的值
      @RequestMapping(value="/users/{userId}/create")
           这样也是可以的,请求的URL可以是"/users/123/create"
      @RequestMapping(value="/users/{userId}/topics/{topicId}")
           这样也是可以的,请求的URL可以是"/users/123/topics/123"

 3)Ant风格的URL路径映射
      @RequestMapping(value="/users/**")
           可以匹配"/users/abc/abc",但"/users/123"将会被【URI模板模式映射中的"/users/{userId}"模式优先映射到】
      @RequestMapping(value="/product/?")
           可匹配"/product/1"或"/product/a",但不匹配"/product"或"/product/aa";
           ?代表有且只有一个字符
      @RequestMapping(value="/product*")
           可匹配"/productabc"或"/product",但不匹配"/productabc/abc";
           *代表0~n个字符
      @RequestMapping(value="/product/*")
           可匹配"/product/abc",但不匹配"/productabc";
      @RequestMapping(value="/products/**/{productId}")
           可匹配"/products/abc/abc/123"或"/products/123",也就是Ant风格和URI模板变量风格可混用;
           **代表所有的子路径

 4)正则表达式风格的URL路径映射
      从Spring3.0 开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式},之后通过@PathVariable可以提取{XXX:正则表达式匹配的值}中的XXX这个变量的值。
      @RequestMapping(value="/products/{categoryCode:\\d+}-{pageNumber:\\d+}")
           可以匹配"/products/123-1",但不能匹配"/products/abc-1",这样可以设计更加严格的规则。
      @RequestMapping(value="/user/{userId:^\\d{4}-[a-z]{2}$}")
           可以匹配"/user/1234-ab"
     
      注意:\d表示数字,但是\在java的字符串中是特殊字符,所以需要再加一个\进行转义即可
      (参照之前js的学习文档,和java的正则几乎一致,js正则中的一个/变为java中的俩个/即可)
           括号:
                [abc]      查找方括号之间的任何字符。
                [^abc]      查找任何不在方括号之间的字符。
                [0-9]      查找任何从 0 至 9 的数字。
                [a-z]      查找任何从小写 a 到小写 z 的字符。
                [A-Z]      查找任何从大写 A 到大写 Z 的字符。
                [A-z]      查找任何从大写 A 到小写 z 的字符。
                (red|blue|green)      查找任何指定的选项。
          
           元字符:
                .      查找单个任意字符,除了换行和行结束符.如果要表示.这个字符,需要转义
                \w      查找单词字符。     字母 数字 _
                \W      查找非单词字符。非 字母 数字 _
                \d      查找数字。
                \D      查找非数字字符。
                \s      查找空白字符。
                \S      查找非空白字符。
                \b      匹配单词边界。
                \B      匹配非单词边界。
                \0      查找 NUL 字符。
                \n      查找换行符。
                \f      查找换页符。
                \r      查找回车符。
                \t      查找制表符。
                \v      查找垂直制表符。

           量词:
                n+           匹配任何包含至少一个 n 的字符串。
                n*           匹配任何包含零个或多个 n 的字符串。
                n?           匹配任何包含零个或一个 n 的字符串。
                n{X}      匹配包含 X 个 n 的序列的字符串。
                n{X,Y}      匹配包含 X 到 Y 个 n 的序列的字符串。
                n{X,}      匹配包含至少 X 个 n 的序列的字符串。
                n$           匹配任何结尾为 n 的字符串。
                ^n           匹配任何开头为 n 的字符串。
                ?=n      匹配任何其后紧接指定字符串 n 的字符串。
                ?!n      匹配任何其后没有紧接指定字符串 n 的字符串。


      正则表达式风格的URL路径映射是一种特殊的URI模板模式映射
      URI模板模式映射不能指定模板变量的数据类型,如是数字还是字符串;
      正则表达式风格的URL路径映射,可以指定模板变量的数据类型,可以将规则写的相当复杂。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值