基于springboot实现http响应异常信息国际化
背景
国际化是指在设计软件,将软件与特定语言及地区脱钩的过程。当软件被移植到不同的语言及地区时,软件本身不用做内部工程上的改变或修正。
本文提到的异常响应信息国际化是指:前端向后台发起请求,后台在处理逻辑中发生异常,把异常信息返回给前端,返回的异常信息应该支持国际化,能够对应特定的语言、地区等环境。例如,中文语言环境下返回的异常信息应该是中文的,英文语言环境下返回的则是对应的英文。
javaweb项目中,不管是对底层的数据操作,还是业务层的处理过程,还是控制层的处理,都不可避免的会遇到各种可预知的(业务异常主动抛出)、不可预知的异常需要处理。一般dao层、service层的异常都会直接抛出,最后由controller统一进行处理,并对前端请求进行异常响应。针对此处的业务异常应该做到设计合理,统一格式,并且支持国际化。
springboot是一个开源的Java/Java EE的应用程序框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。利用springboot提供的API库,我们能方便地做到全局异常统一拦截,并且Spring提供了完善的国际化支持,在此基础上,我们能方便地做到全局异常信息的国际化。
原来存在的方案:
局部的异常信息国际化:程序在抛出异常时手动设置好国际化之后的异常message。
此种方案代码耦合性强,代码繁琐,处理逻辑过程中抛出异常时还得额外考虑对异常进行国际化操作,使得代码逻辑无法很好的集中在业务逻辑的处理。示意图如图1.1。

半异常信息国际化:程序中未采用配置文件来记录国际化资源,而是直接在程序中写死了固定的异常值,每条异常值记录分别对应着不同的异常编号、某几种语言的异常信息。
这是目前比较常见的方式,写起来方便,不需要在程序抛出异常时做国际化,只需在全局异常拦截中做统一的异常返回。但是,这种方式支持的异常信息比较单一,不能轻易添加多种语言的支持,只能改动现有程序的代码。示意图如图1.2。

使用编程语言自带的异常本地化接口。
不少后台语言提供了异常信息本地化接口,比如java提供的java.lang.Throwable#getLocalizedMessage方法,但是这种方式只能获取到本地语言相关的对应的信息,并不能很好的支持多种语言,以及多种语言间的自由切换。
现在的方案
此方案结合异常码、字符串占位符和资源文件的特点及优势。异常码可理解为一个异常信息的ID,具有唯一性,必要性;异常信息资源文件中的值可包含占位符(格式为{n}),处理异常时可用实际值替换,达到异常信息的进一步具体化,但不是必须的。资源文件就是内容为“异常码=提心信息”的记录的文件。
方案具体描述如下:
首先,在springboot项目中定义系统的http请求统一返回的数据格式,此处我们的定义包含三个属性: code(业务异常状态码)、message(异常提示信息)、data(无异常时返回的数据体)。对异常信息国际化主要体现在message属性,也就是返回前端给用户展示的异常提示信息。code属性用于确定唯一的异常。其次定义需要抛出的业务异常,其中主要包括code(异常码)和params(用于替换异常信息字符串占位符{n}的实际值)属性。
在项目路径下定义异常信息的资源文件,文件内容包含多条记录,每条记录为键值对的形式,即key=value。对需要实现的语言种类分别提供一份对应的文件,这些文件名除默认信息外,均包含语言(地区信息),文件中包含中key是一致的,value为相应语言的字符串组成。如果添加语言的支持,只需要添加一份对应的资源文件即可。以下包含默认、英文环境和简体中文环境下对应的异常提示信息国际化资源文件,如图2.1

利用springboot的提供的接口定义统一拦截器,并且注入http请求上下文和资源获取器,在拦截器中对应用抛出的异常进行捕获,针对上述特定的异常做国际化处理。
其国际化处理逻辑如下:根据http请求传入的语言信息指定特定的语言(地区)环境,如没有传入语言信息,则采用应用默认的语言配置;据此读取上述编写好的对应的异常信息资源文件,并依据捕获的异常中的code(异常码)查到到对应的字符串,将params实际值替换掉字符串中的占位符,完成后即为返回给前端的异常提示信息。

在controller、service和dao层中根据程序逻辑抛出相应异常,其中异常码应该在资源文件中已定义。示例代码如下图2.3

整体流程图如下图2.4

demo
以下是一个demo,其中提供了必要的代码注释,以便于理解。
自定义异常结构,包含code和params

异常资源文件定义

全局异常拦截

代码逻辑中抛出异常

