在我们的项目开发中,我们的RESTFUL API经常会要返回一些消息,有异常消息,也有正常的业务消息。特别是一些国际化的项目,会根据用户所选择的语言,返回不同的消息。
项目初期,没有太多的规范,大家都把这些消息直接写在业务代码中,比如:
public List<User> getUserList() throws Exception { ....... List<User> list = userDao.search(searchParams); if (list == null) throw new Exception("没有找到用户"); ...... }
类似这样的消息还有很多,如:用户名或密码错误,手机号码已经被占用,等等。全部直接硬编码写和业务代码写在一起。
也许大家觉得这样也没什么问题吧?但考虑到如果你所在的项目,他的用户群体是外国人,你的错误消息需要用英文来显示,面我们的开发人员,英语水平可能并不是那么的好,而且一般来说,需求文档也不会细致到将每一种情况的错误消息都完完整整的给出来。在这种情况下,最原始的错误消息一般都是收开发人员自己编写了。那么问题就来了,在客户对项目进行测试验收的时候,发现错误消息存在语法问题,或者意思表示得不清楚。那么你怎么处理这个问题?我想只有跟踪到相应的业务方法中,把硬编码的错误消息修改为客户需要的内容。而且这样的问题可能会在很长一段时间内反复上演。
感觉说了一堆的废话,下面进入正题,怎么样解决这样的问题,其实只需要简单的5个步骤:
1. 配置MessageSource
我们要感觉Spring框架为我们提供了太多的方便,今天我们的主角就是 ResourceBundleMessageSource
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>placeholder/error</value> </list> </property> <property name="useCodeAsDefaultMessage" value="true" /> </bean>在applicationContext.xml中配置messageSource bean.
简单来讲一下两个参数:basenames 和 useCodeAsDefaultMessage
basenames是ResourceBundleMessageSource的一个属性,这里是资源文件的存放路径 /placeholder/error
表示会加载 src/main/resources 目录下 placeholder下error开头的文件。
useCodeAsDefaultMessage,字面意思就是当找不到编码相应的错误消息时,用编码来代替错误消息。
比如:如果我使用错误码为:100001,但这个编码在资源文件中没有找到,那么错误消息就直接返回100001。
2. 创建消息资源文件
在placeholder/error目录下创建资源文件
error_zh.properities
error_en.properities
格式:
0=成功
999999=系统异常,请稍后再试
100001=你好{0},我们的系统已暂停服务,请明天再试。
3. 创建自定义枚举类
public interface CommonMessage { public String getCode(); } public enum Success implements CommonMessage { SUCCESS("0"); public String getCode() { return code; } private String code; private Success(String code) { this.code = code; } } public enum SystemError implements CommonMessage { SYS_ERROR("999999"), ERROR_WITH_ARGS("100001"); public String getCode() { return code; } private String code; private SystemError(String code) { this.code = code; } }
请注意,枚举类中的消息编码,与资源文件中的需要一一对应。
4. 创建ResponseMessage类
public class ResponseMsg implements Serializable { @Resource(name = "messageSource") protected MessageSource messageSource; public String error_code; public String message; public ResponseMsg(){} public String getMessage() {} public void initResult(CommonMessage message, Object[] args){} public void initResult(CommonMessage message, String customMessage){} public void initResult(CommonMessage message){} public String getI18nMessge(String msgCode){} public String getI18nMessge(String msgCode, Object[] args){} public String getI18nMessge(String msgCode, Locale locale){} public String getI18nMessge(String msgCode, Object[] args, Locale locale) { return messageSource.getMessage(msgCode, args, locale); } }这个类的重点在于我们注入的messageSource,也就是我们在applicationContext.xml中配置的。
messageSource.getMessage(msgCode, args, locale);
止方法会根据Local的值去找到相应语言的配置文件去读取消息。
5. 使用消息枚举
到这里,我们就来看一看到底如何使用这个ResponseMsg呢。简单的写了一个Controller返回JSON格式的数据。
package com.txzq.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.txzq.common.Success; import com.txzq.common.SystemError; @Controller @RequestMapping("/hello") @Scope("prototype") public class HelloController { @Autowired private ResponseMsg message; @RequestMapping(value = { "/success" }, method = RequestMethod.GET) public @ResponseBody ResponseMsg success() { message.initResult(Success.SUCCESS); return message; } @RequestMapping(value = { "/failed" }, method = RequestMethod.GET) public @ResponseBody ResponseMsg failed() { message.initResult(SystemError.SYS_ERROR); return message; } @RequestMapping(value = { "/args" }, method = RequestMethod.GET) public @ResponseBody ResponseMsg withMessageArgs() { message.initResult(SystemError.ERROR_WITH_ARGS, new Object[] { "先生" }); return message; } }
以上代码已经上传到github,感兴趣的同学可以下载,github链接:
https://github.com/TXZQ1899/app1
如果已经安装了gitbash, 请在gitbash下执行 :
git clone https://github.com/TXZQ1899/app1.git