SpringMVC之JSON数据返回异常处理机制

news2024/11/28 23:40:54

目录

前言

一、JSON数据返回

1.导入依赖

2.配置spring-mvc.xml

3.使用@ResponseBody注解

4.Jackson

4.1.介绍

4.2.常用注解

二、异常处理机制

1.为什么要全局异常处理

2.异常处理思路

3.SpringMVC异常分类

4.综合案例

4.1.异常处理方式一

4.2.异常处理方式二

4.3异常处理方式三

5.响应封装类


前言

        Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过一套注解,我们可以快速的搭建一个Web应用。在本文中,我们将重点介绍如何在Spring MVC中返回JSON数据以及如何处理异常。

一、JSON数据返回

1.导入依赖

为了使@ResponseBody注解生效,我们需要配置一个Jackson消息转换器,用于将Java对象序列化为JSON字符串。需要在pom.xml文件中添加Jackson依赖:

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

2.配置spring-mvc.xml

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
        	<ref bean="mappingJackson2HttpMessageConverter"/>
        </list>
    </property>
</bean>
<bean id="mappingJackson2HttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    <!--处理中文乱码以及避免IE执行AJAX时,返回JSON出现下载文件-->
    <property name="supportedMediaTypes">
        <list>
            <value>text/html;charset=UTF-8</value>
            <value>text/json;charset=UTF-8</value>
            <value>application/json;charset=UTF-8</value>
        </list>
    </property>
</bean>

3.使用@ResponseBody注解

        在SpringMVC中,我们可以使用@ResponseBody注解将Controller方法的返回值直接转换为JSON格式。这样,当客户端请求该方法时,将会收到一个JSON格式的响应。

package com.ctb.controller;

import com.ctb.biz.UserBiz;
import com.ctb.model.User;
import com.ctb.utils.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Controller
@RequestMapping("/user/json")
public class JsonController {
    @Autowired
    private UserBiz userBiz;

    /**
     * 返回List<T> JSON数组
     * @param req
     * @param user
     * @return
     */
    @ResponseBody
    @RequestMapping("/list")
    public List<User> list(HttpServletRequest req, User user){
        PageBean pageBean = new PageBean();
        pageBean.setRequest(req);
        List<User> lst = this.userBiz.listPager(user, pageBean);
        System.out.println(1 / 0);
        return lst;
    }

    /**
     * 返回T JSON对象
     * @param req
     * @param user
     * @return
     */
    @ResponseBody
    @RequestMapping("/load")
    public User load(HttpServletRequest req, User user){
        if(user.getId() != null){
            List<User> lst = this.userBiz.listPager(user, null);
            return lst.get(0);
        }
        return null;
    }


    /**
     * 返回List<Map> JSON数组
     * @param req
     * @param user
     * @return
     */
    @ResponseBody
    @RequestMapping("/mapList")
    public List<Map> mapList(HttpServletRequest req, User user){
        PageBean pageBean = new PageBean();
        pageBean.setRequest(req);
        List<Map> lst = this.userBiz.mapListPager(user, pageBean);
        return lst;
    }

    /**
     * 返回Map JSON对象
     * @param req
     * @param user
     * @return
     */
    @ResponseBody
    @RequestMapping("/mapLoad")
    public Map mapLoad(HttpServletRequest req, User user){
        if(user.getId() != null){
            List<Map> lst = this.userBiz.mapListPager(user, null);
            return lst.get(0);
        }
        return null;
    }

//混合
    @ResponseBody
    @RequestMapping("/all")
    public Map all(HttpServletRequest req, User user){
        PageBean pageBean = new PageBean();
        pageBean.setRequest(req);
        List<User> lst = this.userBiz.listPager(user, pageBean);
        Map map = new HashMap();
        map.put("lst",lst);
        map.put("pageBean",pageBean);
        return map;
    }

    @ResponseBody//
    @RequestMapping("/jsonStr")
    public String jsonStr(HttpServletRequest req, User user){
       
        return "userEdit";
    }


}

注意:在使用此注解之后不会再走视图解析器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。分别为对象,数组,对象数组(混合)

 以下是部分方法运行结果

4.Jackson

4.1.介绍

Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。Jackson所依赖的jar包较少,简单易用并且性能也要相对高些,并且Jackson社区相对比较活跃,更新速度也比较快。