请求响应示例
请求1:http://127.0.0.1:8080/demo?lang=en&msg=a
返回:
请求2:http://127.0.0.1:8080/demo?lang=zh_CN&msg=a
返回:
请求3:http://127.0.0.1:8080/demo?lang=en&msg=c
返回:
请求4:http://127.0.0.1:8080/demo?lang=zh_CN&msg=c
返回:
总结
- 此方案能较好地处理异常信息的国际化,能自如地添加资源文件,不需要改动此方案的现有代码,这也使得程序耦合性降低;
- 统一的异常格式定义、全局异常拦截极大程度上减少了代码耦合性,大大简化了团队编码中对异常逻辑的处理,能减少重复性编码,有利于提高工作效率;
- 现有方案未能较好地支持异常信息中特定值的支持,此方案利用设置占位符的方式,较好地做到了支持,灵活方便;
- springboot支持的国际化实现中默认提供了缓存支持,性能良好。
参考
(文中配图有空再改!!)
基于springboot实现http响应异常信息国际化的更多相关文章
- springboot 1.3.5升级1.5.9后 默认使用tomcat 8.5版本 get请求报400 异常信息为 The valid characters are defined in RFC 7230 and RFC 3986
1.springboot 1.3.5升级1.5.9后 默认使用tomcat 8.5版本而之前用的是tomcat7 get请求报400 异常信息为 The valid characters are ...
- c#执行插入sql 时,报错:异常信息:超时时间已到。在操作完成之前超时时间已过或服务器未响应
问题:c#执行插入sql 时,报错:异常信息:超时时间已到.在操作完成之前超时时间已过或服务器未响应 解决: SqlCommand cmd = new SqlCommand(); cmd.Comman ...
- springboot 统一管理异常信息
新建ResponseEntityExceptionHandler的继承类:(依然,需要入口类扫描) /** * @author sky * @version 1.0 */ @ControllerAdv ...
- 基于SpringBoot搭建应用开发框架(二) —— 登录认证
零.前言 本文基于<基于SpringBoot搭建应用开发框架(一)——基础架构>,通过该文,熟悉了SpringBoot的用法,完成了应用框架底层的搭建. 在开始本文之前,底层这块已经有了很 ...
- shiro,基于springboot,基于前后端分离,从登录认证到鉴权,从入门到放弃
这个demo是基于springboot项目的. 名词介绍: ShiroShiro 主要分为 安全认证 和 接口授权 两个部分,其中的核心组件为 Subject. SecurityManager. Re ...
- 基于springboot的web项目最佳实践
springboot 可以说是现在做javaweb开发最火的技术,我在基于springboot搭建项目的过程中,踩过不少坑,发现整合框架时并非仅仅引入starter 那么简单. 要做到简单,易用,扩展 ...
- 基于SpringBoot+AntDesign的快速开发平台,JeecgBoot 2.0.2 版本发布
Jeecg-Boot 是一款基于SpringBoot+代码生成器的快速开发平台! 采用前后端分离架构:SpringBoot,Ant-Design-Vue,Mybatis,Shiro,JWT. 强大的代 ...
- 搭建基于springboot轻量级读写分离开发框架
何为读写分离 读写分离是指对资源的修改和读取进行分离,能解决很多数据库瓶颈,以及代码混乱难以维护等相关的问题,使系统有更好的扩展性,维护性和可用性. 一般会分三个步骤来实现: 一. 主从数据库搭建 信 ...
- Shiro 核心功能案例讲解 基于SpringBoot 有源码
Shiro 核心功能案例讲解 基于SpringBoot 有源码 从实战中学习Shiro的用法.本章使用SpringBoot快速搭建项目.整合SiteMesh框架布局页面.整合Shiro框架实现用身份认 ...
随机推荐
- easyui 更改dialog弹出的位置
方法一: 在弹出dialog的时候不用$('#dialogDiv').dialog('open');打开.用$('#dialogDiv').window('open');打开.再用window的res ...
- 超越icon font
很久以前,我们如何使用图标? 1.切图 2.拼合(Sprites) 原始社会啊! 后来CSSGagagrunt-css-sprite 字体图标 相见不曾相识 Emoji绘文字 iconfont.cn直 ...
- Shiro实战教程(一)
Shiro完整架构图 Shiro认证过程 Shiro授权的内部处理机制 Shiro 支持三种方式的授权 1.编程式:通过写if/else 授权代码块完成: Subject subject = Secu ...
- GridControl详解(一)原汁原味的表格展示
Dev控件中的表格控件GridControl控件非常强大.不过,一些细枝末节的地方有时候用起来不好找挺讨厌的.使用过程中,多半借助Demo和英文帮助文档.网上具体的使用方法也多半零碎.偶遇一个简单而且 ...
- R0—New packages for reading data into R — fast
小伙伴儿们有福啦,2015年4月10日,Hadley Wickham大牛(开发了著名的ggplots包和plyr包等)和RStudio小组又出新作啦,新作品readr包和readxl包分别用于R读取t ...
- PHP 5 MySQLi 函数总结
连接数据库 mysqli_connect() 函数打开一个到 MySQL 服务器的新的连接. <?php $con=mysqli_connect("localhost",&q ...
- perl6正则 3: 行开头与结尾与多行开头,多行结尾
^ $ 匹配一行的开头或结尾, 可以用 ^ 或 $. > so 'abcde' ~~ /e$/ True > so 'abcdef' ~~ /e$/ False > so 'abcd ...
- ansible 下lineinfile详细使用 【转】
转自 ansible 下lineinfile详细使用 - 散人 - 51CTO技术博客http://zouqingyun.blog.51cto.com/782246/1882367 一.简述 这几天在 ...
- C# 获取mp3文件的歌曲时间长度
添加命名空间: using Shell32; using System.Text.RegularExpressions;添加引用:COM组件的Microsoft Shell Control ...
- 数据结构与算法之KMP 字符串匹配
举例来说,有一个字符串"DSFFKFJD KFJLKFDLJFJ IWWJKJFJIA",我想知道,里面是否包含另一个字符串"JFJI",有的话就返回在原字符串 ...