web項目上之深入理解Java國際化

作者:https://blog.csdn.net/yangbo787827967/article/details/81124439

  假設我們正在開發一個支持多國語言的Web應用程序,要求系統能夠根據客戶端的系統的語言類型返回對應的界面:英文的操作系統返回英文界面,而中文的操作系統則返回中文界面——這便是典型的i18n國際化問題。對于有國際化要求的應用系統,我們不能簡單地采用硬編碼的方式編寫用戶界面信息、報錯信息等內容,而必須為這些需要國際化的信息進行特殊處理。簡單來說,就是為每種語言提供一套相應的資源文件,并以規范化命名的方式保存在特定的目錄中,由系統自動根據客戶端語言選擇適合的資源文件。

基礎知識

  “國際化信息”也稱為“本地化信息”,一般需要兩個條件才可以確定一個特定類型的本地化信息,它們分別是“語言類型”和“國家/地區的類型”。如中文本地化信息既有中國大陸地區的中文,又有中國臺灣、中國香港地區的中文,還有新加坡地區的中文。Java通過java.util.Locale類表示一個本地化對象,它允許通過語言參數和國家/地區參數創建一個確定的本地化對象。
  語言參數使用ISO標準語言代碼表示,這些代碼是由ISO-639標準定義的,每一種語言由兩個小寫字母表示。在許多網站上都可以找到這些代碼的完整列表,下面的網址是提供了標準語言代碼的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。
  國家/地區參數也由標準的ISO國家/地區代碼表示,這些代碼是由ISO-3166標準定義的,每個國家/地區由兩個大寫字母表示。用戶可以從以下網址查看ISO-3166的標準代碼:http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。
  表5-2給出了一些語言和國家/地區的標準代碼:
  這里寫圖片描述

Locale

  java.util.Locale是表示語言和國家/地區信息的本地化類,它是創建國際化應用的基礎。下面給出幾個創建本地化對象的示例:

//①帶有語言和國家/地區信息的本地化對象  Locale locale1 = new Locale("zh","CN"); //②只有語言信息的本地化對象 Locale locale2 = new Locale("zh"); //③等同于Locale("zh","CN") Locale locale3 = Locale.CHINA; //④等同于Locale("zh") Locale locale4 = Locale.CHINESE; //⑤獲取本地系統默認的本地化對象 Locale locale 5= Locale.getDefault(); 

  用戶既可以同時指定語言和國家/地區參數定義一個本地化對象①,也可以僅通過語言參數定義一個泛本地化對象②。Locale類中通過靜態常量定義了一些常用的本地化對象,③和④處就直接通過引用常量返回本地化對象。此外,用戶還可以獲取系統默認的本地化對象,如⑤所示。

  在測試時,如果希望改變系統默認的本地化設置,可以在啟動JVM時通過命令參數指定:java -Duser.language=en -Duser.region=US MyTest。

本地化工具類

  JDK的java.util包中提供了幾個支持本地化的格式化操作工具類:NumberFormat、DateFormat、MessageFormat。下面,我們分別通過實例了解它們的用法:
  
  NumberFormat:

Locale locale = new Locale("zh", "CN");  
NumberFormat currFmt = NumberFormat.getCurrencyInstance(locale); double amt = 123456.78; System.out.println(currFmt.format(amt));

  上面的實例通過NumberFormat按本地化的方式對貨幣金額進行格式化操作,運行實例,輸出以下信息:
¥123,456.78
  DateFormat:

Locale locale = new Locale("en", "US");  
Date date = new Date(); DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); System.out.println(df.format(date));

  通過DateFormat#getDateInstance(int style,Locale locale)方法按本地化的方式對日期進行格式化操作。該方法第一個入參為時間樣式,第二個入參為本地化對象。運行以上代碼,輸出以下信息:
Jan 8, 2007
  MessageFormat在NumberFormat和DateFormat的基礎上提供了強大的占位符字符串的格式化功能,它支持時間、貨幣、數字以及對象屬性的格式化操作。下面的實例演示了一些常見的格式化功能:
  MessageFormat:

    //①信息格式化串  String pattern1 = "{0},你好!你于 {1} 在工商銀行存入 {2} 元。";String pattern2 = "At {1,time,short} On {1,date,long},{0} paid {2,number, currency}.";//②用于動態替換占位符的參數  Object[] params = {"John", new GregorianCalendar().getTime(), 1.0E3}; //③使用默認本地化對象格式化信息 String msg1 = MessageFormat.format(pattern1, params); //④使用指定的本地化對象格式化信息 MessageFormat mf = new MessageFormat(pattern2, Locale.US); String msg2 = mf.format(params); System.out.println(msg1); System.out.println(msg2);

  pattern1是簡單形式的格式化信息串,通過{n}占位符指定動態參數的替換位置索引,{0}表示第一個參數,{1}表示第二個參數,以此類推。
  
  pattern2格式化信息串比較復雜一些,除參數位置索引外,還指定了參數的類型和樣式。從pattern2中可以看出格式化信息串的語法是很靈活的,一個參數甚至可以出現在兩個地方:如 {1,time,short}表示從第二個入參中獲取時間部分的值,顯示為短樣式時間;而{1,date,long}表示從第二個入參中獲取日期部分的值,顯示為長樣式時間。關于MessageFormat更詳細的使用方法,請參見JDK的Javadoc。
  
  在②處,定義了用于替換格式化占位符的動態參數,這里,我們使用到了JDK5.0自動裝包的語法,否則必須采用封裝類表示基本類型的參數值。
  

  運行上面的代碼,輸出以下信息:

John,你好!你于 14-7-7 下午11:29 在工商銀行存入 1,000 元。
At 11:29 PM On July 7, 2014,John paid $1,000.00.

  如果應用系統中某些信息需要支持國際化功能,則必須為希望支持的不同本地化類型分別提供對應的資源文件,并以規范的方式進行命名。國際化資源文件的命名規范規定資源名稱采用以下的方式進行命名:
  

<資源名>_<語言代碼>_<國家/地區代碼>.properties

  其中,語言代碼和國家/地區代碼都是可選的。<資源名>.properties命名的國際化資源文件是默認的資源文件,即某個本地化類型在系統中找不到對應的資源文件,就采用這個默認的資源文件。<資源名>_<語言代碼>.properties命名的國際化資源文件是某一語言默認的資源文件,即某個本地化類型在系統中找不到精確匹配的資源文件,將采用相應語言默認的資源文件。
  舉一個例子:假設資源名為resource,則語言為英文,國家為美國,則與其對應的本地化資源文件命名為resource_en_US.properties。信息在資源文件以屬性名/值的方式表示:

resource_en_US.properties,資源文件內容如下:
greeting.common=How are you!
greeting.morning = Good morning!
greeting.afternoon = Good Afternoon!--------對應語言為中文,國家/地區為中國大陸的本地化資源文件則命名為--------------------resource_zh_ CN.properties,資源文件內容如下:
greeting.common=\u60a8\u597d\uff01
greeting.morning=\u65e9\u4e0a\u597d\uff01 greeting.afternoon=\u4e0b\u5348\u597d\uff01

  本地化不同的同一資源文件,雖然屬性值各不相同,但屬性名卻是相同的,這樣應用程序就可以通過Locale對象和屬性名精確調用到某個具體的屬性值了。
  
  讀者可能已經注意到,上面中文的本地化資源文件內容采用了特殊的編碼表示中文字符,這是因為資源文件對文件內容有嚴格的要求:只能包含ASCII字符。所以必須將非ASCII字符的內容轉換為Unicode代碼的表示方式。如上面中文的resource_zh_CN.properties資源文件的三個屬性值分別是“您好!”、“早上好!”和“下午好!”三個中文字符串對應的Unicode代碼串。
  
  如果在應用開發時,直接采用Unicode代碼編輯資源文件是很不方便的,所以,通常我們直接使用正常的方式編寫資源文件,在測試或部署時再采用工具進行轉換。JDK在bin目錄下為我們提供了一個完成此項功能的native2ascii工具,它可以將中文字符的資源文件轉換為Unicode代碼格式的文件,命令格式如下:

native2ascii [-reverse] [-encoding 編碼] [輸入文件 [輸出文件]]

  resource_zh_CN.properties包含中文字符并且以UTF-8進行編碼,假設將該資源文件放到d:\目錄下,通過下面的命令就可以將其轉換為Unicode代碼的形式:

D:\>native2ascii -encoding utf-8 d:\resource_zh_CN.properties
d:\resource_zh_CN_1.properties

  由于原資源文件采用UTF-8編碼,所以必須顯式通過-encoding指定編碼格式。
  通過native2ascii命令手工轉換資源文件,不但在操作上不方便,轉換后資源文件中的屬性內容由于采用了ASCII編碼,閱讀起來也不方便。很多IDE開發工具都有屬性編輯器的插件,插件會自動將資源文件內容轉換為ASCII形式的編碼,同時以正常的方式閱讀和編輯資源文件的內容,這給開發和維護帶來了很大的便利。對于MyEclipse來說,使用MyEclipse Properties Editor編輯資源屬性文件;對于Intellij IDEA來說,無須安裝任何插件就自然支持資源屬性文件的這種編輯方式了。

  如果應用程序中擁有大量的本地化資源文件,直接通過傳統的File操作資源文件顯然太過笨拙。Java為我們提供了用于加載本地化資源文件的方便類java.util.ResourceBoundle。
  ResourceBoundle為加載及訪問資源文件提供便捷的操作,下面的語句從相對于類路徑的目錄中加載一個名為resource的本地化資源文件:

ResourceBundle rb = ResourceBundle.getBundle("com/baobaotao/i18n/resource", locale)

?

  通過以下的代碼即可訪問資源文件的屬性值:

rb.getString("greeting.common") 

?

  來看下面的實例:

ResourceBundle rb1 = ResourceBundle.getBundle("com/baobaotao/i18n/resource", Locale.US);
ResourceBundle rb2 = ResourceBundle.getBundle("com/baobaotao/i18n/resource", Locale.CHINA); System.out.println("us:"+rb1.getString("greeting.common")); System.out.println("cn:"+rb2.getString("greeting.common"));

  rb1加載了對應美國英語本地化的resource_en_US.properties資源文件;而rb2加載了對應中國大陸中文的resource_zh_CN.properties資源文件。運行上面的代碼,將輸出以下信息:

us:How are you!
cn:你好!

  加載資源文件時,如果不指定本地化對象,將使用本地系統默認的本地化對象。所以,在中文系統中,ResourceBundle.getBundle(“com/baobaotao/i18n/resource”)語句也將返回和代碼清單5-14中rb2相同的本地化資源。
  
  ResourceBundle在加載資源時,如果指定的本地化資源文件不存在,它按以下順序嘗試加載其他的資源:本地系統默認本地化對象對應的資源→默認的資源。上面的例子中,假設我們使用ResourceBundle.getBundle(“com/baobaotao/i18n/resource”,Locale.CANADA)加載資源,由于不存在resource_en_CA.properties資源文件,它將嘗試加載resource_zh_CN.properties的資源文件,假設resource_zh_CN.properties資源文件也不存在,它將繼續嘗試加載resource.properties的資源文件,如果這些資源都不存在,將拋出java.util.MissingResourceException異常。

在資源文件中使用格式化串

  在上面的資源文件中,屬性值都是一般的字符串,它們不能結合運行時的動態參數構造出靈活的信息,而這種需求是很常見的。要解決這個問題很簡單,只須使用帶占位符的格式化串作為資源文件的屬性值并結合使用MessageFormat就可以滿足要求了。
  上面的例子中,我們僅向用戶提供一般性問候,下面我們對資源文件進行改造,通過格式化串讓問候語更具個性化:

greeting.common=How are you!{0},today is {1}
greeting.morning = Good morning!{0},now is {1 time short} greeting.afternoon = Good Afternoon!{0} now is {1 date long}

  將該資源文件保存在fmt_resource_en_US.properties中,按照同樣的方式編寫對應的中文本地化資源文件fmt_resource_zh_CN.properties。
  下面,我們聯合使用ResourceBoundle和MessageFormat得到美國英文的本地化問候語:

//①加載本地化資源  
ResourceBundle rb1 =   ResourceBundle.getBundle("com/baobaotao/i18n/fmt_ resource",Locale.US);   
ResourceBundle rb2 =   ResourceBundle.getBundle("com/baobaotao/i18n/fmt_ resource",Locale.CHINA); Object[] params = {"John", new GregorianCalendar().getTime()}; String str1 = new MessageFormat(rb1.getString("greeting.common"),Locale.US).format(params); String str2 =new MessageFormat(rb2.getString("greeting.morning"),Locale.CHINA).format(params); String str3 =new MessageFormat(rb2.getString("greeting.afternoon"),Locale.CHINA).format(params); System.out.println(str1); System.out.println(str2); System.out.println(str3);

  運行以上的代碼,將輸出以下信息:

How are you!John,today is 1/9/07 4:11 PM 早上好!John,現在是下午4:11 下午好!John,現在是2007年1月9日

MessageSource

  Spring定義了訪問國際化信息的MessageSource接口,并提供了幾個易用的實現類。首先來了解一下該接口的幾個重要方法:

String getMessage(String code, Object[] args, String defaultMessage, Locale locale) code表示國際化資源中的屬性名;args用于傳遞格式化串占位符所用的運行期參數;當在資源找不到對應屬性名時,返回defaultMessage參數所指定的默認信息;locale表示本地化對象;
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException
與上面的方法類似,只不過在找不到資源中對應的屬性名時,直接拋出NoSuchMessageException異常;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException
MessageSourceResolvable 將屬性名、參數數組以及默認信息封裝起來,它的功能和第一個接口方法相同。

MessageSource的類結構

  MessageSource分別被HierarchicalMessageSource和ApplicationContext接口擴展,這里我們主要看一下HierarchicalMessageSource接口的幾個實現類,如圖5-7所示:

這里寫圖片描述
  HierarchicalMessageSource接口添加了兩個方法,建立父子層級的MessageSource結構,類似于前面我們所介紹的HierarchicalBeanFactory。該接口的setParentMessageSource (MessageSource parent)方法用于設置父MessageSource,而getParentMessageSource()方法用于返回父MessageSource。
  HierarchicalMessageSource接口最重要的兩個實現類是ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。它們基于Java的ResourceBundle基礎類實現,允許僅通過資源名加載國際化資源。ReloadableResourceBundleMessageSource提供了定時刷新功能,允許在不重啟系統的情況下,更新資源的信息。StaticMessageSource主要用于程序測試,它允許通過編程的方式提供國際化信息。而DelegatingMessageSource是為方便操作父MessageSource而提供的代理類。

ResourceBundleMessageSource
  該實現類允許用戶通過beanName指定一個資源名(包括類路徑的全限定資源名),或通過beanNames指定一組資源名。在前面的代碼清單中,我們通過JDK的基礎類完成了本地化的操作,下面我們使用ResourceBundleMessageSource來完成相同的任務。讀者可以比較兩者的使用差別,并體會Spring所提供的國際化處理功能所帶給我們的好處:

  通過ResourceBundleMessageSource配置資源

    <bean id="myResource"  class="org.springframework.context.support.ResourceBundleMessageSource"> <!--①通過基名指定資源,相對于類根路徑--> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> </bean> 

  啟動Spring容器,并通過MessageSource訪問配置的國際化資源,如下代碼清單所示:
  訪問國際化消息:ResourceBundleMessageSource:

String[] configs = {"com/baobaotao/i18n/beans.xml"};  
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  //①獲取MessageSource的Bean  
MessageSource ms = (MessageSource)ctx.getBean("myResource"); Object[] params = {"John", new GregorianCalendar().getTime()}; //②獲取格式化的國際化信息 String str1 = ms.getMessage("greeting.common",params,Locale.US); String str2 = ms.getMessage("greeting.morning",params,Locale.CHINA); String str3 = ms.getMessage("greeting.afternoon",params,Locale.CHINA); System.out.println(str1); System.out.println(str2); System.out.println(str3);

  比較代碼清單中的代碼,我們發現最主要的區別在于我們無須再分別加載不同語言、不同國家/地區的本地化資源文件,僅僅通過資源名就可以加載整套的國際化資源文件。此外,我們無須顯式使用MessageFormat操作國際化信息,僅通過MessageSource# getMessage()方法就可以完成操作了。這段代碼的運行結果與前面的代碼的運行結果完全一樣。

ReloadableResourceBundleMessageSource

  前面,我們提到該實現類比之于ResourceBundleMessageSource的唯一區別在于它可以定時刷新資源文件,以便在應用程序不重啟的情況下感知資源文件的變化。很多生產系統都需要長時間持續運行,系統重啟會給運行帶來很大的負面影響。這時,通過該實現類就可以解決國際化信息更新的問題。請看下面的配置:
  通過ReloadableResourceBundleMessageSource配置資源:

<bean id="myResource"   
lass="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> <!--① 刷新資源文件的周期,以秒為單位--> <property name="cacheSeconds" value="5"/> </bean>

  在上面的配置中,我們通過cacheSeconds屬性讓ReloadableResourceBundleMessageSource每5秒鐘刷新一次資源文件(在真實的應用中,刷新周期不能太短,否則頻繁的刷新將帶來性能上的負面影響,一般不建議小于30分鐘)。cacheSeconds默認值為-1表示永不刷新,此時,該實現類的功能就蛻化為ResourceBundleMessageSource的功能。
  我們編寫一個測試類對上面配置的ReloadableResourceBundleMessageSource進行測試:

String[] configs = {"com/baobaotao/i18n/beans.xml"};  
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  MessageSource ms = (MessageSource)ctx.getBean("myResource");  
Object[] params = {"John", new GregorianCalendar().getTime()}; for (int i = 0; i < 2; i++) { String str1 = ms.getMessage("greeting.common",params,Locale.US); System.out.println(str1); Thread.currentThread().sleep(20000); //①模擬程序應用,在此期間,我們更改資源文件 } 

  在①處,我們讓程序睡眠20秒鐘,在這期間,我們將fmt_resource_zh_CN.properties資源文件的greeting.common鍵值調整為:

---How are you!{0},today is {1}---
  • 1

  我們將看到兩次輸出的格式化信息分別對應更改前后的內容,也即本地化資源文件的調整被自動生效了:

How are you!John,today is 1/9/07 4:55 PM ---How are you!John,today is 1/9/07 4:55 PM---

容器級的國際化信息資源

  在如圖5-7所示的MessageSource類圖結構中,我們發現ApplicationContext實現了MessageSource的接口。也就是說ApplicationContext的實現類本身也是一個MessageSource對象。
  將ApplicationContext和MessageSource整合起來,乍一看挺讓人費解的,Spring這樣設計的意圖究竟是什么呢?原來Spring認為:在一般情況下,國際化信息資源應該是容器級。我們一般不會將MessageSource作為一個Bean注入到其他的Bean中,相反MessageSource作為容器的基礎設施向容器中所有的Bean開放。只要我們考察一下國際化信息的實際消費場所就更能理解Spring這一設計的用意了。國際化信息一般在系統輸出信息時使用,如Spring MVC的頁面標簽,控制器Controller等,不同的模塊都可能通過這些組件訪問國際化信息,因此Spring就將國際化消息作為容器的公共基礎設施對所有組件開放。
  既然一般情況下我們不會直接通過引用MessageSource Bean使用國際信息,那如何聲明容器級的國際化信息呢?我們其實在5.1.1節講解Spring容器的內部工作機制時已經埋下了伏筆:在介紹容器啟動過程時,我們通過代碼清單5-1對Spring容器啟動時的步驟進行剖析,④處的initMessageSource()方法所執行的工作就是初始化容器中的國際化信息資源:它根據反射機制從BeanDefinitionRegistry中找出名稱為“messageSource”且類型為org.springframework.context.MessageSource的Bean,將這個Bean定義的信息資源加載為容器級的國際化信息資源。請看下面的配置:
  容器級資源的配置:

<!--①注冊資源Bean,其Bean名稱只能為messageSource -->  
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> </bean>

  下面,我們通過ApplicationContext直接訪問國際化信息,如下代碼清單所示:

String[] configs = {"com/baobaotao/i18n/beans.xml"};  
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  
//①直接通過容器訪問國際化信息  
Object[] params = {"John", new GregorianCalendar().getTime()}; String str1 = ctx.getMessage("greeting.common",params,Locale.US); String str2 = ctx.getMessage("greeting.morning",params,Locale.CHINA); System.out.println(str1); System.out.println(str2);

  運行以上代碼,輸出以下信息:

How are you!John,today is 1/9/07 5:24 PM 早上好!John,現在是下午5:24

?

  假設MessageSource Bean名字沒有命名為“messageSource”,以上代碼將拋出NoSuchMessageException異常。

這些文章摘自于我的《Spring 4.x企業應用開發實戰》,我將通過連載的方式,陸續在此發出。歡迎大家討論。

以下是個人在項目中應用的經驗,

前后臺聯動語言

UI設計一個下拉框, 如下
這里寫圖片描述
這里寫圖片描述
客戶自定義語言, 操作之后向后臺設置語言,語言保存于當前SESSION。

String language = request.getParameter("language");
//設置語言并放到session中
request.getSession().setAttribute("language", language); resMessageSource.setResLocale(language);

?

后期的前臺線程進入后臺請求之前在過濾器中設置語言,出過濾器時移除當前ThreadLocal,以免造成內存溢出

    //進入過濾器時ResMessageSourceUtil.setResLocale(request.getSession());//調用方法public static void setResLocale(HttpSession session){ String language = (String)session.getAttribute("language"); if(language == null || "".equals(language)){ language = ResReloadableResourceBundleMessageSource.LANGUAGE; } getResMessageSource().setResLocale(language); } //出過濾器時 ResMessageSourceUtil.remove();

轉載于:https://www.cnblogs.com/But-you/p/10825614.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/536478.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536478.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536478.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Chrome運行時性能瓶頸分析

一&#xff0c;初探&#xff0c;根據現象發現問題 chrome的performance知道很久了&#xff0c;但總是沒有特別權威且跟上時代的學習資料&#xff0c;這次痛定思痛&#xff0c;直接看英文文檔&#xff0c;一點點把這塊啃掉&#xff0c;本筆記基于Chrome 59 step 1: 隱身模式打開…

vue-router之路由鉤子(八)

路由鉤子&#xff0c;即導航鉤子&#xff0c;其實就是路由攔截器&#xff0c;vue-router一共有三類&#xff1a;全局鉤子&#xff1a;最常用路由單獨鉤子組件內鉤子1、全局鉤子在src/router/index.js中使用&#xff0c;代碼如下&#xff1a;// 定義路由配置const router new V…

java第一 ++--

大的轉換小的自動轉換 byte -> short -> int -> long -> float -> double l 自動類型轉換 表示范圍小的數據類型轉換成范圍大的數據類型&#xff0c;這種方式稱為自動類型轉換 自動類型轉換格式&#xff1a; 范圍大的數據類型 變量 范圍小的數據類型值&#xf…

在加拿大讀大學被開除了,以后該怎么辦?

在加拿大讀大學被開除了&#xff0c;以后該怎么辦&#xff1f; 一天晚上正準備睡覺的時候&#xff0c;手機振動&#xff0c;打開一看&#xff0c;是一條微消息&#xff0c;“在加拿大讀大學被開除了&#xff0c;以后該怎么辦&#xff1f;”又一個留學生遇到的棘手問題。在國內上…

GO編程程序員修煉秘籍:十本經典書單

隨著BAT、今日頭條、京東、抖音等大型互聯網公司對Go語言的大范圍應用&#xff0c;帶動更多互聯網企業采取技術跟隨戰略&#xff0c;Go語言發展前景一片大好。5月20日工業和信息化部信息中心發布《2018中國區塊鏈產業白皮書》&#xff0c;Go語言與區塊鏈成為“數字中國”建設的…

AngularJs 冷兵器雜談

一、指令 scope.template中的dom屬性值可以直接用{{attr}}表達式取到scope中的屬性attrlink中attr.$observe可以監聽scope屬性attr的動態變化需要改變$scope上的屬性值時&#xff1a;$scope.$apply(function(){$scope.attr newValue }) 復制代碼二、服務 循環依賴&#xff08;…

02-print的用法

print的常用&#xff1a; print(hello world!)print(hello,world!) # 逗號自動添加默認的分隔符&#xff1a;空格。print(hello world!) # 加號表示字符拼接。print(hello,world,sep***) # 單詞間用***分隔。print(# * 20) # *號表示重復20遍。print(are you sure?, end)…

單田芳白眉大俠全320回下載

1、搜索“十方評書網”。 2、要下載那個評書家的選擇那個評書家。 3、然后選擇自己要下載的下載可以了。 轉載于:https://blog.51cto.com/14204019/2392323

pip模塊 redis、xlrd、xlutils、nnlog、requests

# import模塊的實質&#xff1a;把python文件執行一遍,# 導入模塊的順序&#xff0c;1、從當前模塊找&#xff0c;如果當前模塊沒有&#xff0c;2、就去python環境變量里面找 pip install redispip install xlrd pip install xlutilspip install nnlogpip install requests pip…

react.js基礎

現在最熱門的前端框架有AngularJS、React、Bootstrap等。自從接觸了ReactJS&#xff0c;ReactJs的虛擬DOM&#xff08;Virtual DOM&#xff09;和組件化的開發深深的吸引了我&#xff0c;下面來跟我一起領略ReactJs的風采吧~~ 文章有點長&#xff0c;耐心讀完&#xff0c;你會有…

第 11 章 日志管理 - 089 - 初探 ELK

在開源的日志管理方案中&#xff0c;最出名的莫過于 ELK 了。 ELK 是三個軟件的合稱&#xff1a;Elasticsearch、Logstash、Kibana。 Elasticsearch 一個近乎實時查詢的全文搜索引擎。Elasticsearch 的設計目標就是要能夠處理和搜索巨量的日志數據。 Logstash 讀取原始日志&…

【轉】Kotlin 新版來了,支持跨平臺!

作者&#xff1a;Tamic 原文鏈接&#xff1a;juejin.im/post/5cd8f9… 谷歌在今年的 I/O 大會上宣布&#xff0c;Kotlin 編程語言現在是 Android 應用程序開發人員的首選語言(谷歌宣布 Kotlin 成為安卓開發首選)。 還有一個好消息, Kotlin 1.3.30 正式發布&#xff0c;做了對ap…

WebSocket輕松單臺服務器5w并發jmeter實測

測試結論 nginx最多只能維持(65535*后端服務器IP個數)條websocket的長連接&#xff0c;如果后端websocket服務器IP只有一個&#xff0c;那么就只能最多支持65535條連接。瓶頸就產生在了nginx上建議采用LVS的DR模式來做負載均衡&#xff0c;這樣最大長連接數目就只和websocket服…

人工智能的歷史

AI(Artificial Intelligence)即人工智能&#xff0c;最初是在1956 年被提出&#xff0c;人工智能研究如何用計算機去模擬、延伸和擴展人的智能&#xff1b;如何把計算機用得更聰明&#xff1b;如何設計和建造具有高智能水平的計算機應用系統&#xff1b;如何設計和制造更聰明的…

nginx配置 vue打包后的項目 解決刷新頁面404問題|nginx配置多端訪問

訪問vue頁面時&#xff0c;/# 使url看著不美觀&#xff0c;使用 H5 history模式可以完美解決這個問題&#xff0c;但需要后端nginx幫助。接下來我們自己配置一下。 使用前端路由&#xff0c;但切換新路由時&#xff0c;想要滾動到頁面頂部&#xff0c;或者保持原先的滾動位置&a…

算法導論2nd 10.1-7

為什么80%的碼農都做不了架構師&#xff1f;>>> 思路&#xff1a;兩個隊列q1和q2&#xff0c;兩個隊列指針pusher和poper分別指向q1和q2&#xff0c;push時調用pusher->enqueue&#xff0c;然后將poper里的元素全部dequeue并enqueue到pusher&#xff0c;最后交換…

阿里云Windows2012 R2服務器IPV6配置記錄

要上蘋果APP&#xff0c;則必須要支持IPV6和HTTPS&#xff0c;阿里云本身沒有開放IPV6地址。因此需要進行IPV6的相關配置。查了很多IPV6的配置資料&#xff0c;最終選擇用HE進行IPV6設置。在這過程中遇到一些問題&#xff0c;以記錄下來以備注。 1、IPV6 Tunnel Broker設置 在H…

mycat 1.6.5 for mysql 8分表攻略

2019獨角獸企業重金招聘Python工程師標準>>> 簡述 mycat 對于 mysql 的支持有版本要求&#xff0c;目前 1.6.5 不支持 mysql 8.0 版本。因為mysql 8.0 的加密方式發生了變化。 mycat 1.6.5 連接 mysql 8.0 的兩個方式 mysql 8.0 采用兼容方式&#xff0c;&#xff0…

Funcode-貪吃蛇

自己編寫的一個小游戲&#xff0c;本來打算做貪吃蛇&#xff0c;結果不會使蛇的身子隨蛇頭方向改變而改變就換了種想法&#xff0c;最后變成了這樣一個另類的小游戲&#xff0c;“笑哭“&#xff0c;下面是程序的主要代碼&#xff0c;如果有興趣也可以下載完整程序代碼資源&…

mac 使用遠程連接

https://www.jianshu.com/p/9cc90361f37a轉載于:https://www.cnblogs.com/xiangsj/p/10876400.html