特点

  • 容易使用,提供了高层次外观,简化常用的用例。

  • 无需创建映射,API提供了默认的映射大部分对象序列化。

  • 性能高,快速,低内存占用

  • 创建干净的json

  • 不依赖其他库

  • 代码开源

4.2.常用注解
注解说明
@JsonIgnore作用在字段或方法上,用来完全忽略被注解的字段和方法对应的属性
@JsonProperty作用在字段或方法上,用来对属性的序列化/反序列化,可以用来避免遗漏属性,同时提供对属性名称重命名
@JsonIgnoreProperties作用在类上,用来说明有些属性在序列化/反序列化时需要忽略掉
@JsonUnwrapped作用在属性字段或方法上,用来将子JSON对象的属性添加到封闭的JSON对象
@JsonFormat指定序列化日期/时间值时的格式

二、异常处理机制

1.为什么要全局异常处理

我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

2.异常处理思路

系统的dao、service、controller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

3.SpringMVC异常分类

  • 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;

  • 实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器;

  • 使用@ControllerAdvice + @ExceptionHandler

4.综合案例

4.1.异常处理方式一

SpringMVC中自带了一个异常处理器叫SimpleMappingExceptionResolver,该处理器实现了HandlerExceptionResolver 接口,全局异常处理器都需要实现该接口。

<!-- springmvc提供的简单异常处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!-- 定义默认的异常处理页面 -->
    <property name="defaultErrorView" value="error"/>
    <!-- 定义异常处理页面用来获取异常信息的变量名,也可不定义,默认名为exception --> 
    <property name="exceptionAttribute" value="ex"/>
    <!-- 定义需要特殊处理的异常,这是重要点 --> 
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.RuntimeException">error</prop>
        </props>
    	<!-- 还可以定义其他的自定义异常 -->
    </property>
</bean> 

注:页面跳转由SpringMVC来接管了,所以此处的定义默认的异常处理页面都应该配置成逻辑视图名。  

前端页面


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>错误界面</title>
</head>
<body>
错误信息界面。。。。。。
${ex}
</body>
</html>

4.2.异常处理方式二
  •  创建一个名为GlobalException的自定义异常类

这是一个名为GlobalException的Java类,它继承自RuntimeExceptionRuntimeException是Java中所有未检查异常的父类。这个类提供了多种构造方法,用于创建不同类型的异常对象。

package com.ctb.exception;

public class GlobalException extends RuntimeException {
    // 默认构造方法,创建一个不带任何消息和原因的运行时异常
    public GlobalException() {
    }

    // 带一个字符串消息的构造方法,创建一个带有指定消息的运行时异常
    public GlobalException(String message) {
        super(message);
    }

    // 带一个字符串消息和一个原因的构造方法,创建一个带有指定消息和原因的运行时异常
    public GlobalException(String message, Throwable cause) {
        super(message, cause);
    }

    // 带一个原因的构造方法,创建一个带有指定原因的运行时异常
    public GlobalException(Throwable cause) {
        super(cause);
    }

    // 带一个字符串消息、一个原因、一个标志位(是否抑制异常)和一个标志位(是否可写栈轨迹)的构造方法,创建一个带有指定消息、原因、抑制标志位和可写栈轨迹的运行时异常
    public GlobalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  • 创建一个名为GlobalExceptionHandler的类,并实现了HandlerExceptionResolver接口。
package com.ctb.component;

import com.ctb.exception.GlobalException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class GlobalExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         Object o, Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");//error.jsp
        if (e instanceof GlobalException){
            GlobalException globalException = (GlobalException) e;
            mv.addObject("ex",globalException.getMessage());
            mv.addObject("msg","全局异常....");
        }else if (e instanceof RuntimeException){
            RuntimeException runtimeException = (RuntimeException) e;
            mv.addObject("ex",runtimeException.getMessage());
            mv.addObject("msg","运行时异常....");
        }
        return mv;
    }
}

它实现了HandlerExceptionResolver接口(异常处理解析器)。当应用程序中抛出异常时,这个处理器会被调用,返回一个ModelAndView对象,用于渲染错误页面。

