背景

国际化是指在设计软件,将软件与特定语言及地区脱钩的过程。当软件被移植到不同的语言及地区时,软件本身不用做内部工程上的改变或修正。

本文提到的异常响应信息国际化是指:前端向后台发起请求,后台在处理逻辑中发生异常,把异常信息返回给前端,返回的异常信息应该支持国际化,能够对应特定的语言、地区等环境。例如,中文语言环境下返回的异常信息应该是中文的,英文语言环境下返回的则是对应的英文。

javaweb项目中,不管是对底层的数据操作,还是业务层的处理过程,还是控制层的处理,都不可避免的会遇到各种可预知的(业务异常主动抛出)、不可预知的异常需要处理。一般dao层、service层的异常都会直接抛出,最后由controller统一进行处理,并对前端请求进行异常响应。针对此处的业务异常应该做到设计合理,统一格式,并且支持国际化。

springboot是一个开源的Java/Java EE的应用程序框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。利用springboot提供的API库,我们能方便地做到全局异常统一拦截,并且Spring提供了完善的国际化支持,在此基础上,我们能方便地做到全局异常信息的国际化。

原来存在的方案:

  1. 局部的异常信息国际化:程序在抛出异常时手动设置好国际化之后的异常message。

    此种方案代码耦合性强,代码繁琐,处理逻辑过程中抛出异常时还得额外考虑对异常进行国际化操作,使得代码逻辑无法很好的集中在业务逻辑的处理。示意图如图1.1。

  2. 半异常信息国际化:程序中未采用配置文件来记录国际化资源,而是直接在程序中写死了固定的异常值,每条异常值记录分别对应着不同的异常编号、某几种语言的异常信息。

    这是目前比较常见的方式,写起来方便,不需要在程序抛出异常时做国际化,只需在全局异常拦截中做统一的异常返回。但是,这种方式支持的异常信息比较单一,不能轻易添加多种语言的支持,只能改动现有程序的代码。示意图如图1.2。

  3. 使用编程语言自带的异常本地化接口。

    不少后台语言提供了异常信息本地化接口,比如java提供的java.lang.Throwable#getLocalizedMessage方法,但是这种方式只能获取到本地语言相关的对应的信息,并不能很好的支持多种语言,以及多种语言间的自由切换。

现在的方案

此方案结合异常码、字符串占位符和资源文件的特点及优势。异常码可理解为一个异常信息的ID,具有唯一性,必要性;异常信息资源文件中的值可包含占位符(格式为{n}),处理异常时可用实际值替换,达到异常信息的进一步具体化,但不是必须的。资源文件就是内容为“异常码=提心信息”的记录的文件。

方案具体描述如下:

  1. 首先,在springboot项目中定义系统的http请求统一返回的数据格式,此处我们的定义包含三个属性: code(业务异常状态码)、message(异常提示信息)、data(无异常时返回的数据体)。对异常信息国际化主要体现在message属性,也就是返回前端给用户展示的异常提示信息。code属性用于确定唯一的异常。其次定义需要抛出的业务异常,其中主要包括code(异常码)和params(用于替换异常信息字符串占位符{n}的实际值)属性。

  2. 在项目路径下定义异常信息的资源文件,文件内容包含多条记录,每条记录为键值对的形式,即key=value。对需要实现的语言种类分别提供一份对应的文件,这些文件名除默认信息外,均包含语言(地区信息),文件中包含中key是一致的,value为相应语言的字符串组成。如果添加语言的支持,只需要添加一份对应的资源文件即可。以下包含默认、英文环境和简体中文环境下对应的异常提示信息国际化资源文件,如图2.1

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

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

  5. 整体流程图如下图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
返回:

总结

  1. 此方案能较好地处理异常信息的国际化,能自如地添加资源文件,不需要改动此方案的现有代码,这也使得程序耦合性降低;
  2. 统一的异常格式定义、全局异常拦截极大程度上减少了代码耦合性,大大简化了团队编码中对异常逻辑的处理,能减少重复性编码,有利于提高工作效率;
  3. 现有方案未能较好地支持异常信息中特定值的支持,此方案利用设置占位符的方式,较好地做到了支持,灵活方便;
  4. springboot支持的国际化实现中默认提供了缓存支持,性能良好。

参考

(文中配图有空再改!!)

