JavaSpringMVC:响应封装REST异常处理

Posted ahcfl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSpringMVC:响应封装REST异常处理相关的知识,希望对你有一定的参考价值。

文章目录

问答:
	请求携带日期类型的数据如何接收?
    请求参数名与形参名不一致时如何接收参数?
    如何获取请求携带的cookie的值?
    如何处理post请求的乱码问题?
    SpringMVC生成响应的方式有哪些?
    SpringMVC生成响应时如何共享数据?
    @RequestBody和@ResponseBody的区别?
    静态资源过滤的三种方式?
    什么是SpringMVC的统一异常处理机制? 如何实现?
    文件上传前端三要素是什么?
    
编程:
	响应的多种方式实现
    响应的多种方式返回值实现
    ajax请求与响应实现
    文件上传
    RestFul风格的路径实现
    

一、响应与封装返回值

SpringMVC返回值的方式可以分为两大类: 
 1.同步请求的响应:
请求转发 或 重定向

2.异步请求的响应
异步指的是前端的请求的方式:ajax
ajax请求直接返回响应结果字符串

1、SpringMVC中响应的多种方式

pom.xml配置

 <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.8</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- tomcat7插件,运行命令: mvn tomcat7:run -DskipTests -->
            <!-- 配置Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <uriEncoding>UTF-8</uriEncoding>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
           version="3.0">

    <!--配置springmvc提供的中文乱码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <!-- 设置过滤器中的属性值 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
   <!--     <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>-->
    </filter>
    <!-- 过滤所有请求 -->
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--配置核心控制器(前端控制器/调度控制器/总控制器) servlet-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置springmvc资源的路径,dispatcherServlet初始化,就加载springmvc.xml资源-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--配置servlert加载时机-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--配置映射规则-->
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--拦截所有请求(除了jsp后缀请求外)-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

springmvc.xml

 <!--扫包加载bean资源-->
    <context:component-scan base-package="com.ahcfl"/>

    <!--配置视图解析器:将逻辑视图转换成物理视图-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--配置资源前缀-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--开启mvc注解驱动-->
    <!--
        开启注解驱动后,可以使用springmvc扩展的注解
           @DateTimeFormat
           @RequestBody
           @ResponseBody
           。。。。。
    -->
    <mvc:annotation-driven/>

    <!--使用springmvc提供的默认决绝方式-->
    <mvc:default-servlet-handler/>

【1】原生API与SpringMVC【实现请求转发】

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class Demo2Controller {

    /**
     * 请求转发与重定向的区别:
     *      请求转发是一次请求的延续
     *      请求转发可以共享Request对象
     *      请求转发是服务器内部行为,只能转发到服务器内部的资源上
     *      请求转发时地址栏地址不变
     *      请求转发是Request的行为
     *
     *      重定向,改变方向发送多次请求
     *      重定向不可以共享Request对象
     *      重定向可以跳转到任何路径上
     *      重定向时浏览器地址栏显示最后一次请求的路径
     *      重定向是Response对象的行为
     *
     * SpringMVC的响应:
     *      同步响应:
     *          请求转发: 一次请求的延续,浏览器地址栏地址不会发生改变
     *              原生API: HttpServletRequest
     *              forward:物理视图路径
     *              逻辑视图 + 视图解析器
     *          重定向:
     *              原生API: HttpServletResponse
     *              redirect:重定向的物理逻辑
     *
     *      以流的形式写回给浏览器
     *              原生API: HTTPServletResponse
     *              @ResponseBody + String
     *                  @RequestMapping(value = "/handler07",
     *                  produces = "text/html;charset=utf-8")
     */


    /**
     * 请求转发:
     *      原生API实现
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("/handler01")
    public void handler01(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("handler01方法执行了...");
        // 请求转发到 /pages/success.jsp
        request.getRequestDispatcher("/pages/success.jsp").forward(request,response);
    }

    /**
     * 请求转发:
     *      SpringMVC方式:
     *          forward:物理视图
     * @throws IOException
     */
    @RequestMapping("/handler02")
    public String handler02(){
        System.out.println("handler02方法执行了...");
        // forward:物理视图路径
        return "forward:/pages/success.jsp";
    }

    /**
     * 请求转发:
     *      SpringMVC方式:
     *          逻辑视图 + 视图解析器
     * @throws IOException
     */
    @RequestMapping("/handler03")
    public String handler03(){
        System.out.println("handler03方法执行了...");
        // forward:物理视图路径
        return "success";
    }
}

【2】原生API与SpringMVC【实现重定向】

    /**
     * 重定向-原生API
     * @return
     */
    @RequestMapping("/handler04")
    public void handler04(HttpServletResponse response) throws IOException {
        System.out.println("handler04方法执行了...");
        response.sendRedirect("/pages/success.jsp");
    }

    /**
     * 重定向
     *      SpringMVC方式:
     *          redirect:重定向的路径
     * @return
     */
    @RequestMapping("/handler05")
    public String handler05() {
        System.out.println("handler05方法执行了...");
        return "redirect:https://www.baidu.com";
    }