代码解析:

  1. @Component注解表示这个类是一个Spring组件,Spring会自动扫描并管理这个类的实例。

  2. GlobalExceptionHandler类实现了HandlerExceptionResolver接口,该接口只有一个方法resolveException,Spring在处理异常时会调用这个方法。

  3. resolveException方法接收四个参数,分别是HttpServletRequest、HttpServletResponse、Object和Exception。HttpServletRequest和HttpServletResponse是HTTP请求和响应的对象,Object是当前处理的请求或响应的对象,Exception是发生的异常。

  4. resolveException方法中,首先创建了一个ModelAndView对象mv,然后设置了视图名称为"error",即错误页面。

  5. 接着判断异常的类型,如果是GlobalException类型,则获取其消息并添加到mv中,同时添加一条"全局异常...."的消息。如果是RuntimeException类型,则获取其消息并添加到mv中,同时添加一条"运行时异常...."的消息。

  6. 最后返回mv对象,Spring会根据这个对象渲染错误页面。

部分方法测试 

4.3异常处理方式三
  • ControllerAdvice:这是一个全局的异常处理器,可以捕获所有控制器中抛出的异常。通常我们会使用 @ControllerAdvice 注解来标记一个类为 ControllerAdvice,然后在该类中定义异常处理方法。

  • @ExceptionHandler:这是一个用于处理方法参数中抛出的指定类型的异常的注解。我们可以在方法上使用 @ExceptionHandler 注解来指定要处理的异常类型,以及处理方法的名称。

package com.ctb.component;

import com.ctb.exception.GlobalException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionResolver {

//    跳转错误页面
//    @ExceptionHandler
//    public ModelAndView handler(Exception e){
//        ModelAndView mv = new ModelAndView();
//        mv.setViewName("error");
//        if (e instanceof GlobalException){
//            GlobalException globalException = (GlobalException) e;
//            mv.addObject("ex",globalException.getMessage());
//            mv.addObject("msg","全局异常....");
//        }else if (e instanceof RuntimeException){
//            RuntimeException runtimeException = (RuntimeException) e;
//            mv.addObject("ex",runtimeException.getMessage());
//            mv.addObject("msg","运行时异常....");
//        }
//        return mv;
//    }

// 返回错误json数据
    @ResponseBody
    @ExceptionHandler
    public Map handler(Exception e){
        Map map = new HashMap();
        if (e instanceof GlobalException){
            GlobalException globalException = (GlobalException) e;
            map.put("ex",globalException.getMessage());
            map.put("msg","全局异常....");
        }else if (e instanceof RuntimeException){
            RuntimeException runtimeException = (RuntimeException) e;
            map.put("ex",runtimeException.getMessage());
            map.put("msg","运行时异常....");
        }else {
            map.put("ex",e.getMessage());
            map.put("msg","其它异常....");
        }
        return map;
    }
}

代码解析

handler(Exception e)方法:

  • 使用@ResponseBody注解,表示将返回的对象作为响应体发送给客户端。
  • 使用@ExceptionHandler注解,表示该方法用于处理控制器中抛出的异常。
  • 创建一个HashMap对象,用于存储异常信息。
  • 判断异常类型,如果是GlobalException,则将异常信息添加到map中,并设置提示信息为"全局异常....";
  • 如果异常类型是RuntimeException,则将异常信息添加到map中,并设置提示信息为"运行时异常....";
  • 其他类型的异常,将异常信息添加到map中,并设置提示信息为"其它异常....";
  • 返回map对象。

部分方法测试 

 

 

5.响应封装类

  • 创建自定义异常类BusinessException

BusinessException自定义异常类将继承RuntimeException异常,该异常类用于处理在程序代码运行过程所产生的运行时业务异常信息。

  • 创建响应枚举类JsonResponseStatus

JsonResponseStatus响应枚举类用于自定义错误码。

  • 创建响应封装类JsonResponseBody

JsonResponseBody响应封装类用于以JSON的形式统一输出错误信息。

// 响应封装类
    @ResponseBody
    @ExceptionHandler
    public R handler(Exception e){
        if (e instanceof GlobalException){
            GlobalException globalException = (GlobalException) e;
            return R.ok(666,"全局异常....",globalException.getMessage());
        }else if (e instanceof RuntimeException){
            RuntimeException runtimeException = (RuntimeException) e;
            return R.ok(666,"运行异常....",runtimeException.getMessage());
        }else {
            return R.ok(666,"其它异常....",e.getMessage());
        }
    }