基于springboot实现http响应异常信息国际化的更多相关文章

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

  2. c#执行插入sql 时,报错:异常信息:超时时间已到。在操作完成之前超时时间已过或服务器未响应

    问题:c#执行插入sql 时,报错:异常信息:超时时间已到.在操作完成之前超时时间已过或服务器未响应 解决: SqlCommand cmd = new SqlCommand(); cmd.Comman ...

  3. springboot 统一管理异常信息

    新建ResponseEntityExceptionHandler的继承类:(依然,需要入口类扫描) /** * @author sky * @version 1.0 */ @ControllerAdv ...

  4. 基于SpringBoot搭建应用开发框架(二) —— 登录认证

    零.前言 本文基于<基于SpringBoot搭建应用开发框架(一)——基础架构>,通过该文,熟悉了SpringBoot的用法,完成了应用框架底层的搭建. 在开始本文之前,底层这块已经有了很 ...

  5. shiro,基于springboot,基于前后端分离,从登录认证到鉴权,从入门到放弃

    这个demo是基于springboot项目的. 名词介绍: ShiroShiro 主要分为 安全认证 和 接口授权 两个部分,其中的核心组件为 Subject. SecurityManager. Re ...

  6. 基于springboot的web项目最佳实践

    springboot 可以说是现在做javaweb开发最火的技术,我在基于springboot搭建项目的过程中,踩过不少坑,发现整合框架时并非仅仅引入starter 那么简单. 要做到简单,易用,扩展 ...

  7. 基于SpringBoot+AntDesign的快速开发平台,JeecgBoot 2.0.2 版本发布

    Jeecg-Boot 是一款基于SpringBoot+代码生成器的快速开发平台! 采用前后端分离架构:SpringBoot,Ant-Design-Vue,Mybatis,Shiro,JWT. 强大的代 ...

  8. 搭建基于springboot轻量级读写分离开发框架

    何为读写分离 读写分离是指对资源的修改和读取进行分离,能解决很多数据库瓶颈,以及代码混乱难以维护等相关的问题,使系统有更好的扩展性,维护性和可用性. 一般会分三个步骤来实现: 一. 主从数据库搭建 信 ...

  9. Shiro 核心功能案例讲解 基于SpringBoot 有源码

    Shiro 核心功能案例讲解 基于SpringBoot 有源码 从实战中学习Shiro的用法.本章使用SpringBoot快速搭建项目.整合SiteMesh框架布局页面.整合Shiro框架实现用身份认 ...

随机推荐

  1. easyui 更改dialog弹出的位置

    方法一: 在弹出dialog的时候不用$('#dialogDiv').dialog('open');打开.用$('#dialogDiv').window('open');打开.再用window的res ...

  2. 超越icon font

    很久以前,我们如何使用图标? 1.切图 2.拼合(Sprites) 原始社会啊! 后来CSSGagagrunt-css-sprite 字体图标 相见不曾相识 Emoji绘文字 iconfont.cn直 ...

  3. Shiro实战教程(一)

    Shiro完整架构图 Shiro认证过程 Shiro授权的内部处理机制 Shiro 支持三种方式的授权 1.编程式:通过写if/else 授权代码块完成: Subject subject = Secu ...

  4. GridControl详解(一)原汁原味的表格展示

    Dev控件中的表格控件GridControl控件非常强大.不过,一些细枝末节的地方有时候用起来不好找挺讨厌的.使用过程中,多半借助Demo和英文帮助文档.网上具体的使用方法也多半零碎.偶遇一个简单而且 ...

  5. R0—New packages for reading data into R — fast

    小伙伴儿们有福啦,2015年4月10日,Hadley Wickham大牛(开发了著名的ggplots包和plyr包等)和RStudio小组又出新作啦,新作品readr包和readxl包分别用于R读取t ...

  6. PHP 5 MySQLi 函数总结

    连接数据库 mysqli_connect() 函数打开一个到 MySQL 服务器的新的连接. <?php $con=mysqli_connect("localhost",&q ...

  7. perl6正则 3: 行开头与结尾与多行开头,多行结尾

    ^ $ 匹配一行的开头或结尾, 可以用 ^ 或 $. > so 'abcde' ~~ /e$/ True > so 'abcdef' ~~ /e$/ False > so 'abcd ...

  8. ansible 下lineinfile详细使用 【转】

    转自 ansible 下lineinfile详细使用 - 散人 - 51CTO技术博客http://zouqingyun.blog.51cto.com/782246/1882367 一.简述 这几天在 ...

  9. C# 获取mp3文件的歌曲时间长度

    添加命名空间:    using Shell32;    using System.Text.RegularExpressions;添加引用:COM组件的Microsoft Shell Control ...

  10. 数据结构与算法之KMP 字符串匹配

    举例来说,有一个字符串"DSFFKFJD KFJLKFDLJFJ IWWJKJFJIA",我想知道,里面是否包含另一个字符串"JFJI",有的话就返回在原字符串 ...