【3】原生API与SpringMVC 【以流的形式响应字符串】

    /**
     * 以流的形式写回字符串
     *      原生API: HttpServletResponse
     * @return
     */
    @RequestMapping("/handler06")
    public void handler06(HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        System.out.println("handler06方法执行了...");
        response.getWriter().print("原生API响应的数据...");
    }
    /**
     * mime常用类型:
     *          *.html  text/html
     *          *.js    text/javascript
     *          *.png   image/png
     *          *.json  application/json
     * 以流的形式写回字符串
     *      SpringMVC方式:
     *          @ResponseBody + String
     *  RequestMapping参数:
     *      produces: 设置响应参数的mime类型
     * @return
     */
    @RequestMapping(value = "/handler07",produces = "text/html;charset=utf-8")
    @ResponseBody
    public String handler07() {
        System.out.println("handler07方法执行了...");
        return "SpringMVC写回的字符串";
    }
}

了解几个常用的数据类型:

常用的Content-Type类型:
【text/html  :HTML格式】 
【text/plain :纯文本格式】      
text/xml   :XML格式

image/gif  :gif图片格式    
image/jpeg :jpg图片格式 
image/png  :png图片格式

application/xml     : XML数据格式
【application/json    : JSON数据格式】
application/pdf     : pdf格式  
application/msword  : Word文档格式
application/octet-stream : 二进制流数据(如文件下载)

【application/x-www-form-urlencoded : 
    <form encType="">中默认的encType,
    form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)】

【multipart/form-data : 表单上传文件】

2、响应时数据共享问题

请求转发:  数据都会存放到Request域中
重定向:    将共享的数据拼接在请求路径的后面
    
说明:
ModelAndViewModel是框架给我们准备好的,我们直接拿过来使用的即可,
我们称这些对象为【隐式对象】。

【1】使用request域对象封装响应结果

从http请求到服务器处理结束的整个过程中,多次请求转发过程中request域下的变量共享

**使用这种方式需要导入servlet的包 **
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.0.1</version>
</dependency>
public String demo1(HttpServletRequest request){
    request.setAttribute("user","admin");
    return "success";
}

【2】使用Model封装结果

public String demo2(Model model){
    model.addAttribute("user","admin");
    return "success";
}

【3】使用ModelAndView封装结果

public ModelAndView demo3(ModelAndView modelAndView){
    modelAndView.addObject("user","admin");
    modelAndView.setViewName("success");
    return modelAndView;
}

【4】代码演示

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>${msg}</h1>
</body>
</html>
【1】转发响应时共享数据

通过Request域,Model、ModelAndView都可实现;

package com.ahcfl.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/params")
public class Demo3Controller {
    /**
     * 请求转发:
     *      携带数据给目标资源 -- HttpServletRequest
     * @return
     */
    @RequestMapping("/test01")
    public String test01(HttpServletRequest request){
        System.out.println("test01方法执行了...");
        request.setAttribute("msg","如今的现在早已不是曾经说好的以后");
        return "success";
    }

    /**
     * 请求转发:
     *      SpringMVC携带共享的资源
     *      Model : model对象是SpringMVC内置对象,当前对象可以直接使用
     *          当我们向model中存放数据后,最终model中的数据会转存到Request域中
     * @return
     */
    @RequestMapping("/test02")
    public String test02(Model model){
        System.out.println("test01方法执行了...");
        model.addAttribute("msg","你若安好,便是晴天");
        return "success";
    }

    /**
     * 请求转发:
     *      SpringMVC携带共享的资源
     *      ModelAndView: 封装视图和转发共享的数据
     * @return
     */
    @RequestMapping("/test03")
    public ModelAndView test03(ModelAndView modelAndView){
        System.out.println("test01方法执行了...");
        // 封装转发携带的数据
        modelAndView.addObject("msg","情绪是智慧不够的产物!");
        // 封装视图
        modelAndView.setViewName("success");
        return modelAndView;
    }
}
【2】重定向时共享数据

数据存放到session域下,会占用服务器内存空间;【不可取】

重定向时,request域下的数据不能共享,

但是使用Model或者ModelAndView可以自动将数据以参数的方式拼接到请求路径中。

	/**
     * 重定向-共享数据:
     *      如果需要重定向,SpringMVC会自动将Model中的数据
     *      拼接到重定向的路径后面
     * @param model
     * @return
     */
    @RequestMapping("/test04")
    public String test04(Model model){
        System.out.println("test04方法执行了...");
        model.addAttribute("msg","你若安好,便是晴天");
        return "redirect:/pages/success.jsp";
    }

    @RequestMapping("/test05"以上是关于JavaSpringMVC:响应封装REST异常处理的主要内容,如果未能解决你的问题,请参考以下文章

无法在 SpringBoot 中使用 ControllerAdvice 返回 rest api 响应

73-DRF的封装:APIView类及五大模块

springboot统一响应实体封装+统一异常类管理

在 Django REST 中引发异常

SpringBoot:如何优雅地进行响应数据封装异常处理?

SpringBoot:如何优雅地进行响应数据封装异常处理?