根据传入的异常对象进行类型判断,并返回相应的响应结果。

部分方法测试

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1008296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《PostgreSQL事务管理深入解析》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

分类预测 | Matlab实现GRNN-Adaboost多特征分类预测

分类预测 | Matlab实现GRNN-Adaboost多特征分类预测 目录 分类预测 | Matlab实现GRNN-Adaboost多特征分类预测效果一览基本介绍研究内容程序设计参考资料 效果一览 基本介绍 1.Matlab实现GRNN-Adaboost多特征分类预测&#xff08;Matlab完整程序和数据&#xff09; 2.多特征输入…

【Redis】Redis作为缓存

【Redis】Redis常见面试题&#xff08;2&#xff09; 文章目录 【Redis】Redis常见面试题&#xff08;2&#xff09;1. 缓存2. Redis作为缓存2.1 缓存雪崩2.2 缓存穿透2.3 缓存击穿2.4 缓存雪崩、缓存穿透、缓存击穿的区别2.5 缓存预热2.6 如何保证缓存和MySQL双写一致 【Redis…

阿里云产品试用系列-云服务器 ECS

阿里云为个人开发者或者企业用户提供云产品的免费试用&#xff0c;本文主要描述ECS云服务器试用体验。 如上所示&#xff0c;在阿里云官方网站中&#xff0c;可使用云服务器ECS构建应用服务。 如上所示&#xff0c;在阿里云控制台中&#xff0c;可以显示成功定制免费使用阿里云…

锂离子电池和电池组安全使用指南

声明 本文是学习GB-T 42729-2023 锂离子电池和电池组安全使用指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件提供了锂离子电池和电池组使用过程中的安全指导和建议&#xff0c;给出了锂离子电池和电池组制 造厂商向用户提供可能…

【ShardingSphere】单实例模式创建分片表、广播表、单表

文章目录 1、简介2、ShardingSphere-Proxy 默认行为2.1 安装2.2 启动 3、设计测试环境3.1 架构3.2 数据映射关系 4、 准备工作4.1 配置 server.yaml4.2 配置 config-logic_db.yaml4.3 创建数据源所配置的物理库4.3.1 ds_0、ds_14.3.2 ds_2 4.4 启动4.5 &#xff08;可选&#x…

4基于pytorch的蚁群算法求解TSP(旅行商问题),访问一座城市并回到最初位置的最佳路径,解决组合中的NP问题。程序已调通,替换自己的数据可以直接运行。

基于pytorch的蚁群算法求解TSP(旅行商问题)&#xff0c;访问一座城市并回到最初位置的最佳路径&#xff0c;解决组合中的NP问题。程序已调通&#xff0c;替换自己的数据可以直接运行。 4pytorchTSP路径优化 (xiaohongs4pytorchTSP路径优化 (xiaohongshu.com)4pytorchTSP路径优化…

ARM如何利用PMU的Cycle Counter(时钟周期)来计算出CPU的时钟频率

本章将学习如何利用ARM PMU的Cycle Counter&#xff0c;来计算出CPU的时钟周期&#xff0c;从而计算出CPU的时钟频率。在介绍计算方法前&#xff0c;有必要先介绍下什么是时钟周期、机器周期以及指令周期。 如何计算出CPU的时钟频率 一&#xff0c;时钟周期&#xff0c;机器周…

AP5191 DC-DC降压恒流IC LED智能控制电源芯片 线性 PWM调光

产品描述 AP5191是一款PWM工作模式,高效率、外围简单、内置功率MOS管&#xff0c;适用于4.5-150V输入的高精度降压LED恒流驱动芯片。输出最大功率150W&#xff0c;最大电流6A。AP5191可实现线性调光和PWM调光&#xff0c;线性调光脚有效电压范围0.55-2.6V.AP5191 工作频率可以…

86 # express 基本实现

koa 和 express 的区别 koa 内部原理使用 es6 来编写的&#xff08;promise async await&#xff09;&#xff0c;express 是使用 es5 来编写的&#xff0c;内部是基于回调函数来实现express 内置了很多中间件&#xff08;功能会比 koa 强大一些&#xff0c;内部集成了路由&a…

