最近项目要做国际化,由于前端直接显示了后端返回的错误码文案,所以后端需要针对错误码做国际化。
实现过程中主要考虑要满足以下两个需求:
1、由于世界的语言非常多,所以新增一门语言能够快速增加,不需要改动代码骨架。
2、在新增一个错误码时,不同的语言的实现类都要同步新增一个错误码,如果未新增时,系统启动时应该给于提示/报错.
基于以上两个需求,想到用工厂模式来实现该需求,实现过程主要包括以下几个类:
LanguageErrorCodeService:语言相关错误码业务接口。
AbstractLanguageErrorCodeService:抽象语言相关错误码业务接口实现类。
LangErrorCodeFactory:语言错误码工厂类 ,主要作用是通过语言去获得对应的处理业务类。
ErrorCodeEnum:错误码枚举,全部语言的错误码都基于这个枚举去定义翻译后的错误码文案。
ChinaErrorCodeService、EngishErrorCodeService、GermanErrorCodeService:具体语言实现业务类
代码结构:
以下为具体的实现代码:
public interface LanguageErrorCodeService { /** * * @param errorCode 错误枚举 * @return 错误码文案 */ String getMessage(ErrorCodeEnum errorCode); }
public abstract class AbstractLanguageErrorCodeService implements LanguageErrorCodeService,InitializingBean{ @Override public void afterPropertiesSet() throws Exception { //校验子类中定义的错误码是否足够,避免每次定义新的错误码之后,子类忘记定义的漏洞 //如果子类的错误码未配置全,那么启动进程时将报错。 ErrorCodeEnum[] enums = ErrorCodeEnum.values(); for(ErrorCodeEnum errorCode : enums) { if (!hasErrorCode(errorCode)) { throw new IllegalStateException(this.getClass().getSimpleName()+"缺少配置的国际化错误msg"); } } } /** * 是否有错误码 * @param errorCode * @return */ protected abstract boolean hasErrorCode(ErrorCodeEnum errorCode); }
@Component public class LangErrorCodeFactory implements ApplicationContextAware{ private ApplicationContext applicationContext; /** * 错误代码语言类 * @param language 语言 * @return */ public LanguageErrorCodeService getLangErrorCode(String language) { return applicationContext.getBean(language, LanguageErrorCodeService.class); } public String[] getAllService(){ return applicationContext.getBeanNamesForType(LanguageErrorCodeService.class); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public static void main(String[] args) { ApplicationContext application = new AnnotationConfigApplicationContext("org.zhanglang.test.web.errorcode"); LangErrorCodeFactory langErrorCodeFactory = application.getBean(LangErrorCodeFactory.class); ErrorCodeEnum passwordError = ErrorCodeEnum.PASSWORD_ERROR; for (String service : langErrorCodeFactory.getAllService()) { String msg = ((LanguageErrorCodeService)application.getBean(service)).getMessage(passwordError); System.out.println(service+"'s errormsg is "+msg); } } }
public enum ErrorCodeEnum { SUCCESS("0","成功"), PASSWORD_ERROR("001","密码错误"), OUT_OF_RETAY_TIMES("002","超过登录最大尝试次数"), CHANGE_DEVICE("003","更换了设备?"); private ErrorCodeEnum(String code, String message) { this.code = code; this.message = message; } private String code; private String message; public String getCode() { return code; } public String getMessage() { return message; } }
@Service("cn") public class ChinaErrorCodeService extends AbstractLanguageErrorCodeService implements LanguageErrorCodeService { @Override public String getMessage(ErrorCodeEnum errorCode) { return errorCode.getMessage(); } @Override protected boolean hasErrorCode(ErrorCodeEnum errorCode) { return true; } }
@Service("engish") public class EngishErrorCodeService extends AbstractLanguageErrorCodeService implements LanguageErrorCodeService { private static final Map<ErrorCodeEnum,String> codeMap = new HashMap<>(); static { codeMap.put(ErrorCodeEnum.SUCCESS, "success."); codeMap.put(ErrorCodeEnum.CHANGE_DEVICE,"change device." ); codeMap.put(ErrorCodeEnum.OUT_OF_RETAY_TIMES,"out of retry times." ); codeMap.put(ErrorCodeEnum.PASSWORD_ERROR, "password is error."); } @Override public String getMessage(ErrorCodeEnum errorCode) { String msg = codeMap.get(errorCode); return msg; } @Override protected boolean hasErrorCode(ErrorCodeEnum errorCode) { return codeMap.containsKey(errorCode); } }
运行LangErrorCodeFactory中的main方法,控制台打印出以下结果,ok.
1234 [main] INFO o.s.c.a.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@157632c9: startup date [Mon Oct 21 16:48:13 CST 2019]; root of context hierarchy 1399 [main] INFO o.s.b.f.a.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring cn's errormsg is 密码错误 engish's errormsg is password is error. german's errormsg is Fehler beim Passwort.