【SpringMVC02】返回值ModelAndView、ajax请求返回json、全局异常处理、拦截器

控制器方法返回值

ModelAndView

参照目录:“SpringMVC入门–使用” 中的代码

String

相当于ModelAndView中的View部分。

    @RequestMapping(value = "/returnString.do")
    public String receiveObject(){
        return "other";
    }

如果还想接受参数,那就使用ModelAndView,或者在形参中加入HttpRequest,手动接受即可

    @RequestMapping(value = "/returnString.do")
    public String receiveObject(HttpServletRequest request,
                                String name,
                                Integer age){
        request.setAttribute("name", name);
        request.setAttribute("age", age);
        return "other";
    }

另外,如果要返回完整路径,则不能配置视图解析器,否则会报错

void

不能表示数据也不能表示视图,在处理ajax请求时,可以使用void返回值,通过HttpServletRequest输出信息,响应ajax请求。

1、首先,在前端页面借一个按钮,发起ajax请求

<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
    $(function(){
        $("button").click(function(){
            // alert("btn")
            $.ajax({
                url:"test/ajaxRequest.do",
                data:{
                    name:"zhangsan",
                    age:12
                },
                type:"post",
                dataType:"json",
                success:function (resp) {
                    alert(resp.name
                }
            });
        });
    });
</script>
    <button id="btn">发起ajax</button>
</body>

2、编写控制器方法代码

@RequestMapping(value = "/ajaxRequest.do")
public void ajaxRequest(HttpServletResponse response,
                        String name,
                        Integer age) throws IOException {
    //这里假设service已经对数据进行处理,返回了一个Student
    Student student = new Student();
    student.setName(name);
    student.setAge(age);
    String json = "";
    if (student != null){
        ObjectMapper objectMapper = new ObjectMapper();
        json = objectMapper.writeValueAsString(student);
    }
    //响应
    response.setContentType("application/json;charset=utf-8");
    PrintWriter writer = response.getWriter();
    writer.println(json);
    writer.flush();
    writer.close();
}

控制器处理ajax请求,并返回json数据的过程,会发现有一部分是重复的工作,每个方法中都要这样写:

1、java对象转换成json字符串;2、通过response输出json

因此,可以由框架来实现:即最后一种返回值:Object

Object

可以是String、Integer,也可以是List、Map等。返回的数据不是作为逻辑视图出现,而是作为直接在页面上显示的数据出现。需要使用@ResponseBody注解,将转换后的json数据放入响应体中

实现步骤:

1、加入依赖,springMVC默认使用的是jackson,处理json数据

2、在springMVC配置文件中加入注解驱动<mvc:annotataion-driven>

​ 这一步相当于,将java对象转换成json数据

3、在控制器方法上加上@ResponseBody注解

​ 这一步相当于,将 json 输出到前端

1、加入依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.0</version>
</dependency>

2、前端代码

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
    $(function(){
        $("#btn2").click(function(){
            $.ajax({
                url:"test/returnStudentJson.do",
                data:{
                    name:"lisi",
                    age:12
                },
                type:"post",
                dataType:"json",
                success:function (resp) {
                    alert(resp.name)
                }
            });
        });
    });
</script>
</head>
<body>
    <button id="btn2">springmvc内置转换json</button>
</body>

3、控制器代码

@ResponseBody
@RequestMapping(value = "/returnStudentJson.do")
public Student returnStudentJson(String name,Integer age){
    Student student = new Student();
    student.setName(name);
    student.setAge(age);
    return student;
}

4、springmvc配置文件中加入注解驱动

<mvc:annotation-driven/>

返回String字符串数据,非视图

/*这里使用@ResponseBody与返回视图的区分
* produces属性指定返回的ContentType
* */
@ResponseBody
@RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
public String returnString(String name){
    return "返回的字符串";
}

静态资源处理

以上的代码全部都是基于<servlet-mapping>中的<url-pattern>.do的情况,我们还有另外一种配置方法:" / "*

这就意味着所有的页面、资源都要交给框架处理,而除了经过注解配置的controller方法以外,框架没有处理一些静态资源如图片、html等未经配置的资源,这些资源一开始都是交由tomcat处理的。要解决这种问题,需要:

使用<mvc:default-servlet-handler/>

    <mvc:annotation-driven/>

    <!--
        第一种处理静态资源的方式:
        原理:加入此标签后,框架会创建控制器对象DefaultServletHttpRequestHandle(类似自己创建的Controller类)
        此对象可以接受到的请求转发给tomcat的DefaultServlet
        同时也要加入注解驱动标签<mvc:annotation-driven/>,否则所有的请求都会被转发给tomcat,自己配置的也会。
    -->
    <mvc:default-servlet-handler/>

使用<mvc:resources />

在Spring3.0后,spring定义了专门用于处理静态资源访问请求的处理器:ResourceHttpRequestHandle。

并且添加了<mvc:resources />标签专门用于解决静态资源无法访问的问题,此种方式不依赖tomcat服务器。

<!--
        mapping:表示访问静态资源的uri地址,使用通配符**
        location:静态资源在你项目中的目录位置
         同时也要加入注解驱动标签<mvc:annotation-driven/>
    -->
    <mvc:resources mapping="/images/**" location="/images/"/>

转发重定向

返回值ModelAndBView

转发

    @RequestMapping(value = "/testForward.do")
    public ModelAndView testForward(String name, Integer age){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name", name);
        modelAndView.addObject("age", age);
        //forward:完整路径(不和视图解析器一起使用)
        modelAndView.setViewName("forward:/WEB-INF/jsp/test.jsp");
        return modelAndView;
    }

重定向

重定向无法访问WEB-INF中的页面

/*框架会把model中的简单类型数据,转为string使用,
作为重定向页面的get请求参数使用,目的是在重定向的两次请求之间传递数据
因为是两次不同的请求,两个不同的request作用域,因此要取数据的话需要:
${param.name}相当于<%=request.getParameter("name")*/
@RequestMapping(value = "/testRedirect.do")
public ModelAndView testRedirect(String name, Integer age){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("name", name);
    modelAndView.addObject("age", age);
    modelAndView.setViewName("redirect:/test.jsp");
    return modelAndView;
}

异常处理

springMVC使用的是统一、全局的异常处理。把controller所有异常集中处理,采用的是AOP的思想。把业务逻辑代码和异常处理代码解耦合。

需要这两个注解:@ExceptionHandle、@ControllerAdvice

实现步骤:

  1. 自定义一个异常类和两个子类
  2. 创建一个普通类,作为全局异常处理类
    1. 在类的上方加入@ControllerAdvice
    2. 在自定义方法中加入@ExceptionHandle
  3. 创建处理异常的视图页面
  4. springMVC的配置文件
    1. 组件扫描器:@controller
    2. 组件扫描器:@ControllerAdvice
    3. 注解驱动

自定义异常:

public class MyUserException extends Exception{
    public MyUserException() {
        super();
    }

    public MyUserException(String message) {
        super(message);
    }
}
===================================================================================================
public class NameException extends MyUserException {
    public NameException() {
        super();
    }

    public NameException(String message) {
        super(message);
    }
}

控制器方法:

    @RequestMapping(value = "/testException.do")
    public ModelAndView testException(String name, Integer age) throws MyUserException {
        ModelAndView modelAndView = new ModelAndView();
        if (!"zhangsan".equals(name)){
            throw new NameException("姓名不正确");
        }
        modelAndView.addObject("name", name);
        modelAndView.addObject("age", age);
        modelAndView.setViewName("forward:/WEB-INF/jsp/test.jsp");
        return modelAndView;
    }

异常处理类:

/*@ControllerAdvice控制器增强,给控制器增加功能(异常处理)*/
@ControllerAdvice
public class GlobalExceptionHandle {
    /*处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView、
    * String、void等返回值
    * 形参:Exception e表示Controller类中抛出的异常对象
    *
    * @ExceptionHandler:
    * 表示异常类型,当此类型异常发生时由此方法处理
    * */
    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameExcpetion(Exception e){
        /*异常处理流程
        * 1、需要把异常记录下来,记录到数据库、日志等。
        *   记录异常发生的时间、方法、错误内容
        * 2、发送通知,把异常信息通过邮件、信息发送给相关人员
        * 3、给用户提示
        * */
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "姓名必须是“zhangsan”。");
        modelAndView.addObject("ex" , e);
        modelAndView.setViewName("nameError");
        return modelAndView;
    }
}