【应用笔记】Sub-1G系列产品CW32W031单片机CAD应用参考

一、功能介绍 CW32W031 的射频部分支持 CAD 中断。从 Deepsleep 进入 STB3&#xff0c;开启 CAD 功能并进入 RX 模式后&#xff0c; CW32W031 会检测信道中是否会有 ChirpIOT ™信号 , 如果存在将 CAD-IRQ 置高&#xff0c;MCU 内核可以通过一定的时间来检测 CAD-IRQ 信号是否…

DenseNet网络详解及Pytorch实现

DenseNet网络详解及Pytorch实现 DenseNet网络简介 DenseNet&#xff08;Densely Connected Convolutional Networks&#xff09;是由Gao Huang等研究人员于2017年提出的一种深度神经网络架构。DenseNet的主要思想是在网络的每一层之间建立密集的连接&#xff0c;这种密集连接…

[NLP] LLM---扩充词表LLama2-构建中文tokenization

使用SentencePiece的除了从0开始训练大模型的土豪和大公司外&#xff0c;大部分应该都是使用其为当前开源的大模型扩充词表&#xff0c;比如为LLama扩充通用中文词表&#xff08;通用中文词表&#xff0c;或者 垂直领域词表&#xff09;。那这部分工作有没有意义呢&#xff1f;…

Flutter 中的单元测试:从工作流基础到复杂场景

对 Flutter 的兴趣空前高涨——而且早就应该出现了。 Google 的开源 SDK 与 Android、iOS、macOS、Web、Windows 和 Linux 兼容。单个 Flutter 代码库支持所有这些。单元测试有助于交付一致且可靠的 Flutter 应用程序&#xff0c;通过在组装之前先发制人地提高代码质量来确保不…

【多尺度增强网络:超分】

Remote Sensing Image Super-Resolution via Multiscale Enhancement Network &#xff08;基于多尺度增强网络的遥感图像超分辨率&#xff09; 近年来&#xff0c;遥感图像因其特殊的价值而引起了人们的广泛关注。然而&#xff0c;卫星遥感图像通常是低分辨率的&#xff0c;…

案例实践丨基于SkyWalking全链路监控的微服务系统性能调优实践篇

1背景 随着开源社区和云计算的快速推进&#xff0c;云原生微服务作为新型应用系统的核心架构&#xff0c;得到了越来越广泛的应用。根据Gartner对微服务的定义&#xff1a;“微服务是范围狭窄、封装紧密、松散耦合、可独立部署且可独立伸缩的应用程序组件。” 微服务之父&…

markdown学习笔记

markdown学习笔记 1.文字&#xff08;依靠HTML&#xff09; 1.1文字缩进-空格转义符 单字符空&#xff1a;&emsp; 半字符空&#xff1a;&ensp;1.2文字对齐 「居中&#xff1a;」<center> 居中 </center> or <p align"center"> 居中 …

Java线程池中哪些事??

需要提前把线程准备好&#xff01;&#xff01;创建线程不是直接从系统申请&#xff0c;而是从池子里拿&#xff01; 等到线程不用了&#xff0c;也是还给池子&#xff01;&#xff01; 池子的目的是为了提高效率 线程的创建虽然比进程轻量&#xff0c;但是在频繁创建的情况下…

【计算机网络】图解应用层协议

图解应用层协议 1.应用层2.远程登录2.1 Telnet2.2 SSH 3.文件传输3.1 FTP3.2 TFTP 4.电子邮件4.1 通信架构4.2 邮件地址4.3 SMTP 协议4.4 POP3 协议4.5 IMAP 协议 5.WWW5.1 URI5.2 HTML5.3 HTTP 6.网络管理应用6.1 DHCP 协议6.2 DNS 协议 1.应用层 我们前面介绍过 TCP / IP 模…

【深度学习】 Python 和 NumPy 系列教程(十一):NumPy详解:3、数组数学(元素、数组、矩阵级别的各种运算)

目录 一、前言 二、实验环境 三、NumPy 0、多维数组对象&#xff08;ndarray&#xff09; 多维数组的属性 1、创建数组 2、数组操作 3、数组数学 1. 元素级别 a. 直接运算 b. 加法&#xff1a;np.add()函数 c. 减法&#xff1a;np.subtract()函数 d. 乘法&#xf…