一、解读url-pattern

servlet-Mapping中的url-pattern中使用 /

  1. <servlet-mapping>
  2. <servlet-name>springmvc</servlet-name>
  3. <url-pattern>/</url-pattern> 【这样就可以不用some.do了,就是some了】
  4. </servlet-mapping>
  • 导致所有的静态资源请求都交给了DispatcherSerlvet处理,默认情况下DispatcherServlet没有处理静态资源的能力。没有控制器对象能对静态资源的访问,
  • 所有静态资源都是404【图片,js,html,css】

:::warning (当中央调度器的url-pattern设置为/ 之后 静态资源访问会失败 404 ,动态资源可以正常访问) :::

1、第一种处理静态资源无法访问的方式

需要在springmvc的配置文件中加入 <mvc:default-servlet-handler>

  • 加入这个标签后,框架会创建一个default对象,他像是一个监察员,对请求中的uri进行筛查,如果是访问静态资源,那么 他做处理。【注意 这里要加入 注解驱动,要不动态资源无法访问,有冲突,至于什么冲突,负负得正吧…】

    1. <mvc:default-servlet-handler/>
    2. <mvc:annotation-driven/>

    2、第二种处理静态资源无法访问的方式【常用】

    在springmvc的配置文件中添加该标签
    <mvc:resources mapping="``/static/**``" location="``/static/``"/>

  • 属性:

    • Mapping: 访问静态资源的uri,使用统配符 ** [两个星星]
    • Location:静态资源在项目中的目录
  • 作用:
    • 加入该标签后,框架会创建 ResourceHttpRequestHandler对象,让这个对象去处理静态资源的访问。
  • 注意:还需要添加上json的注解驱动标签 不然有冲突
    • <mvc:annotation-driven/>
  • 常用
    1. <mvc:resources mapping="/static/**" location="/static/"/>
    2. <mvc:annotation-driven/>

    二、路径问题

    在jsp/html中路径是使用 /开头 还是不用 / 开头 ?

1、地址分类:

相对地址:除绝对地址其余都是相对地址 user/some.do /user/some.do
相对地址不能独立使用,必须要有一个参考地址,通过参考地址+相对地址=访问地址
绝对地址:带有协议名称的。 http://www.baidu.com

2、处理方案

Jsp/html文件上有一个 user/some.do 的请求,链接

当你的地址没有斜杠 / 开头,点击链接时,访问地址是当前页面的地址 加上 链接的地址 【不建议使用】

会出现的问题:

解决方案:

  • 添加EL表达式

<a href="${pageContext.request.contextPath}/user/some.do"> ``链接``</a>

  • 加入一个base标签

表示当前页面中访问地址中的基地址 【你的页面中所有 没有以“/” 开头的地址,都是以base中的地址为参考地址
使用base中的地址 + user/some.do 组成访问地址
<``**base href="http://localhost:8080/myWeb/**``"/>
未命名图片.png

当你的地址有斜杠 / 开头,点击链接时,访问的是服务器地址 加上 链接的地址

3、在项目中遇到了 / 开头的路径时,可加入${pageContext.request.contextPath}

<a href="``**${pageContext.request.contextPath}**``/user/some.do"> ``链接``</a>

4、通过代码获取项目的路径,base可以直接使用获取到的

  1. <%
  2. //获取项目路径,到myWeb项目那里
  3. String basePath = request.getScheme() + "://" +
  4. request.getServerName() + ":" + request.getServerPort() +
  5. request.getContextPath() + "/";
  6. %>
  7. <title>Title</title>
  8. <base href="<%=basePath%>">
  9. <a href="user/doSome">aaaaaaaaaaa</a>
  10. //在使用了base之后,就不需要添加/开头了,因为base会将没有以斜杠开头的地址,把参考地址改为base地址

未命名图片.png

三、请求转发和重定向

  • springmvc对请求转发和重定向操作进行了封装,现在可以使用简单的方式实现请求转发和重定向
  • **forward**:表示请求转发,实现request.getRequestDispatcher("xx.jsp").forward();
  • **redirect**:表示重定向,实现response.sendRedirect("xxx".jsp)
  • forwarredirect都是框架的关键字,有一个共同的特点,他们都不和视图解析器一同工作。

1、forward

处理器方法返回ModelAndView,实现请求转发 forward
语法:mv.setViewName("forward:/视图文件完整路径")
特点:不和视图解析器一同使用,就当项目中没有视图解析器
就算有视图解析器,也得写上前缀 后缀
显式转发,明显的说明这是转发,同时setViewName("show")这也是转发
作用:项目中存在视图解析器,但是要转发的页面没在view目录下,那么就转发不到
例如:转发和index.jsp同级目录的jsp文件 setViewName("forward:/hello.jsp")
未命名图片.png

2、redirect

处理器方法返回ModelAndView,实现重定向 redirect
语法:mv.setViewName("redirect:/路由")
特点:和上面的一样

  • 框架对重定向的操作:框架会把ModelAndView中的简单类型的数据,转为字符串使用,作为hello.jsp的get请求参数使用,
  • 在jsp中使用el表达式 **${param.xxxx}** 来获取get请求参数值
  • 目的:为了在重定向的过程中能够传递数据

