前言
在上一期的博客中我们分享了有关SpringMVC中的JSR303和拦截器新知识的内容,希望给各位老铁的学习带来了帮助和增长了知识。今天我来继续给各位老铁带来SpringMVC新的武功秘籍——JSON和异常处理机制,一个是有关数据回显,一个是有关运行异常处理,让我们一起来领略一下吧。
一、秘籍一:JSON返回
1. JSON简介
1.1 什么是JSON返回
JSON返回是指在网络请求中,服务器返回的数据格式为JSON(JavaScript Object Notation)格式。JSON是一种轻量级的数据交换格式,常用于前后端数据传输和通信。在JSON返回中,服务器将数据以键值对的形式进行组织,通过键(key)和对应的值(value)来表示数据的结构和内容。客户端可以通过解析JSON数据,使用相应的键来获取对应的值,以便进行后续的处理和显示。JSON返回通常用于API接口的数据传输,能够灵活、高效地传递结构化数据。
1.2 JSON返回的用途
JSON返回的作用
用途 | 说明 |
数据传输 | 通过将数据以JSON格式返回给客户端,可以有效地传递结构化数据,方便客户端进行解析和处理。 |
API 接口 | API接口通过定义统一的数据格式(通常是JSON),使得不同平台和系统之间的数据交互变得更加简单和可靠。 |
数据存储 | JSON返回可以将数据以易读易解析的方式进行存储。很多应用程序会将数据以JSON格式存储在文件或数据库中,以便后续读取和使用。 |
前端渲染 | JSON返回使得前端开发者能够直接处理和展示后端传递的数据。 |
移动开发 | 后端通常会以JSON返回数据给客户端,让客户端进行数据解析和展示。这样可以实现前后端的分离,提高移动应用的性能和响应速度。 |
2. SpringMVC之JSON返回的运用
2.1 导入依赖
在pom.xml文件中添加一下代码
<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.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>
2.3 @ResponseBody注解使用
2.3.1 什么是@ResponseBody注解
@ResponseBody注解是一种用于标记方法或类的注解,常用于服务器端的Web开发中,作用是指示方法的返回值应作为响应的内容直接发送给客户端,而不是作为视图名称进行解析。它通常与Spring框架的@Controller或@RestController注解一起使用。
当一个方法使用@ResponseBody注解时,Spring框架会自动将方法返回的对象(通常是Java对象)转换为合适的数据格式,比如JSON、XML等,然后将其作为HTTP响应体发送给客户端。这种方式使得开发者能够更加方便地返回结构化数据给客户端,而无需手动进行数据转换和格式化。
@ResponseBody注解可以应用在控制器(Controller)中的方法上,也可以应用在整个类上,从而标记该类的所有方法都会将返回值作为响应内容发送给客户端。
注:
在使用此注解之后不会再走视图解析器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
2.3.2 测试工作的准备
编写测试所需的方法
ClazzMapper.xml
<select id="mapListPager" resultType="java.util.Map" parameterType="com.yx.model.Clazz" > select <include refid="Base_Column_List" /> from t_struts_class <where> <if test="cname != null"> and cname like concat('%',#{cname},'%') </if> </where> </select>
ClazzMapper.java、接口类及接口实现类代码
package com.yx.mapper; import com.yx.model.Clazz; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Map; @Repository public interface ClazzMapper { int deleteByPrimaryKey(Integer cid); int insert(Clazz record); int insertSelective(Clazz record); Clazz selectByPrimaryKey(Integer cid); int updateByPrimaryKeySelective(Clazz record); int updateByPrimaryKey(Clazz record); List<Clazz> ListPager(Clazz clazz); List<Map> mapListPager(Clazz clazz); } //===========================以上是ClazzMapper.java代码==================================== //===========================以下是ClazzBiz接口代码==================================== package com.yx.biz; import com.yx.model.Clazz; import com.yx.utils.PageBean; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:28 */ public interface ClazzBiz { int deleteByPrimaryKey(Integer cid); int insert(Clazz record); int insertSelective(Clazz record); Clazz selectByPrimaryKey(Integer cid); int updateByPrimaryKeySelective(Clazz record); int updateByPrimaryKey(Clazz record); List<Clazz> ListPager(Clazz clazz, PageBean pageBean); List<Map> mapListPager(Clazz clazz, PageBean pageBean); } //===========================以下是ClazzBizImpl接口实现类代码==================================== package com.yx.biz.Impl; import com.yx.biz.ClazzBiz; import com.yx.mapper.ClazzMapper; import com.yx.model.Clazz; import com.yx.utils.PageBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:47 */ @Service public class ClazzBizImpl implements ClazzBiz { @Autowired private ClazzMapper clazzMapper; @Override public int deleteByPrimaryKey(Integer cid) { return clazzMapper.deleteByPrimaryKey(cid); } @Override public int insert(Clazz record) { return clazzMapper.insert(record); } @Override public int insertSelective(Clazz record) { return clazzMapper.insertSelective(record); } @Override public Clazz selectByPrimaryKey(Integer cid) { return clazzMapper.selectByPrimaryKey(cid); } @Override public int updateByPrimaryKeySelective(Clazz record) { return clazzMapper.updateByPrimaryKeySelective(record); } @Override public int updateByPrimaryKey(Clazz record) { return clazzMapper.updateByPrimaryKey(record); } @Override public List<Clazz> ListPager(Clazz clazz, PageBean pageBean) { return clazzMapper.ListPager(clazz); } @Override public List<Map> mapListPager(Clazz clazz, PageBean pageBean) { return clazzMapper.mapListPager(clazz); } }
控制器代码
JsonController.java
package com.yx.web; import com.yx.biz.ClazzBiz; import com.yx.model.Clazz; import com.yx.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; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:25 */ @Controller @RequestMapping("/clz/json") public class JsonController { @Autowired private ClazzBiz clazzBiz; /** * 返回List<T> * @param req * @param clazz * @return */ @ResponseBody @RequestMapping("/list") public List<Clazz> list(HttpServletRequest req, Clazz clazz){ PageBean pageBean = new PageBean(); pageBean.setRequest(req); List<Clazz> lst = this.clazzBiz.ListPager(clazz, pageBean); return lst; } /** * 返回T * @param req * @param clazz * @return */ @ResponseBody @RequestMapping("/load") public Clazz load(HttpServletRequest req, Clazz clazz){ if(clazz.getCid() != null){ List<Clazz> lst = this.clazzBiz.ListPager(clazz, null); return lst.get(0); } return null; } /** * 返回List<Map> * @param req * @param clazz * @return */ @ResponseBody @RequestMapping("/mapList") public List<Map> mapList(HttpServletRequest req, Clazz clazz){ PageBean pageBean = new PageBean(); pageBean.setRequest(req); List<Map> lst = this.clazzBiz.mapListPager(clazz, pageBean); return lst; } /** * 返回Map * @param req * @param clazz * @return */ @ResponseBody @RequestMapping("/mapLoad") public Map mapLoad(HttpServletRequest req, Clazz clazz){ if(clazz.getCid() != null){ List<Map> lst = this.clazzBiz.mapListPager(clazz, null); return lst.get(0); } return null; } @ResponseBody @RequestMapping("/all") public Map all(HttpServletRequest req, Clazz clazz){ PageBean pageBean = new PageBean(); pageBean.setRequest(req); List<Clazz> lst = this.clazzBiz.ListPager(clazz, pageBean); Map map = new HashMap(); map.put("lst",lst); map.put("pageBean",pageBean); return map; } @ResponseBody//返回单个字符串而不是页面 @RequestMapping("/jsonStr") public String jsonStr(HttpServletRequest req, Clazz clazz){ return "clzEdit"; } }
2.3.3 运行测试结果
结果一:/list
结果二:/load
结果三: /mapList
结果四:/mapLoad
结果五:/all
结果六:/jsonStr
2.3.4 注意事项
- 当方法的@ResponseBody的标签注释掉之后,再去运行请求/jsonStr方法的请求路径,则不会显示数据,则会跳转到/WEB/jsp/clzEdit.jsp页面。
- 当控制器类里的所有方法都是返回json数据则可以在该类的头部打上@ResponseBody注释。
二、秘籍二:异常处理机制
1. 什么是异常处理机制
异常处理机制是一种在软件开发中用于处理错误和异常情况的机制。当程序运行过程中遇到错误或者无法正常执行的情况时,异常处理机制可以捕获和处理这些异常,从而保证程序的健壮性和可靠性。
2. 异常处理机制的主要部分
- 异常的抛出:当程序内部发生错误或者异常情况时,可以通过抛出异常的方式来通知调用者或者上层代码。
- 异常的捕获:在程序的适当位置通过捕获异常的方式来处理异常,避免程序崩溃或者出现不可预料的错误。
- 异常处理代码块:通过使用try-catch-finally语句块来捕获和处理异常,try块用于包含可能抛出异常的代码,catch块用于捕获和处理异常,finally块用于包含无论是否发生异常都需要执行的代码。
- 异常类型的分类:异常可以分为不同的类型,包括系统异常(如空指针异常、数组越界异常等)和自定义异常(在程序中定义的特定异常类型)。
- 异常处理策略:根据不同的异常类型和处理需求,可以采取不同的异常处理策略,如终止程序执行、日志记录、错误提示等。
3. 异常的处理思路
- 检测异常:在程序运行中,首先要检测是否发生了异常。这可以通过条件判断语句、异常捕获语句(如try-catch)或监测错误代码等方式进行。
- 捕获异常:一旦发现异常,需要用合适的机制来捕获异常。在编写代码时,可以使用try-catch语句块来捕获可能抛出的异常。当异常被抛出时,会跳转到catch代码块,并进行进一步的处理。
- 处理异常:在捕获到异常后,需要根据具体情况采取相应的处理措施。这可以包括输出错误信息、记录日志、重新尝试操作、恢复数据、抛出新的异常并终止程序等。
- 清理资源:在处理异常后,要确保已经释放或清理所有已分配的资源,以避免资源泄漏或其他问题。通常会使用finally代码块来实现资源清理操作,确保无论是否发生异常,都会执行finally中的代码。
- 返回结果或提供适当的反馈:根据具体的业务需求,在异常处理过程中需要返回最终的结果或者向用户提供相关的反馈信息。这可以帮助用户更好地理解问题,并可能采取进一步的操作。
异常处理机制图
4. 为什么要全局异常处理
我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。
5. SpringMVC异常分类
SpringMVC异常分类
异常 | 说明 |
Controller层异常 | 这类异常主要是由控制器层(Controller)处理请求过程中抛出的异常,例如请求参数校验失败、请求方法不支持等。 |
业务逻辑异常 | 这类异常一般由Service层负责处理,主要是针对业务操作时产生的异常,例如数据验证失败、资源不存在等。可以根据具体的业务需求定义自定义的业务异常,并通过全局异常处理器进行统一处理。 |
数据访问异常 | 这类异常主要由数据访问层(DAO)抛出,用于表示与数据库、缓存或其他外部系统进行交互时发生的异常,例如数据库连接断开、查询结果为空等。 |
系统级异常 | 这类异常一般是指运行环境、配置或者其他与系统相关的异常,例如文件读写错误、网络连接问题等。这些异常通常是不可预测的,需要通过合适的方式进行处理,如记录错误日志并提供友好的提示信息。 |
6. 综合案例运用
在方法中编写一些异常,待会在测试中测试展示效果。
1. 方式一: springmvc提供的简单异常处理器
在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>
error.jsp页面代码
<%-- Created by IntelliJ IDEA. User: 86158 Date: 2023/9/13 Time: 22:03 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 错误信息界面 ${ex} </body> </html>
页面运行结果
注:页面跳转由SpringMVC来接管了,所以此处的定义默认的异常处理页面都应该配置成逻辑视图名。
2. 方式二:创建一个全局异常类解决
异常类GlobalException .java
package com.yx.exception; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:47 */ 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.java
package com.yx.common; import com.yx.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; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:47 */ @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"); 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","运行时异常...."); }else{ mv.addObject("ex",e.getMessage()); mv.addObject("msg","其他异常...."); } return mv; } }
编写异常
编写jsp代码
测试结果
测试之前要将之前方式的文件代码注释,否则会影响代码运行测试。
3. 方式三:@ControllerAdvice和 @ExceptionHandler完成
将方式二的GlobalExceptionHandler.java文件删除了,创建一个GlobalExceptionResolver.java类(代码如下)
@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; } }
测试结果
将 跳转错误页面的方法代码注释解开,讲下面返回错误json数据的方法注释掉,运行结果如下。
本期的分享到此结束,希望老铁能够三连加关注一波。