构建健壮的Spring MVC应用:JSON响应与异常处理

简介: 构建健壮的Spring MVC应用:JSON响应与异常处理

1. 引言

探讨Spring MVC中关键的JSON数据返回和异常处理机制。

2. JSON

2.1 了解JSON数据格式


JSON(JavaScript Object Notation)作为一种数据交换格式具有许多特点和优势,这些特点使其成为广泛应用于Web和应用程序开发的理想选择。下面详细解释了JSON的特点和优势:

1. 轻量级和可读性


  • JSON是一种轻量级的文本格式,其数据结构以键-值对(key-value pairs)的形式表示,易于理解和阅读。
  • 与XML等其他数据格式相比,JSON更加简洁,不包含繁琐的标签和属性,使数据在传输和存储时更为紧凑。


2. 易于编写和解析


  • JSON数据的编写和解析在多种编程语言中都有成熟的支持和库,因此开发人员可以轻松地生成和解析JSON数据。
  • 多数现代编程语言都提供了内置的JSON解析器和生成器,使得操作JSON数据变得非常简单。


3. 自描述性


  • JSON数据包含字段名和相应的值,使得数据的结构和含义变得明确。
  • 数据结构本身包含在数据中,不需要额外的元数据或模式定义。



4. 支持多种数据类型

  • JSON支持多种基本数据类型,包括字符串、数字、布尔值、数组和对象(嵌套的键-值对结构)。
  • 这种灵活性允许开发人员表示各种复杂的数据结构。


5. 平台无关性

  • JSON是一种独立于平台的数据格式,可在各种操作系统和编程语言之间自由交换。
  • 这种特性使得不同技术栈的应用程序能够轻松地共享和解释JSON数据。


6. 易于集成

  • JSON适用于Web服务、API和数据交换,因此它是构建分布式系统和跨平台应用程序的理想选择。
  • 多数Web浏览器都原生支持JSON,使其成为前后端通信的常用数据格式。



7. 社区支持和标准化

  • JSON已成为Web应用程序中的事实标准,得到了广泛的社区支持。
  • 它的标准规范由RFC 8259定义,这进一步巩固了其在数据交换中的地位。


总的来说,JSON作为一种数据交换格式具有轻量级、可读性强、易于编写和解析、自描述、跨平台、灵活支持多种数据类型等优势。这些特点使得JSON在Web开发、API设计、数据交换以及分布式系统中都广泛应用,并且在不同领域的应用中表现出色。


2.2 Spring MVC中的JSON

导入依赖

<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> 


配置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>


使用@ResponseBody注解

package com.liao.controller;
import com.liao.biz.UserBiz;
import com.liao.model.User;
import com.liao.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;
    @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;
    }
    @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;
    }
    @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;
    }
    @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";
    }
}

3. 高效处理异常

3.1 异常处理的必要性


Web应用程序需要有效的异常处理机制,因为异常是在应用程序运行过程中不可避免的情况,可以发生各种错误和异常情况,包括但不限于以下原因:


运行时错误: 应用程序可能会遇到运行时错误,例如空指针异常、数据库连接失败、文件不存在等。这些错误通常无法在编译时预测,但需要在运行时进行处理。


外部输入不可控: Web应用程序通常受到来自外部用户或其他系统的输入。用户可能会提供不正确或恶意的输入数据,这可能导致应用程序出现异常。有效的异常处理可以防止这些异常影响应用程序的稳定性和安全性。


资源不足或不可用: 在运行过程中,应用程序可能会遇到资源不足的情况,如数据库连接池用尽、磁盘空间耗尽等。这些情况需要适当的异常处理以避免应用程序崩溃。


网络通信问题: Web应用程序通常需要与其他系统或服务进行通信,这可能会导致网络故障或超时。有效的异常处理可以帮助应用程序优雅地处理这些问题。


业务逻辑异常: 有时应用程序需要捕获和处理与业务逻辑相关的异常情况,例如用户试图执行无权限操作、购物车中的商品数量超出库存等。


