spring第四讲

目录

四、拦截器异常处理

1

2 拦截器

3 时间转换器

4 全局异常处理

四、拦截器异常处理

1 <mvc: default-servlet-handler/>

如果将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。感觉就是所有资源都被拦截而如何让Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理, 下面就会用到 <mvc: default-servlet-handler/> 在springMVC的配置文件中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。

  <servlet>
    <servlet-name>lwl</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <!--      如果是一个maven项目:那这里的classpath:就是要去main下面的resources里面去寻找对应的文件-->
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>lwl</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
    <!--
        因为DispatcherServlet请求映射配置为"/",所以这里需要开放页面静态资源
    -->
    <mvc:default-servlet-handler/>

2 拦截器

SpringMVC中的拦截器用于拦截控制器方法的执行

SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式:

第一种方式是要定义的Interceptor类要实现Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;

第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

实现HandlerInterceptor接口

HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。

(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。

(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

登录拦截器:

public class LoginIntercaptor implements HandlerInterceptor {
//    如果没有拦截器,那么需要在每个方法里面都写上对应的判断语句,去判断session中是否有值
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object name = session.getAttribute("name");
        if (name==null){
//            如果session中没有值,那么就进行重定向,因为不知道是几层路径,所以这里重定向选择的是绝对路径:项目名称/路径
            String contextPath = request.getContextPath();
            response.sendRedirect(contextPath+"/login.jsp");
            return false;
        }else {
//            如果有值,那么就走下一个过滤器
            return true;
        }
​
    }
//此方法在Controller的业务方法执行之后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
​
    }
//此方法在Controller的业务方法执行结束并且视图解析完成后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
​
    }
}

拦截器编写完之后需要配置到spring.xml文件中:

    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
<!--            拦截所有的路径,包括jsp页面,所以这里需要在web.xml中配置一下开放的资源 -->
            <mvc:mapping path="/**"/>
            <!-- 将要跳转的登录页面放行 -->
            <mvc:exclude-mapping path="/login"/>
<!--            将拦截器作为bean注入到spring容器中-->
            <bean class="com.lwl.interceptor.LoginIntercaptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

因为配置的拦截器是拦截所有类型的路径,这里还要在web.xml中配置一下需要放行的静态资源

<!--是为了解决拦截器拦截静态资源,所以这里要填上放行的静态资源,
这里需要放行什么样的静态资源还可以自己添加
,这段话一定要放在前端控制器之前-->
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.css</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.gif</url-pattern>
    <url-pattern>*.jpeg</url-pattern>
    <url-pattern>/assets/*</url-pattern>
    <url-pattern>/images/*</url-pattern>
  </servlet-mapping>

过滤器和拦截器的区别:总体区别:

1)拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2)拦截器不依赖与servlet容器,过滤器依赖于servlet容器。

3)拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用(例如字节编码过滤器就是作用在所有文件上)。

4)拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

5)在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

6)拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

拦截器可以获取ioc中的service bean实现业务逻辑。

3 时间转换器

普通的时间类获取的结果是现在到1970年1月1号的时间毫秒数,不方便观看,可以通过时间转换器转换为我们想要的格式,有两种方法:

1)在时间类型的属性上加注解

加注解@JsonFormat(partten="yyyy-MM-dd")

实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
//    在返回JSON数据时,返回的是yyyy-MM-dd类型的,如果不加,将返回的是现在到1970年的毫秒数
//    除此之外也可以在springmvc中使用全局的时间注解配置,
//    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
​
    public User(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
}
​
测试类:
    @GetMapping("getAllUserData")
    public List<User> getAllUserData(){
        List<User> list = new ArrayList<>();
        User user1 = new User(1,"测试1","123",new Date());
        User user2 = new User(2,"测试2","123",new Date());
        User user3 = new User(3,"测试3","123",new Date());
        User user4 = new User(4,"测试4","123",new Date());
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);
        return list;
    }
最后得到的结果就是 2022-10-13这种类型

2) 在spring.xml文件中进行全局配置:注解驱动中配置

    <!--注解驱动-->
    <mvc:annotation-driven >
        <!-- 全局配置时间转换器 -->
        <mvc:message-converters>
            <!-- jackson  2.5.x -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                        <property name="dateFormat">
                            <bean class="java.text.SimpleDateFormat">
                                <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"></constructor-arg>
                            </bean>
                        </property>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

4 全局异常处理

异常时,默认的系统会报出一堆异常信息,这里可以通过对异常处理,使异常发生时只打印我们自定义的信息:

//由spring容器来管理,并将其标记为一个异常处理组件,这里标记完之后,也需要在配置文件中扫描该注解所在的包
@ControllerAdvice
public class ExceptionMethod {
​
//    这里需要标明需要对什么样的异常进行处理,这里使用的案例是UserController里面的getAllUserData方法
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public ResultMessage errorTest(Exception exception){
//        返回的结果必须是LayData类型的JSON数据,所以在下面定义了一个Result类,还需要在上面标明@ResponseBody
//        在这里将异常的信息进行返回,如果打印全部的异常信息,那么就是用Result,如果只打印部分信息,这里可以使用ResultMessage
//        这里返回的结果类型是不同的,
//        return new Result(exception);
        return new ResultMessage(exception.getMessage());
    }
}
​
​
@Data
@AllArgsConstructor
@NoArgsConstructor
class Result{
    private Integer code = 1;
    private String msg = "失败";
    private Exception exception;
​
    public Result(Exception exception) {
        this.exception = exception;
    }
}
​
@Data
@AllArgsConstructor
@NoArgsConstructor
class ResultMessage{
    private Integer code = 1;
    private String msg = "失败";
    private String  exceptionmsg;
​
    public ResultMessage(String exceptionmsg) {
        this.exceptionmsg = exceptionmsg;
    }
}

再次注意:记得把异常处理类所在的包让springmvc.xml扫描

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值