SpringCloud網關(Zuul)如何給多個微服務之間傳遞共享參數
1、使用場景
因為最近項目需要國際化,但是以前國際化的語言切換是放置在未進行微服務化之前的一個獨立的SpringBoot服務之中。
目前由于業(yè)務的需要和不同模塊能夠復用的要求目前已經拆分為如下服務:zuul網關服務、**dx服務(包含主要服務)、**ai(一些推薦的AI服務)、message(消息咨詢服務)、forum(論壇版塊服務)等等。
如果還是按照以前的的方式只切換 **dx服務 之中的語言;其他微服務是不知道當前的Request請求是什么語言體系的。
就意味 **dx服務 是en語言,但是其他服務還是 zh(中文語言)。
因為此問題,我本人在項目開始進行國際化改版的時候,我就知道有此問題。 我就知道有此問題。 最開始就是有人不信;最后遇見問題了還是相信了!遇見問題了,總得使用相關的方案來解決此問題。
于是本人就是想到了有如下兩種解決方案:
解決方案1
在網關服務(Zuul)之中,寫一個統(tǒng)一的切換語言接口;在切換語言的使用同時調用其他服務的切換語言接口。這樣實現起來最為簡單。
具體如下圖所示:
此方法比較原始直接,但是書寫代碼比較多;想當與每個微服務都得提供一個修改語言體系的接口供 網關(Zuul)
解決方案2
在網關(Zuul)服務層進行語言切換時候獲得切換語言的參數;使用 LocaleContextHolder 暫存當前已經切換語言的信息;
然后在Zuul的過濾器之中通過獲得當前請求(Request)的參數后,把以前語言切換暫存參數值從LocaleContextHolder獲得切換語言的參數值。然后把這個參數傳遞到其他微服務之中;其他微服務通過Request 即可獲得最新切換的語言參數;然后做到順利獲取切換后的最新的語言信息。
具體如下圖所示:
針對方案一與方案二比較后;我選擇使用的方案二。
2、代碼實現
@Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String reqUrl=request.getRequestURL().toString(); HttpSession session = request.getSession(); Map<String, Object> user=(Map<String, Object>) session.getAttribute("user"); if(!(reqUrl.contains("permissionUser/userLogin") || (reqUrl.contains("noAuth")) || reqUrl.contains("appapi"))) { String[] actProfile = env.getActiveProfiles(); String curProfile = actProfile[0]; if (StringUtils.startsWith(curProfile, "dev")) { //dev環(huán)境不做過濾 return null; } //判斷用戶ID是否存在,不存在就跳轉到登錄界面 if (!checkUserIsLogin(ctx, user)) { // System.out.println("session丟失: " + request.getSession().getId()); return null; } //放行ignoreUrls中配置的url if(checkIsIgnoreUrl(request)) { addUserToZuulRequestHeader(user); return null; } //檢查該url是否有權訪問 if (!checkIsUrlHasRight(ctx)) { return null; } //從會話之中獲得當前登錄用戶的userId,判斷用戶是否被踢 if (checkUserIsKickout(ctx, user)) { return null; } } //可以往后走了,把session放入request的header中 addUserToZuulRequestHeader(user); //語言包 setLanguageLocal(request); return null; } /** * 設置本地語言包 * */ private void setLanguageLocal(HttpServletRequest request) { String lang = "zh"; if (StringUtils.isNotEmpty(request.getParameter("lang"))) { lang = request.getParameter("lang"); }else { lang=localeMessageSourceService.getCurrentLanguage(); } switch(lang) { case "zh": LocaleContextHolder.setLocale(Locale.CHINESE); break; case "en": LocaleContextHolder.setLocale(Locale.ENGLISH); break; case "fr": LocaleContextHolder.setLocale(Locale.FRENCH); break; } //此處為獲得請求的參數 然后在請求的參數里面加入暫存的語言攜帶參數 lang RequestContext ctx = RequestContext.getCurrentContext(); request.getParameterMap(); Map<String,List<String>> requestQueryParams=ctx.getRequestQueryParams(); if(requestQueryParams==null) { requestQueryParams=new HashMap<>(); } //String langCode=request.getParameter("lang").toString(); //講需要新增的參數添加進去,被調用的微服務可以直接獲取,就像普通的一樣;框架會直接注入進去 ArrayList<String> arrayList = new ArrayList<>(); arrayList.add(lang); requestQueryParams.put("lang", arrayList); ctx.setRequestQueryParams(requestQueryParams); FrameWorkConstant.MSG_INFO_EMPTY = localeMessageSourceService.getMessage("msg.info.empty"); FrameWorkConstant.MSG_INFO_SUCCESS = localeMessageSourceService.getMessage("msg.success.operate"); FrameWorkConstant.MSG_INFO_FAILED= localeMessageSourceService.getMessage("msg.error.unknown"); }
ChangeLanauageConfigurer
import java.util.Locale; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.SessionLocaleResolver; /*** *@purpose:國際化啟動配置類 *@since:2018年4月9日 ***/ @Configuration public class ChangeLanauageConfigurer extends WebMvcConfigurerAdapter { /** * 描述 : 國際化配置類(會話區(qū)域解析器) * */ @Bean public SessionLocaleResolver localeResolver() { SessionLocaleResolver slr = new SessionLocaleResolver(); // System.out.println("aaaaaaaaaaaaaaaaaaaaaa"); // // 設置默認語言 slr.setDefaultLocale(Locale.CHINESE); return slr; } @Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); // 設置參數名 lci.setParamName("lang"); return lci; } public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } }
LocaleMessageSourceService
/*** *@purpose:本地化語言信息工具類 *@since:2018年3月30日 ***/ @Service public class LocaleMessageSourceService { @Autowired private MessageSource messageSource; /** * *@param code:對應messages配置的key. *@return */ public String getMessage(String code){ //這里使用比較方便的方法,不依賴request. Locale locale = LocaleContextHolder.getLocale(); String lang = locale.getLanguage(); if(LanguageConstant.LANGUAGE_FR.equals(lang)) { locale = new Locale(lang,"FR"); } if(LanguageConstant.LANGUAGE_ZH.equals(lang)) { locale = new Locale(lang,"CN"); } if(LanguageConstant.LANGUAGE_EN.equals(lang)) { locale = new Locale(lang,"US"); } String message = messageSource.getMessage(code,null,locale); return message; } /** * 獲得當前語言 * @param code * @return */ public String getCurrentLanguage(){ Locale locale = LocaleContextHolder.getLocale(); String lang = locale.getLanguage(); if(StringUtils.isEmpty(lang)) { lang = LanguageConstant.LANGUAGE_EN; } return lang; } }
3、成果展現
在網關服務之中切換語言(en)后獲得信息
ai服務的語言體系
**dx服務的語言體系
網關切換為中文(zh)后其他服務語言返回
ai服務語言切換結果
**dx服務語言切換結果
4、總結
如果使用簡單粗暴的方法,直接通過網關調用其他微服務;雖然能夠實現功能;但是此方法比較笨重;同時書寫的代碼比較多。為后期維護帶來很大的不便利。
如果使用方案二在網關層進行統(tǒng)一處理,借助語言切換的能夠在網關(Zuul)服務進行暫存和傳遞;同時動態(tài)添加切換語言后的參數到Request之中;能夠便捷的把語言參數帶到其他微服務之中。此方法值得推崇。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java獲取當前時間并轉化為yyyy-MM-dd?HH:mm:ss格式的多種方式
這篇文章主要介紹了Java獲取當前時間并轉化為yyyy-MM-dd?HH:mm:ss格式的多種方式,每種方式結合實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-03-03mybatisplus?selectOne查詢,有數據,但返回為null問題
這篇文章主要介紹了mybatisplus?selectOne查詢,有數據,但返回為null問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11Java ==,equals()與hashcode()的使用
本文主要介紹了Java ==,equals()與hashcode()的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05