以下是为什么需要有效的异常处理机制的一些理由:


稳定性: 有效的异常处理可以帮助应用程序保持稳定性,避免崩溃或不可预测的行为。它可以使应用程序在出现异常情况时恢复正常状态或提供适当的错误信息。


安全性: 适当的异常处理可以增强应用程序的安全性,防止攻击者利用异常情况来获得敏感信息或执行恶意操作。


用户友好性: 异常处理应该提供有意义的错误消息,以便最终用户能够理解问题并采取适当的措施。这有助于提供更好的用户体验。


日志和监控: 通过异常处理,应用程序可以记录异常情况,以便开发人员能够诊断和解决问题。此外,它还可以用于监控应用程序的运行状况。


总之,有效的异常处理机制是确保Web应用程序稳定、安全且用户友好的关键组成部分。通过捕获、处理和记录异常,开发人员可以更好地管理和维护应用程序。


3.2.SpringMVC异常分类


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

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

使用@ControllerAdvice + @ExceptionHandler

综合案例

异常处理方式一

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



spring-mvc.xml

<!-- 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> 

前端异常页面

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


a9cdd7c3d13349779fccacc3ac1302c8.png


异常处理方式二

创建一个名为GlobalException的自定义异常类

GlobalException

1.package com.liao.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

GlobalExceptionHandler实现HandlerExceptionResolver接口

package com.liao.component;
import com.liao.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;
    }
}


测试:

异常处理方式三

@ControllerAdvice + @ExceptionHandler

package com.liao.component;
import com.liao.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;
    }
}


目录
相关文章
|
3月前
|
人工智能 Java Nacos
基于 Spring AI Alibaba + Nacos 的分布式 Multi-Agent 构建指南
本文将针对 Spring AI Alibaba + Nacos 的分布式多智能体构建方案展开介绍,同时结合 Demo 说明快速开发方法与实际效果。
3053 68
|
5月前
|
JSON 人工智能 Java
基于Spring AI构建智能Text-to-SQL转换器:一个完整的MCP
Spring AI 更新结构化输出转换器,弃用旧版 Parser 类,引入与 Spring 框架对齐的 Converter 体系,提升命名规范与功能兼容性。新版本支持 JSON、XML 及 Java 对象转换,确保 LLM 输出结构化,便于下游应用处理。
|
5月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
978 3
|
4月前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
2428 58
|
3月前
|
缓存 监控 Java
《深入理解Spring》性能监控与优化——构建高性能应用的艺术
本文系统介绍了Spring生态下的性能监控与优化实践,涵盖监控体系构建、数据库调优、缓存策略、线程池配置及性能测试等内容,强调通过数据驱动、分层优化和持续迭代提升应用性能。
|
3月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
4月前
|
XML Java 测试技术
使用 Spring 的 @Import 和 @ImportResource 注解构建模块化应用程序
本文介绍了Spring框架中的两个重要注解`@Import`和`@ImportResource`,它们在模块化开发中起着关键作用。文章详细分析了这两个注解的功能、使用场景及最佳实践,帮助开发者构建更清晰、可维护和可扩展的Java应用程序。
273 0
|
消息中间件 存储 Java
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统
本文详细介绍了如何使用Spring Boot 3结合RabbitMQ构建高效可靠的聊天消息存储系统。通过引入消息队列,实现了聊天功能与消息存储的解耦,解决了高并发场景下直接写入数据库带来的性能瓶颈问题。文章首先分析了不同MQ产品的特点及适用场景,最终选择RabbitMQ作为解决方案,因其成熟稳定、灵活路由和易于集成等优势。接着,通过Docker快速部署RabbitMQ,并完成Spring Boot项目的配置与代码实现,包括生产者发送消息、消费者接收并处理消息等功能。最后,通过异步存储机制,既保证了消息的即时性,又实现了可靠持久化。
760 0
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统