springMVC组件扫描器

<context:component-scan base-package="com.wm.handle"/>

其他异常:

除NameException以外的所有异常都会经过此方法处理

    /*处理其他异常*/
    @ExceptionHandler
    public ModelAndView defaultException(Exception e){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", "信息异常!");
        modelAndView.addObject("ex" , e);
        modelAndView.setViewName("defaultError");
        return modelAndView;
    }

拦截器

拦截器需要实现HandlerInterceptor接口

拦截器和过滤器类似,但过滤器主要用于过滤请求:设置编码字符集等工作

拦截器是拦截用户请求做请求判断处理。

拦截器是全局的,可以对多个Controller做判断,一个项目可以有0个或多个拦截器

常用于:用户登录处理、权限检查、记录日志

实现步骤:

1、定义类实现HandlerInterceptor接口

2、在springmvc配置文件中声明拦截器

拦截器执行时间:

1、在请求处理之前,也就是controller执行之前

2、在控制器方法执行后

3、在请求处理完之后

拦截器代码:

public class MyInterceptor implements HandlerInterceptor {
    /*preHandle:预处理方法
    * 参数:
    * Object handler:被拦截的控制器对象
    * 返回值:
    *   true:请求通过了验证,可以执行控制器方法
    *   false:没通过
    * 特点:
    * 方法在控制器之前先执行的。
    * 在这个方法中可以获取请求的信息,验证是否符合要求
    *   如:验证用户是否登录、验证用户是否有权限访问某个url
    * 如果验证失败则拦截,验证成功才放行,此时才执行controller方法
    * */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("拦截器preHandle");
//        request.getRequestDispatcher("/WEB-INF/jsp/tips.jsp").forward(request,response);
        return true;
    }

    /*postHandle:后处理方法
    * 参数:
    * Object handler:被拦截的控制器对象
    * ModelAndView:处理器方法的返回值
    * 特点:
    *   在处理器方法之后执行。
    *   能够获取处理器方法的返回值ModelAndView,可以修改ModelAndView的值
    * 主要是对原来的执行结果做二次修正
    * */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器postHandle");
        modelAndView.addObject("date",new Date());
    }

    /*afterCompletion:最后执行的方法
    * 参数:
    * Object handler:被拦截的控制器对象
    * Exception ex:程序中发生的异常
    *特点:
    * 请求处理完成后执行的:即视图已经返回给用户了
    * 一般用于资源回收
    * */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("拦截器afterCompletion");
    }
}

springmvc配置文件注册拦截器:

<!--拦截器-->
<mvc:interceptors>
    <mvn:interceptor>
        <!--指定拦截的请求uri地址
            path:地址,可以使用通配符:**
            **:表示任意字符、文件、或多级目录和目录中的文件
            -->
        <mvn:mapping path="/student/**"/>
        <!--声明由哪个拦截器拦截-->
        <bean class="com.wm.handle.MyInterceptor"/>
    </mvn:interceptor>
</mvc:interceptors>

多个拦截器

以配置文件声明为顺序,最先拦截的最后出拦截,如下图所示

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值