缺点:

  • 因为是重新从浏览器发出的请求,所以不能访问 WEB-INF 下的文件
  • 重定向取不到请求作用域的数据。【不是同一个请求包了】

未命名图片.png
未命名图片.png

四、统一全局异常处理

  • 为了避免代码中,出现冗长的try..catch的语句。
  • 统一全局异常处理:把controller中所有的异常都集中到一个地方,采用的是aop的思想,把业务逻辑和异常处理分开,解耦合。

1、使用两个注解

  1. @ExceptionHandler
  2. @ControllerAdvice

2、异常处理步骤

  1. 新建一个maven web项目
  2. 加入依赖
  3. 新建一个自定义异常类,MyUserException ,在定义子类 NameException,AgeException
  4. 在MyController中抛出异常 NameException,AgeException
  5. 创建一个普通类,作为全局异常处理类
    • 在类的上面加入注解,@ControllerAdvice
    • 在类中定义方法,方法的上面加入 @ExceptionHandler
  6. 创建处理异常的视图页面 【当发生异常了,让用户知道的页面】
  7. 创建springmvc的配置文件
    • 组件扫描器,【注解创建对象 @Controller】
      • <context:component-scan base-package="com.yixuexi``.controller``"/>
    • 组件扫描器,【扫描@ControllerAdvice所在的包名】(直接扫描他的父包也行,那上面那个就免了)
      • <context:component-scan base-package="com.yixuexi``.handler``"/>
    • 声明注解驱动
      • <mvc:annotation-driven/>

不用写try catch,直接在方法的定义上抛出他的父类异常,让统一全局异常处理类代替你去处理异常
未命名图片.png

3、@ControllerAdvice

  • 控制器增强(给控制器增加功能,——>异常处理功能)
  • 特点:必须让框架知道这个注解所在的包名,需要在springmvc声明组件扫描器
  • 位置:在类的上面定义
    1. @ControllerAdvice
    2. public class HandlerException {
    3. // 在这个统一全局异常处理类中写方法 来处理对应的异常
    4. }

4、@ExceptionHandler(异常类.class)

  • value参数表示该异常类由该方法进行处理,一个异常类的class
  • 位置:方法定义的上面
    1. @ExceptionHandler(NameException.class)
    2. public ModelAndView doNameException(Exception e){}
    统一全局异常处理类中的方法定义:和处理器方法定义是一样的,可以有ModelAndViewString void,等等返回值,也可以有多个参数
    参数Exception e 表示controller类中抛出的异常对象,可以通过该形参获取详细的异常信息 ```java @ExceptionHandler(NameException.class) public ModelAndView doNameException(Exception e){ ModelAndView mv = new ModelAndView(); //给请求作用域中添加数据 mv.addObject(“msg”,”姓名必须是张三,其他不能显示”); mv.addObject(“ex”,e); //转发给nameError页面【已经配置了视图解析器】 mv.setViewName(“nameError”); // 转发给nameError.jsp显示错误信息 return mv; }
  1. <a name="LkvzA"></a>
  2. ## 5、发生异常之后的处理逻辑:
  3. 1. 需要把异常记录下来,记录到数据库,日志文件记录发生的时间,那个方法发生的,异常错误内容
  4. 1. 发送通知,把异常的信息通过邮件,短息,微信发送给相关人员
  5. 1. 给用户友好的提示
  6. <a name="WNXLb"></a>
  7. ## 6、定义一个处理其他异常的方法(只能有一个该方法)
  8. > 【其实统一都交给他处理就行,别的方法不需要】
  9. - 因为处理的是Name和Age的异常,还会有许多不知道会发生什么的异常,比如空指针,类没找到,除数为0的异常….
  10. - 方法的定义和上面的一样,特殊的是**方法上定义的注解 value属性没有值**
  11. ```java
  12. @ExceptionHandler(空的)
  13. public ModelAndView doOtherException(Exception e){
  14. //抛出非 age 非 name异常时,在这里执行
  15. ModelAndView mv = new ModelAndView();
  16. mv.addObject("msg","未知异常");
  17. mv.addObject("ex",e);
  18. //转发给默认的defaultError页面
  19. mv.setViewName("defaultError");
  20. return mv;
  21. }

五、拦截器

1、拦截器是什么

  1. 拦截器是springmvc的一种,需要实现HandlerInterceptor接口

  2. 和过滤器类似,功能的方向侧重点不同:

    1. 过滤器是用来过滤请求参数,设置编码字符集等功能
    2. 拦截器是拦截用户的请求,对请求做判断处理的。
  3. 拦截器特点:

    1. 全局的,可以对多个controller进行拦截
    2. 一个项目中可以有一个或者多个拦截器,他们在一起来拦截用户的请求
  4. 拦截器常用在:

    1. 用户登陆处理,权限的检查,记录日志

2、拦截器的使用步骤

  1. 定义类,实现HandlerInterceptor接口
    1. 实现里面的3个方法
  2. 需要在springmvc配置文件中中声明拦截器,让框架知道拦截器的存在
    1. 指定拦截的请求的uri地址

拦截器的执行时间

  • 在请求处理之前,controller类中的方法执行之前,先被拦截
  • 在控制器方法执行之后,也会执行拦截器
  • 在请求处理完成后也会执行拦截器

拦截器看作是多个Controller中公用的功能,集中到拦截器统一处理,使用的aop的思想

3、拦截器和过滤器的区别

  1. 过滤器是Servlet中的对象,拦截器是框架中的对象
  2. 过滤器是实现Filter接口,拦截器是实现HandlerInterceptor
  3. 过滤器是用来设置request response的参数,属性的,侧重对数据的过滤的

拦截器是用来验证请求的,能截断请求【返回false】

  1. 过滤器是在拦截器之前 先执行的
  2. 过滤器是tomcat服务器创建的对象,拦截器是springmvc创建的对象
  3. 过滤器是一个执行时间点,拦截器有三个执行时间点
  4. 过滤器可以处理jsp,js,html等等,

拦截器是侧重拦截对controller的请求,如果你的请求不能被中央调度器【DispatcherServlet】接收,那么他不会执行拦截器的内容

4、HandlerInterceptor接口中的三个方法

4.1、第一个 preHandle()

  1. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  2. 计算的业务逻辑,根据计算结果 返回true还是false
  3. return false;
  4. }

preHandle:预处理方法,整个项目的入口,重要

形参:

  • 请求对象
  • 响应对象
  • handler:被拦截的控制器对象,controller对象

返回值boolean

  • true: 请求通过了拦截器的验证,可以执行处理器的方法
    • 同时拦截器的另外两个方法都会执行
  • false: 请求没有通过拦截器的验证,请求到达拦截器后,就截至了,请求不会被处理

特点:

  1. 方法在控制器方法(MyController的doSome()方法)之前先执行的
    • 用户的请求首先到达此方法
  2. 在这个方法中可以获取请求的信息,验证请求是否符合要求。
    • 可以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)
    • 如果验证失败可以截断请求,请求不会被处理
    • 验证成功可以放行请求,此时控制器方法才能执行
  3. 可以想象成电影院的售票员,这个preHandle方法就是入口

    4.2、第二个方法 postHandle()

    1. @Override
    2. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    3. 可以在里面修正结果 modelAndView这个对象的方法
    4. }
    postHandle() 后处理方法

    形参:

  • Handler:被拦截的处理器对象 MyController
  • modelAndView:处理方法的返回值

    特点:

  • 在处理器方法之后执行的

  • 能够获取到处理器方法的返回值,ModelAndView
  • 可以修改ModelAndView中的数据和视图,影响最后的结果

    作用:

  • 对原来的执行结果做二次修正

4.3、第三个方法

  1. @Override
  2. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  3. }

afterCompletion():最后执行的方法

形参:

  • Handler 被拦截的处理器对象
  • Exception ex:程序中发生的异常

    特点:

  • 在请求处理完成后执行的。框架中规定当视图处理完成后【对视图进行了forward,就认为请求处理完成】

    作用:

  • 一般做资源回收功能

  • 在程序中创建了一些对象,在这里进行删除。把占用的内存回收

六、多个拦截器

声明拦截器:先在springmvc配置文件里声明的先执行,后声明的后执行(底层就是一个ArrayList)按照先后顺序放入到ArrayList

1、执行顺序:

两个拦截器的preHandle()方法返回值都是true
1111111111111-拦截器的 preHandle()方法执行
2222222222222-拦截器的 preHandle()方法执行
2222222222222-拦截器的 postHandle()方法执行
1111111111111-拦截器的 postHandle()方法执行
2222222222222-拦截器的afterCompletion()方法执行
1111111111111-拦截器的afterCompletion()方法执行
————————————————————————————————
两个拦截器的preHandler()方法返回值 1是true 2是false
1111111111111-拦截器的 preHandle()方法执行
2222222222222-拦截器的 preHandle()方法执行
1111111111111-拦截器的 afterCompletion()方法执行

1返回是真的话 他的第三个方法 afterCompletion肯定会执行到
只要任意个返回false,那么controller里的doSome()方法不会执行
——————————————————————————————————
两个拦截器的preHandler()方法返回值 1是false 2是true
1111111111111-拦截器的 preHandle()方法执行

因为这个1在ArrayList集合中是第一个,他是false就直接是false了 后面的链条直接就截止了
未命名图片.png
未命名图片.png

七、拦截器登陆验证

  1. maven项目,加依赖
  2. Web.xml注册中央调度器
  3. 新建index.jsp发起请求
  4. 新建MyController类处理请求
  5. 创建MyController处理请求
  6. 创建结果show.jsp
  7. 创建login.jsp模拟登录(把用户的信息放到session中)
    1. 创建logout.jsp模拟退出信息(把用户信息从session中删除)
  8. 创建拦截器,从session中来获取用户的登录数据,验证能否访问系统
  9. 创建一个验证的jsp,如果验证失败,给出提示
  10. 创建springmvc的配置文件