空間站

          北極心空

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

          我的評論

          re: 使用dtree構建動態樹型菜單 蘆葦 2010-02-23 11:32  
          我知道這些代碼是有問題的,而且也是我轉別人的文章,但是我使用的時候就是參考這個弄出來的,一個正常的代碼,你拷貝過去完全正常使用,你還能學到什么?只有出錯了,你自己解決了,你才學到了東西.
          另外:這里是我的私人博客,是我收集一些資料的地方,沒有你想要的東西很正常啊,請不要出口傷人!
          StyleTest
          這個類里面紅叉叉,不知道開發的時候用的jdk是哪個版本,我的jdk1.5的java.awt.Font怎么沒有Font.DIALOG常量?
          re: OpenID使用手冊 蘆葦 2008-11-04 18:38  
          openid server
          http://code.google.com/p/openid-server/
          http://www.movabletype.org/download.html
          客戶端插件:

          http://openid4java.googlecode.com/svn/trunk
          re: OpenID使用手冊 蘆葦 2008-11-04 18:28  
          關于OPENID的單點登陸協議

          因為經常看到有OpenId的吹捧者,所以本來希望寫一個OpenId的BLOG,引起大家的注意,然后從他們哪兒獲得一些關于OpenId詳細協議的資料,可惜失算了。

          不得以,今天早上,花了一些時間,在詞典的幫助下用我蹩腳的英語翻譯了一下OpenId的協議。終于搞明白了OpenId的加密驗證模式。

          最關鍵的是第三步和第七步。這兩步由應用服務器任選其一,他們都是應用服務器直接與身份驗證服務器交互,第三步是獲得并保存一個密匙,用于嚴整用戶所傳遞的數據是否合法。第七步則是直接把接受的信息交個身份驗證服務器,然后由身份驗證服務器來驗證這個信息是否合法。

          這樣以來,我前邊所講的哪個HACK的模式就的確是行不通的了。

          ———以下是我翻譯的全文———

          一個帶圖片說明的OpenId協議介紹

          A description of the OpenID protocol with diagrams.

           

          1: User submits Identity URL

          1:用戶提交身份地址

          The consumer uses a form with GET or POST to allow the user to enter their OpenID url.

          應用服務器通過GET或者POST方法獲得用戶提交他們的OpenId地址(身份地址)

          2: Consumer fetches Identity URL

          2:應用服務器取得身份驗證服務器

          The consumer parses the HTML content and looks for a tag:

          <LINK REL='openid.server' HREF=(the server)>

          應用服務器解吸用戶提交的地址的數據中的HTML標簽:<link rel=’openid.server’ href=’the server’>(其中the server 就是身份驗證服務器)

          3: Consumer associates with server (option 1)

          3:應用服務器與身份驗證服務器交互(選項1

          In order to communicate securely with the server, the consumer gets an association with the server discovered in step 2, using an existing association if it is available, otherwise visiting the server and using Diffie Hellman to negotiate a shared secret with which to sign communication.  A consumer unable to store state uses "dumb mode" which does not perform this step, and instead uses step 7.

          為了能夠與身份驗證服務器安全的通信,應用服務器需要向(從第2步獲取的)身份驗證服務器請求一個協議。如果有現成的可以使用的協議,則用現有的協議,否則,通過Diffie Hellman的方法獲得一個共享密匙,靜默模式(dumb mode)下的應用服務器不需要這一步,而是使用第7步的操作。

          4: Consumer redirects the user to the server

          4:應用服務器將用戶重定向到身份驗證服務器

          The OpenID server URL accepts a query, containing all the information the server needs to check the user's identity and redirect the user back to the consumer.  The server checks the authentication of the user.  If the user is signed in (has an auth cookie) and has already authorized sending their identity to the consumer, step 5 may be skipped.

          OpenId服務器接受一個包含所有應用服務器需要用來驗證用戶的信息,如果用戶已經登陸(有COOKIE)并且他已經同意發送他的身份信息給應用服務器的話,第5步可以跳過。

          5: User Authenticates to server

          5:用戶鑒別是否是自己訪問的服務

          The user authenticates to the server with a cookie or a username and password, and the server asks the user for permission to send their identity information to the consumer.

          通過COOKIE或者用戶名+密碼驗證當前用戶是否登陸,并且詢問當前用戶是否允許應用服務器獲得自己的身份信息。

          6: Server redirects the user back to the consumer

          6: 身份驗證服務器重定向用戶到應用服務器

          The consumer parses the servers response (which is appended to the return-to URL the consumer sent) and verifies it using the association, or in the case of dumb mode proceeds to step 7.

          應用服務器使用獲得的身份驗證服務器的協議,校驗并解析所返回的數據。如果在靜默模式(dumb mode)下,繼續第7步。

          7: Consumer verifies the response with the server (option 2)

          7:應用服務器通過身份驗證服務器校驗接收到的信息(選項2

          Communicating directly with the server, the dumb mode consumer checks the response received via the User Agent in the redirect.

          應用服務器直接連接身份驗證服務器校驗接受到的信息,在靜默模式下的應用服務器使用重定向的方法通過身份地址(User Agent)核對接受到的信息。



          Trackback: http://tb.donews.net/TrackBack.aspx?PostId=1085110

          re: Spring 的優秀工具類盤點 蘆葦 2008-10-27 11:32  

          Spring框架下自帶了豐富的工具類,在我們開發時可以簡化很多工作:

          1.Resource訪問文件資源:

             具體有:ResourceUtils.getFile(url);

                     FileSystemResource(); ClassPathResource();

                     ServletContextResource(application,url);

           

          2.文件操作 FileCopyUtils

             具體有:FileCopyUtils.copy(Resource.getFile,new File(Resource.getFile(),getParent()+'目標文件名'));

           

          3.屬性文件操作 PropertiesLoaderUtils    

             具體有: PropertiesLoaderUtils.loadAllProperties("屬性文件名");  --基于類路徑

           

          4.EncodedResource(Resource對象,"UTF-8") 編碼資源(特殊的);

           

          5.WebApplicationContextUtils

           

          6.WebUtils

             具體有:getCookie, getSessionAttribute, getRealPath;

           

          7.StringEscapeutils 編碼解碼

          re: Hibernate 參數設置一覽表 蘆葦 2008-10-14 18:13  

          SQL方言

          1、Hibernate JDBC屬性

          屬性名 用途
          hibernate.connection.driver_class jdbc驅動類
          hibernate.connection.url jdbc URL
          hibernate.connection.username 數據庫用戶
          hibernate.connection.password 數據庫用戶密碼
          hibernate.connection.pool_size 連接池容量上限數目
          注:使用C3P0的properties樣例代碼:
          hibernate.connection.driver_class = org.postgresql.Driver
          hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
          hibernate.connection.username = myuser
          hibernate.connection.password = secret
          hibernate.c3p0.min_size=5
          hibernate.c3p0.max_size=20
          hibernate.c3p0.timeout=1800
          hibernate.c3p0.max_statements=50
          hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

          2、Hibernate的數據源屬性
          屬性名 用途
          hibernate.connection.datasource 數據源JNDI名字
          hibernate.jndi.url JNDI提供者的URL (可選)
          hibernate.jndi.class JNDI InitialContextFactory (可選)
          hibernate.connection.username 數據庫用戶 (可選)
          hibernate.connection.password 數據庫用戶密碼 (可選)
          注:應用程序服務器JNDI數據源的hibernate.properties樣例代碼:
          hibernate.connection.datasource = java:/comp/env/jdbc/test
          hibernate.transaction.factory_class = \
              org.hibernate.transaction.JTATransactionFactory
          hibernate.transaction.manager_lookup_class = \
              org.hibernate.transaction.JBossTransactionManagerLookup
          hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

          3、Hibernate配置屬性(可選)
          屬性名 用途
          hibernate.dialect 一個Hibernate Dialect類名允許Hibernate針對特定的關系數據庫生成優化的SQL.

          取值full.classname.of.Dialect

          hibernate.show_sql 輸出所有SQL語句到控制臺.

          取值true | false

          hibernate.format_sql 在log和console中打印出更漂亮的sql.

          取值true | false

          hibernate.default_schema 在生成的SQL中, 將給定的schema/tablespace附加于非全限定名的表名上.

          取值SCHEMA_NAME

          hibernate.default_catalog 在生成的SQL中, 將給定的catalog附加于沒全限定名的表名上.

          取值CATALOG_NAME

          hibernate.session_factory_name SessionFactory創建后,將自動使用這個名字綁定到JNDI中.

          取值jndi/composite/name

          hibernate.max_fetch_depth 為單向關聯(一對一, 多對一)的外連接抓取(outer join fetch)樹設置最大深度. 值為0意味著將關閉默認的外連接抓取.

          取值 建議在03之間取值

          hibernate.default_batch_fetch_size 為Hibernate關聯的批量抓取設置默認數量.

          取值 建議的取值為4, 8, 和16

          hibernate.default_entity_mode 為由這個SessionFactory打開的所有Session指定默認的實體表現模式.

          取值dynamic-map, dom4j, pojo

          hibernate.order_updates 強制Hibernate按照被更新數據的主鍵,為SQL更新排序。這么做將減少在高并發系統中事務的死鎖。

          取值true | false

          hibernate.generate_statistics 如果開啟, Hibernate將收集有助于性能調節的統計數據.

          取值true | false

          hibernate.use_identifer_rollback 如果開啟, 在對象被刪除時生成的標識屬性將被重設為默認值.

          取值true | false

          hibernate.use_sql_comments 如果開啟, Hibernate將在SQL中生成有助于調試的注釋信息, 默認值為false.

          取值true | false


          4、Hibernate JDBC和連接(connection)屬性
          屬性名 用途
          hibernate.jdbc.fetch_size 非零值,指定JDBC抓取數量的大小 (調用Statement.setFetchSize()).
          hibernate.jdbc.batch_size 非零值,允許Hibernate使用JDBC2的批量更新.

          取值 建議取530之間的值

          hibernate.jdbc.batch_versioned_data 如果你想讓你的JDBC驅動從executeBatch()返回正確的行計數 , 那么將此屬性設為true(開啟這個選項通常是安全的). 同時,Hibernate將為自動版本化的數據使用批量DML. 默認值為false.

          eg.true | false

          hibernate.jdbc.factory_class 選擇一個自定義的Batcher. 多數應用程序不需要這個配置屬性.

          eg.classname.of.Batcher

          hibernate.jdbc.use_scrollable_resultset 允許Hibernate使用JDBC2的可滾動結果集. 只有在使用用戶提供的JDBC連接時,這個選項才是必要的, 否則Hibernate會使用連接的元數據.

          取值true | false

          hibernate.jdbc.use_streams_for_binary 在JDBC讀寫binary (二進制)serializable (可序列化) 的類型時使用流(stream)(系統級屬性).

          取值true | false

          hibernate.jdbc.use_get_generated_keys 在數據插入數據庫之后,允許使用JDBC3 PreparedStatement.getGeneratedKeys() 來獲取數據庫生成的key(鍵)。需要JDBC3+驅動和JRE1.4+, 如果你的數據庫驅動在使用Hibernate的標 識生成器時遇到問題,請將此值設為false. 默認情況下將使用連接的元數據來判定驅動的能力.

          取值true|false

          hibernate.connection.provider_class 自定義ConnectionProvider的類名, 此類用來向Hibernate提供JDBC連接.

          取值classname.of.ConnectionProvider

          hibernate.connection.isolation 設置JDBC事務隔離級別. 查看java.sql.Connection來了解各個值的具體意義, 但請注意多數數據庫都不支持所有的隔離級別.

          取值1, 2, 4, 8

          hibernate.connection.autocommit 允許被緩存的JDBC連接開啟自動提交(autocommit) (不建議).

          取值true | false

          hibernate.connection.release_mode 指定Hibernate在何時釋放JDBC連接. 默認情況下,直到Session被顯式關閉或被斷開連接時,才會釋放JDBC連接. 對于應用程序服務器的JTA數據源, 你應當使用after_statement, 這樣在每次JDBC調用后,都會主動的釋放連接. 對于非JTA的連接, 使用after_transaction在每個事務結束時釋放連接是合理的. auto將為JTA和CMT事務策略選擇after_statement, 為JDBC事務策略選擇after_transaction.

          取值on_close | after_transaction | after_statement | auto

          hibernate.connection.<propertyName> 將JDBC屬性propertyName傳遞到DriverManager.getConnection()中去.
          hibernate.jndi.<propertyName> 將屬性propertyName傳遞到JNDI InitialContextFactory中去.

          5、Hibernate緩存屬性
          屬性名 用途
          hibernate.cache.provider_class 自定義的CacheProvider的類名.

          取值classname.of.CacheProvider

          hibernate.cache.use_minimal_puts 以頻繁的讀操作為代價, 優化二級緩存來最小化寫操作. 在Hibernate3中,這個設置對的集群緩存非常有用, 對集群緩存的實現而言,默認是開啟的.

          取值true|false

          hibernate.cache.use_query_cache 允許查詢緩存, 個別查詢仍然需要被設置為可緩存的.

          取值true|false

          hibernate.cache.use_second_level_cache 能用來完全禁止使用二級緩存. 對那些在類的映射定義中指定<cache>的類,會默認開啟二級緩存.

          取值true|false

          hibernate.cache.query_cache_factory 自定義的實現QueryCache接口的類名, 默認為內建的StandardQueryCache.

          取值classname.of.QueryCache

          hibernate.cache.region_prefix 二級緩存區域名的前綴.

          取值prefix

          hibernate.cache.use_structured_entries 強制Hibernate以更人性化的格式將數據存入二級緩存.

          取值true|false


          6、Hibernate事務屬性
          屬性名 用途
          hibernate.transaction.factory_class 一個TransactionFactory的類名, 用于Hibernate Transaction API (默認為JDBCTransactionFactory).

          取值classname.of.TransactionFactory

          jta.UserTransaction 一個JNDI名字,被JTATransactionFactory用來從應用服務器獲取JTA UserTransaction.

          取值jndi/composite/name

          hibernate.transaction.manager_lookup_class 一個TransactionManagerLookup的類名 - 當使用JVM級緩存,或在JTA環境中使用hilo生成器的時候需要該類.

          取值classname.of.TransactionManagerLookup

          hibernate.transaction.flush_before_completion 如果開啟, session在事務完成后將被自動清洗(flush). (在Hibernate和CMT一起使用時很有用.)

          取值true | false

          hibernate.transaction.auto_close_session 如果開啟, session在事務完成前將被自動關閉. (在Hibernate和CMT一起使用時很有用.)

          取值true | false


          7、其他屬性
          屬性名 用途
          hibernate.query.factory_class 選擇HQL解析器的實現.

          取值org.hibernate.hql.ast.ASTQueryTranslatorFactory or org.hibernate.hql.classic.ClassicQueryTranslatorFactory

          hibernate.query.substitutions 將Hibernate查詢中的符號映射到SQL查詢中的符號 (符號可能是函數名或常量名字).

          取值hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC

          hibernate.hbm2ddl.auto SessionFactory創建時,自動將數據庫schema的DDL導出到數據庫. 使用 create-drop時,在顯式關閉SessionFactory時,將drop掉數據庫schema.

          取值update | create | create-drop

          hibernate.cglib.use_reflection_optimizer 開啟CGLIB來替代運行時反射機制(系統級屬性). 反射機制有時在除錯時比較有用. 注意即使關閉這個優化, Hibernate還是需要CGLIB. 你不能在hibernate.cfg.xml中設置此屬性.

          取值true | false


          8、SQL方言
             Hibernate SQL方言 (hibernate.dialect)
          RDBMS 方言
          DB2 org.hibernate.dialect.DB2Dialect
          DB2 AS/400 org.hibernate.dialect.DB2400Dialect
          DB2 OS390 org.hibernate.dialect.DB2390Dialect
          PostgreSQL org.hibernate.dialect.PostgreSQLDialect
          MySQL org.hibernate.dialect.MySQLDialect
          MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
          MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
          Oracle (any version) org.hibernate.dialect.OracleDialect
          Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
          Sybase org.hibernate.dialect.SybaseDialect
          Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
          Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
          SAP DB org.hibernate.dialect.SAPDBDialect
          Informix org.hibernate.dialect.InformixDialect
          HypersonicSQL org.hibernate.dialect.HSQLDialect
          Ingres org.hibernate.dialect.IngresDialect
          Progress org.hibernate.dialect.ProgressDialect
          Mckoi SQL org.hibernate.dialect.MckoiDialect
          Interbase org.hibernate.dialect.InterbaseDialect
          Pointbase org.hibernate.dialect.PointbaseDialect
          FrontBase org.hibernate.dialect.FrontbaseDialect
          Firebird org.hibernate.dialect.FirebirdDialect

          9、Hibernate日志類別
          類別 功能
          org.hibernate.SQL 在所有SQL DML語句被執行時為它們記錄日志
          org.hibernate.type 為所有JDBC參數記錄日志
          org.hibernate.tool.hbm2ddl 在所有SQL DDL語句執行時為它們記錄日志
          org.hibernate.pretty 在session清洗(flush)時,為所有與其關聯的實體(最多20個)的狀態記錄日志
          org.hibernate.cache 為所有二級緩存的活動記錄日志
          org.hibernate.transaction 為事務相關的活動記錄日志
          org.hibernate.jdbc 為所有JDBC資源的獲取記錄日志
          org.hibernate.hql.ast 為HQL和SQL的自動狀態轉換和其他關于查詢解析的信息記錄日志
          org.hibernate.secure 為JAAS認證請求做日志
          org.hibernate 為任何Hibernate相關信息做日志 (信息量較大, 但對查錯非常有幫助)

          re: SVN 恢復刪除 蘆葦 2008-10-10 11:34  
          仔細在理解一下,你所述看不到那個按鈕?

          你是使用TortoiseSVN客戶端嗎?
          re: 使用dtree構建動態樹型菜單 蘆葦 2008-10-10 11:21  
          @SS

          的確是轉貼的,沒看到最下面的說明嗎?這是我的收藏,覺得沒用就請你離開
          經過測試的log4j.properties文件---用于數據庫的log
          log4j.rootLogger = DEBUG,DATABASE

          log4j.appender.DATABASE = org.apache.log4j.jdbc.JDBCAppender
          log4j.appender.DATABASE.Driver = oracle.jdbc.driver.OracleDriver
          log4j.appender.DATABASE.URL = jdbc:oracle:thin:@192.168.8.2:1521:dssdb
          log4j.appender.DATABASE.User = tom
          log4j.appender.DATABASE.Password = lizhifeng
          log4j.appender.DATABASE.layout = org.apache.log4j.PatternLayout
          log4j.appender.DATABASE.layout.ConversionPattern = INSERT INTO log4j (createDate, thread, priority, category, message) values(sysdate, '%t', '%-5p', '%c', '%m')
          一 最好與commons-logging一起用,why?

          1.標準接口,即使將來脫離了log4j也一樣用
          2.簡化了編碼,減少耦合度:不需在代碼中指定log4j配制文件位置,代碼中不需要引用log4j的包
          3.基本所有框架都是這么用的。。。。。。(我相信群眾)

          附加提供一下commons-logging尋找配置文件的順序(從別人那抄的)
          1) 首先在classpath下尋找自己的配置文件commons-logging.properties,如果找到,則使用其中定義的Log實現類;
          2) 如果找不到commons-logging.properties文件,則在查找是否已定義系統環境變量org.apache.commons.logging.Log,找到則使用其定義的Log實現類;
          3) 否則,查看classpath中是否有Log4j的包,如果發現,則自動使用Log4j作為日志實現類;
          4) 否則,使用JDK自身的日志實現類(JDK1.4以后才有日志實現類);
          5) 否則,使用commons-logging自己提供的一個簡單的日志實現類SimpleLog;


          二 具體實現

          1.把commons-logging的jar加到classpath中
          2.把log4j的jar加到classpath中
          3.在classpath的根目錄下,建立log4j.properties(必須是這個地方,必須叫這個名,才不用特殊配置),可以直接復制后邊的模板
          4.在需要log的類中:
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;

          private static Log log = LogFactory.getLog(xxxx.class);
          為什么要使用static?因為避免產生多個實例
          為什么不使用this.class?因為是static不能用this(我經常犯這個錯誤。。。)
          為什么不使new XXXX().getClass()?因為。。。。你猜呢?
          5.根據實際需要log.debug()、log.info()、log.warn()、log.error()、log.fatal() 就可以輸出不同等級的log


          三 log的等級

          1.為什么需要等級?寫代碼的時候可能需要很多調試信息,運行的時候可能需要顯示提示信息,如果在服務器上發生嚴重錯誤的時候,可能需要給管理員發郵件。這種:調試,提示,錯誤就是等級。
          2.都有什么等級? 調試(DEBUG)<信息(INFO)<警告(WARN)<錯誤(ERROR)<致命錯誤(FATAL)
          3.怎么用? log.debug() log.info() log.warn() log.error() log.fatal()依次對應上邊的等級


          四 log4j的配制

          1.基本參數解釋:
          ⑴全局配制
          log4j.rootLogger = [ level ] , appenderName, appenderName,..........appenderName
          ★log4j.rootLogger的意思可以理解為:根log或者所有的log
          ★level就是輸出級別,只能設置一個值。
          ·關于等級,前邊已經說過了有5種,他們之間的關系可以理解為:
          調試(DEBUG):包含調試(DEBUG)、信息(INFO)、警告(WARN)、錯誤(ERROR)、致命錯誤(FATAL)
          信息(INFO):包含信息(INFO)、警告(WARN)、錯誤(ERROR)、致命錯誤(FATAL)
          警告(WARN):包含警告(WARN)、錯誤(ERROR)、致命錯誤(FATAL)
          錯誤(ERROR):包含錯誤(ERROR)、致命錯誤(FATAL)
          致命錯誤(FATAL):只有他自己
          這樣,如果log4j.rootLogger = INFO,那么 INFO,WARN,ERROR,FATAL就全部會被輸出
          如果log4j.rootLogger = ERROR,那么ERROR,FATAL就全部會被輸出
          ★appenderName就是記錄的目標,目標可以多個,中間用『,』分割,appenderName是自己定義的,換句話說,名字是隨便起的,起了名之后,就需要在下邊設定具體配制
          總結一下這部分,比如說有這么一句log4j.rootLogger = INFO , F1,F2那么就以為著要將所有INFO,WARN,ERROR,FATAL的log全部輸出到F1,F2上。F1,F2是什么?往下看。。。。
          ⑵具體配制
          log4j.appender.F1=org.apache.log4j.ConsoleAppender
          log4j.appender.F1.layout=org.apache.log4j.PatternLayout
          log4j.appender.F1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
          ★log4j.appender.F1=org.apache.log4j.ConsoleAppender的意思就是:將F1設置為控制臺輸出
          ·還可以設置成什么?
          org.apache.log4j.ConsoleAppender(控制臺),
          org.apache.log4j.FileAppender(文件),
          org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件),
          org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),
          org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
          ★log4j.appender.F1.layout=org.apache.log4j.PatternLayout的意思就是:將F1的輸出布局設置為自定義輸出布局。
          ·還可以設置成什么?
          org.apache.log4j.HTMLLayout(以HTML表格形式布局)
          org.apache.log4j.xml.XMLLayout(以XML形式布局)
          org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
          org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
          org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)
          ★log4j.appender.F1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n既然上邊定義的是自定義輸出布局,那么就要定義一下具體輸出什么樣了~~上邊的%c %p %m 等以%開頭的都是模式字符串,除了模式字符串外[]-空格等這些字符會按照原樣顯示。
          ·模式字符串解釋:
          %m:消息本身
          %p:消息的級別INFO,WARN,ERROR。。。
          %r:從程序開始執行到當前日志產生時的時間間隔(微秒)
          %c:輸出當前日志動作所在的category名稱。例如:如果category名稱是"a.b.c","%c{2}"將會輸出"b.c". {2}意謂著輸出“以點分隔開的category名稱的后兩個組件”,如果 {n}沒有,將會輸出整個category名稱.
          %t:輸出當前線程的名稱
          %x:輸出和當前線程相關聯的NDC,尤其用到像java servlets這樣的多客戶多線程的應用中。
          %n:輸出平臺相關的換行符。
          %%:輸出一個"%"字符
          %d:輸出日志產生時候的日期,當然可以對日期的格式進行定制。例如:%d{HH:mm:ss,SSSS}或者是%d{dd MMM yyyy HH:mm:ss,SSSS},如果沒有指定后面的格式,將會輸出ISO8601的格式。
          %l:輸出位置信息,相當于%C.%M(%F:%L)的組合。
          %C:輸出日志消息產生時所在的類名,如果類名是“test.page.Class1”%C{1}表示輸出類名"Class1",%C{2}輸出"page.Class1",而%C則輸出"test.page.Class1"。
          %M:輸出日志消息產生時的方法名稱
          %F:輸出日志消息產生時所在的文件名稱
          %L:輸出代碼中的行號
          ·可以在%與模式字符之間加上修飾符來控制其最小寬度、最大寬度、和文本的對齊方式。如:
          1)%20c:指定輸出category的名稱,最小的寬度是20,如果category的名稱小于20的話,默認的情況下右對齊。
          2)%-20c:指定輸出category的名稱,最小的寬度是20,如果category的名稱小于20的話,"-"號指定左對齊。
          3)%.30c:指定輸出category的名稱,最大的寬度是30,如果category的名稱大于30的話,就會將左邊多出的字符截掉,但小于30的話也不會有空格。
          4)%20.30c:如果category的名稱小于20就補空格,并且右對齊,如果其名稱長于30字符,就從左邊交遠銷出的字符截掉。
          總結一下,現在來我們所配制的F1的全部內容
          ·我們把它配制成了屏幕輸出
          ·輸出的布局為:自定義布局
          ·我們又定義了自定義布局的格式:日期時間(格式為:yyyy-MM-dd HH:mm:ss,SSS)[產生該日志的包名類名方法名] [等級] 信息+回車
          如果想配制F2為每天產生一個日志文件,并且保存為xml,就這么寫:
          log4j.appender.F2=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.F2.layout=org.apache.log4j.xml.XMLLayout
          這樣就可以了嗎?當然不是,既然保存為文件。。至少要指定一個文件名吧
          log4j.appender.F2.File=c:/logs/log.xml
          可以了嗎?可以運行了。。。但是。。既然每天都產生一個文件,那么前一天的怎么辦呢?
          log4j.appender.F2.DatePattern=yyyyMMdd'.xml.back'
          這樣log4j會在第一次產生今天的log的同時,將昨天的log備份為 log文件名.擴展名yyyyMMdd.xml.back。對應我們這個文件,今天的log到明天有新log產生的時候,就會變為log.xml20070420.xml.back
          這樣的參數到底有多少?常用的有:
          ★ConsoleAppender選項
          ·Threshold=WARN:指定日志消息的輸出最低層次。
          ·ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。
          ·Target=System.err:默認情況下是:System.out,指定輸出控制臺
          ★FileAppender 選項
          ·Threshold=WARN:指定日志消息的輸出最低層次。
          ·ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。
          ·File=mylog.txt:指定消息輸出到mylog.txt文件。
          ·Append=false:默認值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內容。
          ★RollingFileAppender 選項
          ·Threshold=WARN:指定日志消息的輸出最低層次。
          ·ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。
          ·File=mylog.txt:指定消息輸出到mylog.txt文件。
          ·Append=false:默認值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內容。
          ·MaxFileSize=100KB: 后綴可以是KB, MB 或者是 GB. 在日志文件到達該大小時,將會自動滾動,即將原來的內容移到mylog.log.1文件。
          ·MaxBackupIndex=2:指定可以產生的滾動文件的最大數。
          ★DailyRollingFileAppender 選項
          ·Threshold=WARN:指定日志消息的輸出最低層次。
          ·ImmediateFlush=true:默認值是true,意謂著所有的消息都會被立即輸出。
          ·File=mylog.txt:指定消息輸出到mylog.txt文件。
          ·Append=false:默認值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內容。
          ·DatePattern='.'yyyy-ww:每周滾動一次文件,即每周產生一個新的文件。當然也可以指定按月、周、天、時和分。即對應的格式如下:
          1)'.'yyyy-MM: 每月
          2)'.'yyyy-ww: 每周
          3)'.'yyyy-MM-dd: 每天
          4)'.'yyyy-MM-dd-a: 每天兩次
          5)'.'yyyy-MM-dd-HH: 每小時
          6)'.'yyyy-MM-dd-HH-mm: 每分鐘
          ★PatternLayout 選項
          ·ConversionPattern=%m%n :指定怎樣格式化指定的消息。
          ★HTMLLayout 選項
          ·LocationInfo=true:默認值是false,輸出java文件名稱和行號
          ·Title=my app file: 默認值是 Log4J Log Messages.
          ★XMLLayout 選項
          ·LocationInfo=true:默認值是false,輸出java文件和行號
          現在來看一下我們完整的第一個配制文件:
          ========================================================================================
          log4j.rootLogger = INFO,F1,F2

          log4j.appender.F1=org.apache.log4j.ConsoleAppender
          log4j.appender.Threshold=DEBUG
          log4j.appender.F1.Target=System.out
          log4j.appender.F1.layout=org.apache.log4j.PatternLayout
          log4j.appender.F1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n

          log4j.appender.F2=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.F2.File=c:/logs/log.xml
          log4j.appender.F2.DatePattern=yyyyMMdd-HH'.xml.back'
          log4j.appender.F2.layout=org.apache.log4j.xml.XMLLayout
          ========================================================================================
          編段代碼看看效果
          ========================================================================================
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          public class Main{
          private static Log log = LogFactory.getLog(Main.class);
          public static void main(String[] args) throws Exception{
          log.info("info");
          log.debug("debug");
          log.warn("warn");
          log.error("error");
          }

          }
          ========================================================================================
          運行效果
          ========================================================================================
          2007-04-20 12:36:22,531 [cn.yyun.test.Main]-[INFO] info
          2007-04-20 12:36:22,531 [cn.yyun.test.Main]-[WARN] warn
          2007-04-20 12:36:22,531 [cn.yyun.test.Main]-[ERROR] error
          ========================================================================================
          并且在c:/logs/下有log.xml生成,里邊的內容為:
          ========================================================================================
          <log4j:event logger="cn.yyun.test.Main" timestamp="1177043782531" level="INFO" thread="main">
          <log4j:message><![CDATA[info]]></log4j:message>
          </log4j:event>

          <log4j:event logger="cn.yyun.test.Main" timestamp="1177043782531" level="WARN" thread="main">
          <log4j:message><![CDATA[warn]]></log4j:message>
          </log4j:event>

          <log4j:event logger="cn.yyun.test.Main" timestamp="1177043782531" level="ERROR" thread="main">
          <log4j:message><![CDATA[error]]></log4j:message>
          </log4j:event>
          ========================================================================================
          仔細看一下會發現,雖然我們在代碼里寫了log.debug("debug")但是debug并沒有出現在log中,這是因為我們配置文件中,定義了log的等級為INFO,debug的等級小于info,所以不會顯示,而warn,error的大于info,所以也會被顯示出來


          2.根據package生成不同的log文件
          ⑴配置
          log4j.logger.cn.yyun.test.abc=INFO,abc2,abc1

          log4j.appender.abc2=org.apache.log4j.ConsoleAppender
          log4j.appender.abc2.layout=org.apache.log4j.PatternLayout
          log4j.appender.abc2.layout.ConversionPattern=abc:[%p] %m%n

          log4j.appender.abc1=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.abc1.File=C:/logs/abc.log
          log4j.appender.abc1.DatePattern='.'yyyyMMdd
          log4j.appender.abc1.layout=org.apache.log4j.PatternLayout
          log4j.appender.abc1.layout.ConversionPattern=%d %r [%t] %5p - %m%n

          log4j.logger.cn.yyun.test.def=INFO,def
          log4j.appender.def=org.apache.log4j.ConsoleAppender
          log4j.appender.def.layout=org.apache.log4j.PatternLayout
          log4j.appender.def.layout.ConversionPattern=def: [%p] %m%n

          把logger.cn.yyun.test.abc換成需要的package就可以了(整個log4j配制文件中只有這些就可以了 )。但是這樣會有另一個問題,如果cn.yyun.test.Main這個類中,如果有log操作,會報告:log4j:WARN No appenders could be found for logger (cn.yyun.test.Main).所以要加上log4j.rootCategory=INFO,F1 這樣所有的log都會被紀錄了。。但是這樣又做之后:cn.yyun.test.def里的log,會同時出現在def和F1中,cn.yyun.test.abc里的log,會同時出現在abc1,abc2和F1中。。。。。所以定義的時候一定要規劃好。
          ⑵制定package的log等級
          log4j.logger.org.hibernate=DEBUG


          模式字符串簡介:
            %c:Category名稱。還可以使用%c{n}的格式輸出Category的部分名稱,其中n為正整數,輸出時會從Category名稱的右側起查n個".",然后截取第n個"."右側的部分輸出,例如Category的名稱為"x.y.z",指定格式為"%c{2}",則輸出"y.z"。
            %C:輸出信息時Category所在類的名稱,也可以使用%C{n}的格式輸出。
            %d:輸出信息的時間,也可以用%d{FormatString}的格式輸出,其中FormatString的值請參考TTCCLayout的setDateFormat方法,但NULL和RELATIVE在%d中無法使用。
            %F:輸出信息時Category所在類文件的名稱。
            %l:輸出信息時Category所在的位置,使用"%C.%M(%F:%L)"可以產生同樣的效果。
            %L:輸出信息時Category在類文件中的行號。
            %m:信息本身。
            %M:輸出信息時Category所在的方法。
            %n:換行符,可以理解成回車。
            %p:日志級別。
            %r:輸出信息所用的時間,以毫秒為單位。
            %t:當前線程。
            %x:輸出和當前線程相關的NDC信息。
            %X:輸出與當前現成相關的MDC信息。
            %%:輸出%。
          此外,還可以在%與模式字符之間加上修飾符來設置輸出時的最小寬度、最大寬度及文本對齊方式,例如:
            %30d{DATE}:按當前所在地區顯示日期和時間,并指定最小寬度為30,當輸出信息少于30個字符時會補以空格并右對齊。
            %-30d{DATE}:也是按當前所在地區顯示日期和時間,指定最小寬度為30,并在字符少于30時補以空格,但由于使用了"-",因此對齊方式為左對齊,與默認情況一樣。
            %.40d{DATE}:也是按當前所在地區顯示日期和時間,但指定最大寬度為40,當輸出信息多于40個字符時會將左邊多出的字符截掉。此外,最大寬度只支持默認的左對齊方式,而不支持右對齊。
            %30.40d{DATE}:如果輸出信息少于30個字符就補空格并右對齊,如果多于40個字符,就將左邊多出的字符截掉。
            %-30.40d{DATE}:如果輸出信息少于30個字符就補空格并左對齊,如果多于40個字符,就將左邊多出的字符截掉。
          re: Java開源 Jsp標簽庫 蘆葦 2007-11-09 13:25  
          JSP 標簽庫
          2007-06-20 13:50

          displytag

          與Struts結合使用最出名的一個tag主要是顯示表格數據很漂亮、完善。

          cewolf tag

          用來在web上顯示復雜圖形報表的一個jsp tag。

          Loading Tab

          當一個復雜的操作可以加載比較長的時間時,用這個tag。

          DbForms

          DbForms!它是一個基于 Java (Servlet,JSP/Taglib)的快速應用程序開發環境,可以幫助開發人員快速建造基于Web的數據庫應用程序。

          Jakarta Taglibs

          Jakarta Taglibs 是為JSP定制標簽庫和相關的項目提供的一個開源倉庫,如 TagLibraryValidator類,和對頁面生成工具的擴展來支持標簽庫。Jakarta Taglibs 也包括了對JSP Standard Tag Library (JSTL)的參考實現。這個實現基于項目標準。目前,在Jakarta Taglibs 中沒有其它標簽庫代表了Java Community Process (JCP) 標準。

          EasyLDAP

          LDAP標簽庫為JSP程序員和Web頁面設計者提供了最容易的方法來執行任意的LDAP操作。

          WebJMX

          WebJMX標簽庫項目可以控制你的JMX 接口。WebJMX 這個標簽庫項目的目的是生成一個JSP標簽庫,可以讓有技巧的JSP開發人員為JMX生成一個可定制的、規范的、基于Web的界面。

          JPivot

          JPivot - 是一個JSP 自定制的標簽庫,可以繪制一個OLAP表格和圖表。用戶可以執行典型的OLAP導航,如下鉆,切片和方塊。它使用Mondrian 作為其OLAP服務器。

          JSP Tree Tag

          JSP Tree Tag是一個顯示樹型結構jsp標簽,它只把需要顯示的部分送到客戶瀏覽器。

          Google Tag Library

          該標記庫和 Google 有關。使用該標記庫,利用 Google 為你的網站提供網站查詢,并且可以直接在你的網頁里面顯示搜查的結果。

          TableTag

          TableTag是類似于DataGrid的Jsp標簽庫。通過java.util.List填充數據。

          uitags

          uitags利用這個開源自定義標簽可以很容易開發出一個友好的用戶界面。

          ValueList

          ValueList利用這個標簽可以進行數據過濾,排序,分頁。而且界面挺漂亮的。

          JCE taglib

          JCE taglib把JCE(Java Cryptographic Extensions)包裝成TagLib并且包含了EL函數。使用這個標簽能夠為jsp應用程序加強安全性。

          Prize Tags

          Prize Tags是一個集許多功能于一身的Jsp標簽庫。其中最受歡迎的Tree Tag,這個Tag可以為不同節點指定不同的圖標,而且可以服務端可以監控客戶端節點的展開,關閉,選中與未選中等事件。除了Tree Tag還有日歷Tag,Icon Tag,Alternate Tag ,Template Tag 等其它的功能。

          Struts-Layout

          Struts -Layout是一個用在Struts的標簽庫.這個強大的標簽庫可以用來顯示面板(panels),輸入框,表格,treeviews, sortable lists,datagrids,popups,日歷等.使用這些標簽可以不用寫HTML代碼,甚至可以不用懂得HTML.這個項目還提供一個 Eclipse下的插件Kiwi幫助使用Struts和Struts-Layout來開發Jsp頁面.以下是一張例圖:

          JImageTaglib

          JImageTaglib是一個用在J2EE Web應用程序的Java標簽庫.它用來在服務端生成與處理圖片然后再反饋到JSP頁面.可以過濾(filtering)圖片,調整圖片文件大小,生成條形碼等.

          uitags

          uitags是一個開源的JSP custom-tag庫.它讓開發友好的用戶界面變得簡單.

          AWTaglib

          AWTaglib是一個Jsp標簽可用于創建網格(grid)控件.它還提供一些額外的功能可以把網格中的數據導出為XLS,PDF和CSV(利用JasperReports來實現)并能與Struts框架相結合.

          eXtremeTable

          eXtremeTable是一個可擴展的用于以表格的形式來顯示數據的一組JSP標簽庫.

          Ditchnet JSP Tabs Taglib

          這是一個可用來開發多頁選項板(Tabbed Pane)的簡單標簽。以下是一個Demo:
          <tab:tabContainer id="foo-bar-container">

          <tab:tabPane id="foo" tabTitle="Foo!">
          Foo is cool!
          </tab:tabPane>

          <tab:tabPane id="bar" tabTitle="Bar!">
          <c:out value="Bar is cooler!" />
          </tab:tabPane>

          </tab:tabContainer>

          jpa-taglib

          jpa-taglib為使用Java Persistence API提供一個JSP標簽庫。這個標簽庫定義了六個標簽涉及一些普通的數據存取任務。

        1. em, 獲取一個EntityManager
        2. tx, 事務定界
        3. persist, 通過當前EntityManager來把對象持久化
        4. remove, 從數據存儲中移除去對象
        5. find, 通過一個給定的主關鍵字來查找對象
        6. refresh, 刷新對象的內容
        7. UI Widgets Tags

          這組JSP標簽包含了一些常用的UI構件(wizzard, tree, progressBar, list, comboBox和titled panel)。AJAX技術也被盡可能地運用到其中。

          FormView

          FormView 標簽能夠根據狀態(新增,查看,修改,刪除操作)和表單的屬性(最大長度,是不是Date或是否必填等)來控制Form中的表單到底是要修飾成READ- ONLY或還是READ-WRITE。因此利用FormView我們就可以在同一JSP頁面中很簡潔得實現CRUD(CREATE,UPDATE, READ,DELETE)操作而無需多個JSP頁面或復雜的條件判斷。它看起來類似于struts-layout,但是FormView不僅能夠控制簡單 的HTML input而且還能夠控制任何能生成HTML input的JSP標簽(如struts的html:text標簽,也可以是自己開發的標簽)。

          Google:maps JSP Taglibrary

          利用Google:maps JSP標簽庫就能夠在你的Web站點上實現GoogleMaps的所有功能而且不需要javascript或AJAX編程。它還能夠與JSTL相結合生成數據庫驅動的動態Maps。

          dt-Source

          dt-Source這個標簽庫讓Displaytag標簽能夠在JSP頁面中直接調用數據源(Hibernate,JDBC等)中的數據。dt-Source基于Spring框架開發。

          MicroNova YUZU

          MicroNova YUZU開源基于EL的JSP標簽庫。這是一個增強的JSTL(兼容JSP1.2與JSP 2.0)。

          JSControlsTags

          JSControlsTags 這個JSP標簽庫提供了一些基于Ajax(Prototype.js/scriptaculous.js)技術的Web UI控件(Autocomplete,Slider/AjaxSlider,Treeview,Swap)。JSControlsTags利用JSON來 在服務器與客戶端之間傳遞信息。

          pack:tag

          pack: tag是一個用于壓縮靜態資源的JSP標簽庫。它能夠壓縮JavaScript或CSS并緩存到內存或文件中。壓縮算法可針對不同資源類型進行擴展。擴展 使用策略設計模式實現。利用pack:tag壓縮靜態資源:能夠減少帶寬;加速客戶端裝載時間;混淆內容和資源名稱。解決JavaScript文件瀏覽器 緩存問題(將HashCode成新的資源名稱)。

          re: 人民幣大寫轉換[未登錄] 蘆葦 2007-10-29 08:35  
          @QQ745224544

          不客氣,這是轉別人的文章,我同樣感激原創作者!

          關鍵字:   GRASP Java 軟件模式    
           

          當我們分析清楚客戶需求設計出用例模型以后,當我們分析清楚客戶的業務環境制作出領域模型以后,當我們綜合用例模型、領域模型和我們的聰明才智設計出一個又一個的類和它們各自的方法以后,當就在一切都準備就緒只欠東風的關鍵時刻,一個對象發出了撕心裂肺的怒吼——誰來創建我?!!!一個對象,不管擁有多么強大的功能,不管進行了多么精巧的設計,如果不能被創建,就如同韓信不能做將軍,孫臏不能當軍師,勾踐不能回越國,劉備不能得荊州,一切一切的雄才武略都如廢紙一張。既然“創建”對于對象如此重要,我們就來好好探討一下GRASP3.           當我們完成了用例模型、領域模型、對象分析的設計,初步完成了對象設計和職責分配的工作,開始進一步細化的時候,一個我們不得不考慮的問題就擺在我們的面前——誰來創建這些對象?也許現在的你會覺得好笑,這也是問題嗎?在軟件實際開發過程中,誰需要使用某個對象,就去創建它就行了,有什么好討論的。但是,我不得不說的是,如果你只是漫不經心地想要隨意開發一套軟件系統,僅僅是完成自己工作而已,你完全不用考慮創建對象的問題。然而如果你希望開發一套高質量的、低耦合的、封裝性和復用性高的軟件系統,你必須得認真考慮這個問題。為什么呢?因為系統中如果一個對象A那么為了降低系統耦合,提高系統的清晰度、封裝性和可復用性,應該有一些通用的原則,以用于對象職責分配中,關于“創建對象”這類職責的分配。這些原則的描述就在GRASP1)   創建者模式的描述

          如果以下條件之一為真(越多越好),則將創建類A如果有以上多個選項適用,通常首先條件1

          2)   何時使用

          在理解創建者模式的時候,我認為一個首先必須理解的問題是,在軟件項目的整個過程中,它應該是在什么階段使用。一個網友曾經發帖問我,他不清楚GRASP3)   為什么

          我們做事往往有個習慣,凡事問個為什么。前面我提到,使用創建者模式的主要目的是可以降低系統的耦合。那么,我們在使用創建者模式的這幾個建議的時候是如何降低耦合的呢?這一直是困擾了我很久的一個疑問,Craig Larman創建者模式告訴我們,如果系統中存在包含者容納被包含者,或整體聚集部分,則包含者往往是被包含者的最佳創建者,整體往往是部分的最佳創建者。為什么呢?首先,這樣的設計易于理解,可讀性強。為什么這么說呢,我們用我們常見的單據與單據明細來說明吧。一張單據有多條單據明細,這些單據明細聚集于單據中,是單據的一個部分。對于某張單據,我們只有去填寫這張單據,才會去填寫它的明細。同樣,我們要查看和修改這張單據的明細,首先肯定是找到這張單據。以上這些是我們在實際生活中大家都認同的管理單據的方式。GRASP盡管包含者往往是被包含者的最佳創建者,整體往往是部分的最佳創建者,但是在一個軟件系統中,并不是所有類都有它的包含者或者整體。如果沒有,誰應當創建它呢?記錄者當然是另一個可以考慮的人選。倉庫管理員管理進出庫是ERP如果我們正在設計的軟件類也沒有記錄者,這可如何是好?具有創建這個類所需數據的那個類可以考慮,那個類就是信息專家(什么是“信息專家”,我會在以后對信息專家模式的文章中詳細描述)。在我們的設計過程中,很多類的創建是需要一些初始化數據的。最典型的就是我們的vo如果以上方法還不行,那我們就只有找使用者了。尋找使用者是我們創建類最常用的一種方法,但它的缺點也非常明顯。正如前面我描述的,我們系統中對某個軟件類的使用可能分布到系統的各個角落。當我們因為某個需求需要修改這個類的時候,我們根本不知道誰在使用它。正因為如此,這樣的修改變得如夢魘一般,不斷地搜索,不斷地修改。我們前面說過,合理的軟件構造是為了使我們的變更代價最小,而這樣的變更將使我們的代價太大了,也許一個不經意的變更錯誤將造成我們的系統中一個意想不到的地方發生異常。故我們變更后測試的代價也就因此而增大。總之,尋找使用者作為創建者是我們業務分析階段最后的終極選擇。

          4)   創建者模式是原則,不是準則

          “創建者模式是原則,不是準則”難道“原則”和“準則”還有不同嗎?當然。創建者模式是原則,所以我們在業務分析階段應當盡量遵守。但創建者模式不是準則,因為并非我們的所有軟件類都必須遵守。為什么這么說呢?隨著項目的進行,我們的分析設計就不再停留在業務的分析上,各種具體的框架和技術將不斷引進項目中,這時對象的創建就不一定符合創建者模式。比如,為了提高系統的性能和可維護性、更好地處理對象的創建與回收等復雜的問題,我們常常把對象的創建交給工廠,如spring

          總之,合理地創建對象可以有效的提供可讀性、降低耦合度、提高系統的封裝性和可移植性,我們應當引起重視。


          關鍵字:   高內聚 Java 軟件工程 軟件模式    
          在上一章(原創)一個優秀軟件開發人員的必修課:GRASP(2)低耦合中我聊了聊低耦合,今天我想再聊聊與低耦合休戚相關、GRASP的另一個重要的模式:高內聚。

          2.           高內聚是另一個普遍用來評判軟件設計質量的標準。內聚,更為專業的說法叫功能內聚,是對軟件系統中元素職責相關性和集中度的度量。如果元素具有高度相關的職責,除了這些職責內的任務,沒有其它過多的工作,那么該元素就具有高內聚性,反之則為低內聚性。高內聚要求軟件系統中的各個元素具有較高的協作性,因為在我們在完成軟件需求中的一個功能,可能需要做各種事情,但是具有高內聚性的一個元素,只完成它職責內的事情,而把那些不在它職責內的事情拿去請求別人來完成。這就好像,如果我是一個項目經理,我的職責是監控和協調我的項目各個階段的工作。當我的項目進入需求分析階段,我會請求需求分析員來完成;當我的項目進入開發階段,我會請求軟件開發人員來完成;當我的項目需要測試的時候,我會請求測試人員。。。。。。如果我參與了開發,我就不是一個高內聚的元素,因為開發不是我的職責。

           

          我們的項目為什么要高內聚呢?我覺得可以從可讀性、復用性、可維護性和易變更性四個方面來理解。

          1一個人寫文章、講事情,條理清晰才能易于理解,這同樣發生在讀寫軟件代碼上。如果一堆代碼寫得一團亂麻,東一個跳轉西一個調用,讀它的人會感覺非常頭疼。這種事情也許一直在寫程序的你我都曾經有過經歷。如果一段程序條理非常清晰,每個類通過名稱或說明都能清楚明白它的意義,類的每個屬性、函數也都是易于理解的它所應當完成的任務和行為,這段程序的可讀性必然提高。在軟件產業越來越密集,軟件產業中開發人員協作越來越緊密、分工越來越細的今天,軟件可讀性的要求相信也越來越為人們所重視。

          2在軟件開發中,最低等級的復用是代碼拷貝,然后是函數的復用、對象的復用、組件的復用。軟件開發中最懶的人是最聰明的人,他們總是想到復用。在代碼編寫的時候突然發現某個功能是曾經實現過的功能,直接把它拷貝過來就ok在前面《如何在struts+spring+hibernate的框架下構建低耦合高內聚的軟件》中我提到,我們現在的軟件是在不斷變更的,這種變更不僅來自于我們的客戶,更來自于我們的市場。如果我們的軟件通過變更能及時適應我們的市場需求,我們就可以在市場競爭中獲勝。如何能及時變更以適應我們的市場呢,就是通過調整軟件的結構,使我們每次的變更付出的代價最小,耗費的人力最小,這種變更才最快最經濟。高內聚的軟件,每個系統、模塊、類的任務都高度相關,就使每一次的變更涉及的范圍縮小到最小。比如評審表發生了變更,只會與評審表對象有關,我們不會去更改其它的對象。如果我們能做到這一點,我們的系統當然是可維護性好、易變更性好的系統。

          那么,我們如何做到高內聚呢?就拿前面我提到的評審項目舉例。我現在要為“評審表”對象編寫一段填寫并保存評審表的代碼。評審表對象的職責是更新和查詢評審表的數據,但是在顯示一個要填寫的評審表的時候,我需要顯示該評審計劃的名稱、該評審計劃有哪些評審對象需要評審。現在我如何編寫顯示一個要填寫的評審表的代碼?我在評審表對象的這個相應的函數中編寫一段查詢評審計劃和評審對象的代碼嗎?假如你這樣做了,你的代碼就不是高內聚的,因為查詢評審計劃和評審對象的數據不是它的職責。正確的方法應當去請求“評審計劃”對象和“評審對象”對象來完成這些工作,而“評審表”對象只是獲取其結果。

          另外,如果一個對象要完成一個雖然在自己職責范圍內,但過程非常復雜的任務時,也應當將該任務分解成數個功能相對獨立的子函數來完成。我曾經看見一個朋友寫的數百行的一個函數,讓人讀起來非常費勁。同時這樣的函數中一些相對獨立的代碼,本可以復用到其它代碼中,也變成了不可能。所以我給大家的建議是,不要寫太長的函數,超過一百行就可以考慮將一些功能分解出去。

          與“低耦合”一樣,高內聚也不是一個絕對,而是一個相對的指標,應當適當而不能過度。正如我們在現實生活中,如果在一個十來人的小公司,每個人的分工可能會粗一些,所分配的職責會廣一些雜一些,因為其總體的任務少;而如果在一個一兩百人的大公司,每個人的分工會細一些,所分配的任務會更加專一些,因為總體任務多,更需要專業化的分工來提高效率。軟件開發也是一樣,如果“評審計劃”對象完成的業務功能少,并且不復雜,它完全可以代理它的子表“評審對象”和“評審者”的管理。但是“評審計劃”對象需要完成的“對評審計劃表的管理”這個基本職責包含的業務功能繁多或者復雜,它就應當將“對評審對象表的管理”交給“評審對象”對象,將“對評審者表的管理”交給“評審者”對象。同樣,高內聚的可維護性好、易變更性好只能是一個相對的指標。如果一個變更的確是大范圍的變更,你永遠不可能通過內聚就不進行大范圍的變更了。同時內聚也是要付出代價的,所以你也不必要去為了一個不太可能的變更去進行過度設計,應當掌握一個度。過度的內聚必將增加系統中元素之間的依賴,提高耦合度。所以“高內聚”與“低耦合”是矛盾的,必須權衡利弊,綜合地去處理。綜上所述,“高內聚”給軟件項目帶來的優點是:可讀性強、易維護和變更、支持低耦合、移植和重用性強。

          一個優秀軟件開發人員的必修課:GRASP(2)低耦合
          我偶然在google或yahoo這樣的搜索引擎搜索GRASP發現,除了國外的網站,國內網站多介紹和討論GoF而很少介紹GRASP,即使這少量的文章也講解非常粗略。個人認為作為優秀的開發人員,理解GRASP比GoF更重要,故寫此文章。前面我在《  1.           “低耦合”這個詞相信大家已經耳熟能詳,我們在看spring哪些是耦合呢?

           

          1幸運的是,目前已經有大量的框架幫助我們降低我們系統的耦合度。比如,使用struts但是,作為優秀的開發人員,僅僅依靠框架提供的降低軟件耦合的方法是遠遠不夠的。根據我的經驗,以下一些問題我們應當引起注意:

          1)   根據可能的變化設計軟件

          我們采用職責驅動設計,設計中盡力做到“低耦合、高內聚”的一個非常重要的前提是,我們的軟件是在不斷變化的。如果沒有變化我們當然就不用這么費勁了;但是如果有變化,我們希望通過以上的設計,使我們在適應或者更改這樣的變化的時候,付出更小的代價。這里提供了一個非常重要的信息是,我們努力降低耦合的是那些可能發生變更的地方,因為降低耦合是有代價的,是以增加資源耗費和代碼復雜度為代價的。如果系統中某些元素不太可能變更,或者降低耦合所付出的代價太大,我們當然就應當選擇耦合。有一次我試圖將我的表現層不依賴于struts2)   合理的職責劃分

          合理的職責劃分,讓系統中的對象各司其職,不僅是提高內聚的要求,同時也可以有效地降低耦合。比如評審計劃BUS

          3)   使用接口而不是繼承

          通過對耦合的分析,我們不難發現,繼承就是一種耦合。如果子類A《如何在 struts + spring + hibernate
          aaa1.JPG
           描述:  
           文件大小:  21 KB
           看過的:  文件被下載或查看 676 次

          aaa1.JPG
          下載

          最后更新:2007-01-31 08:47
          14:51  |   永久鏈接  |   瀏覽 (4062)  |   評論 (8)  |    收藏  |   進入論壇  |  
          評論    共 8 條 發表評論
          silentlakeside     2007-01-22 16:51

          支持一下,我也覺得GRASP很重要,我是在《應用UML與模式》這一書中看到GRASP,從此后我的設計思路基本上就是參照這幾個原則了。我覺得很多設計模式都是從GRASP發展而來。

          fangang     2007-01-22 17:02

          是的,正因為它的重要,我希望通過這篇文章,提供一個話題,大家都談談這方面的體會,共同進步

          daoger     2007-01-22 17:53

          文章很好,地方不對!
          發在敏捷開發板塊才合適!

          fangang     2007-01-22 18:57

          daoger 寫道
          文章很好,地方不對!
          發在敏捷開發板塊才合適!
          謝謝指教
          Uranus     2007-05-11 09:28

          說真的,我覺得你這篇文章才是寫得最好的(和你的create模式相比,因為create模式中,你可能腦子很清楚,但是寫的語句讓初學者很摸不到頭腦),我個人感覺好像設計模式都是國外人的提出來我們用,我們就缺乏提出思想的人,我們好多同志都是看這個好就拿過來用,根本說不出好在哪。你這個能力很強,希望將來在你的文章里面能多看到這種模式這樣做的理由是什么

          Uranus     2007-05-11 18:00

          對了,我還想請教你一個問題呢,我之前聽一個人說過,不管是gof的設計模式還是GRASP設計模式,最終的目的就是解耦合,不知道你怎么看這句話的,是否可以據個例子?

          fangang     2007-05-14 10:06

          謝謝Uranus的支持,實際上我們學習設計模式就是要思考它為什么好,我們為什么要用它,它還有沒有問題需要修改。最近我正在著手寫《“單例”改變了我們的設計模式》,詳細描述在單例模式大行其道的今天,GoF中的許多模式都需要改改了。至于你的那個問題,我已經寫到我的博客《設計模式GRASP和GoF是怎樣解決耦合的問題》中了。

          JavaVM     2007-05-14 11:54

          期待你的《“單例”改變了我們的設計模式》

          re: SVN配置 蘆葦 2007-10-16 11:17  
           Subversion安裝記錄     CSDN Blog推出文章指數概念,文章指數是對Blog文章綜合評分后推算出的,綜合評分項分別是該文章的點擊量,回復次數,被網摘收錄數量,文章長度和文章類型;滿分100,每月更新一次。

          程序版本:
             Subversion:1.3.2(官方下載
             SmartSVN:2.0.6(官方下載)本地下載:

          安裝過程:
           1、安裝Subversion。這個過程很簡單,默認安裝就可以了,沒什么可說的。
           2、創建Repository(可以理解為代碼倉庫,其實除了放代碼,其他的也可以放的^_^):
             通過CMD進入命令行模式,輸入下列命令,在d:\SubversionWorkspace\pub這個目錄下建立Repository:
          svnadmin create --fs-type fsfs d:\SubversionWorkspace\pub

          注:之所以選擇fsfs格式,參考下面的文檔中的相關資料
          相關文檔資料:
          $ svnadmin create --fs-type fsfs /path/to/repos
          $ svnadmin create --fs-type bdb /path/to/other/repos

          Warning
          Do not create a Berkeley DB repository on a network share—it cannot exist on a remote filesystem such as NFS, AFS, or Windows SMB. Berkeley DB requires that the underlying filesystem implement strict POSIX locking semantics, and more importantly, the ability to map files directly into process memory. Almost no network filesystems provide these features. If you attempt to use Berkeley DB on a network share, the results are unpredictable—you may see mysterious errors right away, or it may be months before you discover that your repository database is subtly corrupted.

          If you need multiple computers to access the repository, you create an FSFS repository on the network share, not a Berkeley DB repository. Or better yet, set up a real server process (such as Apache or svnserve), store the repository on a local filesystem which the server can access, and make the repository available over a network. Chapter 6, Server Configuration covers this process in detail.

           3、添加用戶并設置權限。沒有做詳細研究,請直接參考下面的資料:
          轉自:http://www.dlog.cn/html/di...

          獨立運行的Subversion權限設置很簡單,首先打開snvserve.conf,去掉下面一行的注釋

          authz-db = authz

          然后打開同一目錄下的authz這個文件,這個文件便是整個權限控制的核心,先來看一個例子:

          [groups]
          dev-group = liudong,xfliang
          design-group = newidea

          [/]
          @dev-group = rw
          @design-group = r
          * =

          [/doc]
          @design-group = rw

          [/webapp]
          @design-group = rw

          接下來我給大家解釋一下這個文件,相信就可以明白Subversion如何來做權限控制的了。

          首先我定義了兩個組,一個開發組(dev-group),一個設計組(design-group),接下來我讓dev-group對整個目錄有讀寫的權限,而design-group只有讀權限。但是接下來的兩個子目錄design-group就有讀寫權限,也就是說設計組可以讀取整個項目,但只能修改doc以及webapp這兩個子目錄。

          *= 這行表示其他人不能讀寫。當然也可以直接指定某個用戶,例如我想讓liudong這個用戶可以讀寫webapp目錄,那設置如下:

          [/webapp]
          @design-group = rw
          liudong = rw

          另外有一點注意的是,修改這個文件不需要重新啟動svn服務,這點太棒了。

          下面是詳細的說明Subversion自帶的authz樣例中的注釋

          ### This file is an example authorization file for svnserve.
          ### Its format is identical to that of mod_authz_svn authorization
          ### files.
          ### As shown below each section defines authorizations for the path and
          ### (optional) repository specified by the section name.
          ### The authorizations follow. An authorization line can refer to a
          ### single user, to a group of users defined in a special [groups]
          ### section, or to anyone using the '*' wildcard.  Each definition can
          ### grant read ('r') access, read-write ('rw') access, or no access
          ### ('').

           4、將Subversion注冊為系統。將SVNServise拷貝到Subversion的安裝目錄下的bin目錄(我這里為:C:\Program Files\Subversion\bin)。然后在CMD中轉到剛剛那個目錄,運行下列命令:
          svnserve -d -r d:\SubversionWorkspace\

          注:以下是svnserve的命令選項
          svnserve [選項]
          有效選項:
           -d [--daemon]            : 后臺模式
           --listen-port 參數     : 監聽端口(后臺模式)
           --listen-host 參數     : 監聽主機名或IP地址(后臺模式)
           --foreground             : 在前臺運行(調試時有用)
           -h [--help]              : 顯示這個幫助
           --version                : 顯示版本信息
           -i [--inetd]             : inetd 模式
           -r [--root] 參數       : 服務根目錄
           -R [--read-only]         : force read only, overriding repository config file
           -t [--tunnel]            : 隧道模式
           --tunnel-user 參數     : 隧道用戶名(模式是當前用戶UID的名字)
           -X [--listen-once]       : 監聽一次(調試時有用)

           5、用SmartSVN連接剛剛建好的服務器  

          下載文件 (已下載 22 次)

             SVNServise:將Subversion注冊為系統服務的東東。本地下載:
          下載文件 (已下載 19 次)

             TortoiseSVN:1.4.0 RC1(官方下載
          安裝環境:
             Windows XP-SP2-en


          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1495108

          re: SVN配置 蘆葦 2007-10-16 11:16  
           Windows下安裝和配置SVN Server     CSDN Blog推出文章指數概念,文章指數是對Blog文章綜合評分后推算出的,綜合評分項分別是該文章的點擊量,回復次數,被網摘收錄數量,文章長度和文章類型;滿分100,每月更新一次。
          1.     配置環境
          Windows 2003 Server with SP1
          Apache HTTP Server v2.0.55
          Subversion v1.4.2
          2.     安裝 Apache HTTP Server
          將安裝目錄修改為C:\Apache Group
          默認是安裝到C:\Program Files\Apache Group目錄下
          安裝后的目錄結構如下:
          C:\Apache Group\Apache2\bin\
          C:\Apache Group\Apache2\conf\
          ......
          3.     安裝 Subversion
              這里使用zip包,解壓到C盤,然后將C:\svn-win32-1.4.2\bin添加環境變量PATH中。
              解壓后的目錄結構如下:
              C:\svn-win32-1.4.2\bin\
              C:\svn-win32-1.4.2\iconv\
              ......
          l        將C:\svn-win32-1.4.2\bin目錄下的mod_dav_svn.so和mod_authz_svn.so復制到C:\Apache Group\Apache2\modules目錄下。
          l        將C:\svn-win32-1.4.2\bin目錄下的所有DLL文件復制到C:\Apache Group\Apache2\bin目錄下。注意在復制DLL文件時最好停掉Apache。
          l        用文本編輯器打開C:\Apache Group\Apache2\conf\httpd.conf文件找到以下兩行
              #LoadModule dav_module modules/mod_dav.so
              #LoadModule dav_fs_module modules/mod_dav_fs.so
              去掉前面的#,然后所有LoadModule的后面添加下面兩行
              LoadModule dav_svn_module modules/mod_dav_svn.so
              LoadModule authz_svn_module modules/mod_authz_svn.so
              然后重起Apache
          4.     建庫
              假設所有庫的根目錄是F:\svn,并且要建一個名為testrepos的庫,打開DOS窗口,進入到F:\svn目錄下,然后輸入svnadmin create f:\svn\testrepos
          命令執行完后f:\svn\testrepos目錄下會生成一些目錄和文件。然后在C:\Apache Group\Apache2\conf\httpd.conf文件的最后添加下面內容,并重起Apache
              <Location /svn>
              DAV svn
              SVNParentPath f:\svn
              </Location>
          5.     測試
          打開DOS窗口,進入一個臨時目錄F:\temp下
          svn co http://localhost/svn/testrepos
          正確執行后會顯示"Checked out revision 0."的信息。
          6.     導入
          在一個臨時文件夾(比如C:\temp)下建立如目錄
          trunk
          branches
          tags
          在DOS命令行下進入C:\temp目錄,然后執行
          svn import . http://localhost/svn/testrepos -m "Initial repository"
          執行成功的話會提示提交后的修訂版本為1。
          7.     關于庫的建立
          建議為會每一個項目建立一個庫,例如:
          F:\svn\project1
          F:\svn\project2
          再為每個庫建立如下結構(Subversion官方手冊建議的目錄結構)
          F:\svn\project1\trunk      這個目錄用來存放正在進行開發的項目代碼
          F:\svn\project1\branches   這個目錄用來存放正在開發中的版本分支
          F:\svn\project1\tags       這個目錄用來存放不再變動的分支
           

          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1495115

          re: Hibernate 3 Annotations 進階 蘆葦 2007-10-08 13:53  
          WEB-INF/classes/hibernate.properties
          hibernate.hbm2ddl.auto=create
          hibernate.hbm2ddl.auto=create
          WEB-INF/classes/import.sql
          源碼復制打印
          INSERT INTO mytable(id,name) values(1,'name1');
          INSERT INTO mytable(id,name) values(2,'name2');
          INSERT INTO mytable(id,name) values(3,'name3');
          INSERT INTO mytable(id,name) values(1,'name1');
          <br/> INSERT INTO mytable(id,name) values(2,'name2');
          <br/> INSERT INTO mytable(id,name) values(3,'name3');
          當WEB運行時,hibernate會自動重新生成表結構并插入import.sql里的那三條記錄.
          re: Hibernate 3 Annotations 進階 蘆葦 2007-10-08 13:53  
          在hibernate3中可以自動建數據庫及自動導入數據.在hibernate.properties文件里加入:
          hibernate.hbm2ddl.auto=create
          就可以自動建表結構
          設hibernate.hbm2ddl.auto為update/create-drop/create其中一種都會改變表結構,如果同時在classpath中寫一個/import.sql文件,里包含了數據內容的insert等,那么hibernate3在啟動時就會執行import.sql的內容。
          re: 在DB2中創建第一個觸發器 蘆葦 2007-07-24 15:59  
          sequence是一種方法。也可以用用indentity列
          CREATE TABLE table (col1 INT,
          col2 DOUBLE,
          col3 INT NOT NULL GENERATED ALWAYS AS IDENTITY
          (START WITH 100, INCREMENT BY 5))
          re: 在DB2中創建第一個觸發器 蘆葦 2007-07-24 15:52  
          我自己曾用到的:
          --建觸發器
          --
          修改登錄人信息觸發
          create trigger db2admin.t_userlogin_upd after update on db2admin.USER_LOGIN referencing new as n  old AS o for each row
          begin atomic
            
          declare TEMP_IBMSNAP_COMMITSEQ bigint;
            
          IF ((n.WORK_ID <> o.WORK_ID) or (n.USER_LOGIN_ID <> o.USER_LOGIN_ID) or (n.CURRENT_PASSWORD <> o.CURRENT_PASSWORD)) THEN      
              
          set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
              
          INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'U', n.PARTY_ID, n.USER_LOGIN_ID , n.CURRENT_PASSWORD , 'CLERK_NAME' , n.WORK_ID , '1' );
                
          UPDATE db2admin.CCD_USER_LDAP SET CLERK_NAME = (select CLERK_NAME from CLERK where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
            
          end if;
          end


          --新增登錄人信息觸發
          create trigger db2admin.t_userlogin_ins after insert on db2admin.USER_LOGIN referencing new as n for each row 
          begin atomic
              
          declare TEMP_IBMSNAP_COMMITSEQ bigint;
              
          set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
             
          INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'I', n.PARTY_ID, n.USER_LOGIN_ID , n.CURRENT_PASSWORD , 'CLERK_NAME' , null , '1');
             
          UPDATE db2admin.CCD_USER_LDAP SET CLERK_NAME = (select CLERK_NAME from CLERK where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
          end

          --修改登錄人姓名或狀態觸發
          create trigger db2admin.t_userinfo_upd after update on db2admin.CLERK referencing new as n  old AS o for each row
          begin atomic
            
          declare TEMP_IBMSNAP_COMMITSEQ bigint;
            
          IF ((n.CLERK_NAME <> o.CLERK_NAME) or (n.CLERK_STATUS <> o.CLERK_STATUS)) THEN         
              
          set TEMP_IBMSNAP_COMMITSEQ = nextval for db2admin.seq_name;
              
          INSERT INTO db2admin.CCD_USER_LDAP VALUES (TEMP_IBMSNAP_COMMITSEQ, 0'U', n.PARTY_ID, 'USER_LOGIN_ID' , 'CURRENT_PASSWORD'  , n.CLERK_NAME , 'WORK_ID''0' );
                
          UPDATE db2admin.CCD_USER_LDAP SET USER_LOGIN_ID = (select USER_LOGIN_ID from USER_LOGIN where PARTY_ID =n.PARTY_ID),CURRENT_PASSWORD=(select CURRENT_PASSWORD from USER_LOGIN where PARTY_ID =n.PARTY_ID),WORK_ID=(select WORK_ID from USER_LOGIN where PARTY_ID =n.PARTY_ID) where IBMSNAP_COMMITSEQ = TEMP_IBMSNAP_COMMITSEQ;
            
          end if;
          end

          --刪除觸發器
          DROP TRIGGER DB2ADMIN.T_USERLOGIN_INS;
          DROP TRIGGER db2admin.T_USERLOGIN_UPD;
          DROP TRIGGER db2admin.T_USERINFO_UPD;
          --創建一個sequence 
          create sequence seq_name start with 1 increment by 1 
          --刪除sequence
          drop sequence seq_name
          re: JAVA版農歷和陽歷相互轉換 蘆葦 2006-11-24 15:58  
          有一個小BUG

          public ChineseEra() {
          int iYear = 1981;
          }


          應該是

          public ChineseEra(){
          iYear = 1981;
          }
          Aspjpeg添加水印完整方法
          Aspjpeg添加水印完整方法
          用ASPJPEG組件制作圖片的縮略圖和加水印


          ASPJPEG是Persits出品的共享軟件,試用期為30天,您可以在這里下載:http://www.persits.com/aspjpeg.exe。最新版本號是1.3
          ASPJPEG是一款功能相當強大的圖象處理組件,用它可以輕松地做出圖片的縮略圖和為圖片加上水印功能。下面簡單介紹一下使用方法:
          您先要執行下載得到的exe文件,安裝該組件
          1、為圖片制作縮略圖

          <% \\\' 建立實例
          Dim Jpeg,Path
          Set Jpeg = Server.CreateObject("Persits.Jpeg")
          \\\' 圖片所在位置
          Path = Server.MapPath("images") & "\\\\clock.jpg"


          \\\' 打開
          Jpeg.Open Path

          \\\' 設置縮略圖大小(這里比例設定為50%)
          Jpeg.Width = Jpeg.OriginalWidth / 2
          Jpeg.Height = Jpeg.OriginalHeight / 2

          \\\' 保存縮略圖到指定文件夾下
          Jpeg.Save Server.MapPath("images") & "\\\\clock_small.jpg"

          \\\' 注銷實例
          Set Jpeg = Nothing
          %>

          <IMG SRC="images/clock.jpg"><P>
          <IMG SRC="images/clock_small.jpg">


          2、為圖片加入水印功能
          <%
          Dim Jpeg
          \\\' 建立實例
          Set Jpeg = Server.CreateObject("Persits.Jpeg")
          \\\' 打開目標圖片
          Jpeg.Open Server.MapPath("images/dodge_viper.jpg")

          \\\' 添加文字水印
          Jpeg.Canvas.Font.Color = &HFF0000\\\' 紅色
          Jpeg.Canvas.Font.Family = "宋體"
          Jpeg.Canvas.Font.Bold = True
          Jpeg.Canvas.Print 10, 10, "Copyright (c) Cnmaya.org"

          \\\' 保存文件
          Jpeg.Save Server.MapPath("images/dodge_viper_framed.jpg")

          \\\' 注銷對象
          Set Jpeg = Nothing
          %>


          上次做過圖片水印,效果很差,沒辦法把圖片弄成背景透明的,用背景透明gif會自動填充成白色。用去掉某種顏色的功能,圖片顏色總是不純,出來的效果斑斑點點。今天靈機一動,把這兩個結合起來,用背景透明的gif,并且抽取水印底色,果然成功了!

          ogvbox.Canvas.Pen.Color = &H000000 \\\'// 邊框的顏色
          ogvbox.Canvas.Pen.Width = 1 \\\'// 邊框的粗細
          ogvbox.Canvas.Brush.Solid = False \\\'// 圖片邊框內是否填充顏色
          ogvbox.DrawImage ogvbox.Width-210, ogvbox.Height-74, Logobox ,0.3,&HFFFFFF \\\'// 加入圖片的位置坐標(添加水印圖片),我用圖片大小減去水印大小,把水印加在右下角。參數順序為:水平坐標,垂直坐標,水印圖片地址,水銀透明度,抽取顏色(&H表示16進制)
          ogvbox.Canvas.Bar 0, 0, ogvbox.Width, ogvbox.Height \\\'// 圖片邊框線的位置坐標和大小
          ogvbox.Save Server.MapPath(imagename) \\\'// 生成文件
          \'//------Pollener.com AspJpeg組件的預覽和水印生成------開始------
          \'創建預覽圖片:call CreateView(原始文件的路徑,預覽文件名及路徑)
          Sub CreateView(imagename,tempFilename)
          \'定義變量。
          Dim PreviewImageFolderName
          Dim ogvbox,objFont
          Dim Logobox,LogoPath
          LogoPath = Server.MapPath("images") & "\\shuiyin.gif" \'//加入圖片所在路徑及文件名(我的是論壇\\images\\shuiyin.gif)。

          Select Case upload_ViewType
          Case 0
          \'---------------------CreatePreviewImage---------------
          set ogvbox = Server.CreateObject("CreatePreviewImage.cGvbox")
          ogvbox.SetSavePreviewImagePath=Server.MapPath(tempFilename) \'預覽圖存放路徑。
          ogvbox.SetPreviewImageSize =SetPreviewImageSize \'預覽圖寬度。
          ogvbox.SetImageFile = trim(Server.MapPath(imagename)) \'imagename原始文件的物理路徑。
          \'創建預覽圖的文件。
          If ogvbox.DoImageProcess=false Then
          Response.write "生成預覽圖錯誤:"& ogvbox.GetErrString
          End If
          Case 1
          \'---------------------AspJpegV1.2---------------
          Set Logobox = Server.CreateObject("Persits.Jpeg")
          \'//建議不要圖片和文字水印同時使用,本代碼為使用圖片水印。
          Logobox.Open LogoPath \'//讀取添加的圖片。

          \'//重新設置圖片的大小。
          Logobox.Width = 186 \'//用做水印的圖片的寬度值(像素)。
          Logobox.Height = 52 \'//用做水印的圖片的高度值(像素)。
          \'//添加水印。
          Set ogvbox = Server.CreateObject("Persits.Jpeg")
          \'//讀取要處理的原文件。
          ogvbox.Open Trim(Server.MapPath(imagename))
          If ogvbox.OriginalWidth<Cint(ImageWidth) or ogvbox.Originalheight<Cint(ImageHeight) Then
          F_Viewname=""
          Set ogvbox = Nothing
          Exit Sub
          Else
          IF ImageMode<>"" and FileExt<>"gif" Then \'//如果將這行改為IF ImageMode<>"" Then則可給上傳的GIF圖片也加上水印,但是那些動畫的GIF在加了水印以后就只剩第一楨了,根據你的需求酌情處理吧。

          \'//關于修改字體及文字顏色的。
          \'//ogvbox.Canvas.Font.Color = &H0000FF \'//水印文字的顏色,&H后面輸入色彩值。
          \'//ogvbox.Canvas.Font.Size = 18 \'//水印文字的大小。
          \'//ogvbox.Canvas.Font.Family = "Arial" \'//水印文字的字體名稱。
          \'//ogvbox.Canvas.Font.ShadowColor = &H000000 \'//水印文字的陰影色彩。
          \'//ogvbox.Canvas.Font.ShadowXoffset = 1 \'//水印文字陰影向右偏移的像素值,輸入負值則向左偏移。
          \'//ogvbox.Canvas.Font.ShadowYoffset = 1 \'//水印文字陰影向下偏移的像素值,輸入負值則向右偏移。
          \'//ogvbox.Canvas.Font.Quality = 3 \'//水印文字的清晰度,從0~4,變換不是很大,建議用2或3。
          \'//ogvbox.Canvas.Font.Bold = True \'//水印文字是否為粗體,True=粗體 False=正常。

          \'ogvbox.Canvas.Print 10, 10, ImageMode \'//水印文字的起始坐標(像素)。
          ogvbox.Canvas.Pen.Color = &H000000 \'//增加水印后圖片的邊框色彩。
          ogvbox.Canvas.Pen.Width = 1 \'//增加水印后圖片的邊框寬度。
          ogvbox.Canvas.Brush.Solid = False \'//邊框內是否填充顏色,你可以試試看值為True時的效果^o^
          ogvbox.DrawImage ogvbox.width-186, ogvbox.height-52, Logobox, 0.5 \'//水印圖片的起始坐標,我這里ogvbox.width-186, ogvbox.height-52,表示圖片在右下角,因為我的圖片寬是186,高是52,所以這樣寫,你可以根據自己的圖片進行調整。0.5是透明度,我這里是半透明,1表示不透明,你也可以試試看0.7或者0.8的效果。
          ogvbox.Canvas.Bar 0, 0, ogvbox.Width, ogvbox.Height \'//水印可用的范圍。我這里表示左上角至右下角,即整張圖片的任意為止都可加水印。
          ogvbox.Save Server.MapPath(imagename) \'//根據以上參數生成增加水印后的圖片文件。
          End If
          ogvbox.Width = ImageWidth
          ogvbox.height = ImageHeight
          \'ogvbox.height = ogvbox.Originalheight*ImageWidth\\ogvbox.OriginalWidth
          ogvbox.Sharpen 1, 120
          ogvbox.Save Server.MapPath(tempFilename) \'//生成增加水印后的圖片的預覽圖片。
          End If
          Set Logobox=Nothing
          \'//------Pollener.com AspJpeg組件的預覽和水印生成------結束------

          re: Java實現漢字轉換為拼音 蘆葦 2006-11-24 15:09  
          c#的漢字轉拼音
          /// <summary>
          /// 獲取一串漢字的拼音聲母
          /// </summary>
          /// <param name="chinese">Unicode格式的漢字字符串</param>
          /// <returns>拼音聲母字符串</returns>
          public static String Convert(String chinese)
          {
          char[] buffer = new char[chinese.Length];
          for(int i=0; i<chinese.Length; i++)
          {
          buffer[i] = Convert(chinese[i]);
          }
          return new String(buffer);
          }

          /// <summary>
          /// 獲取一個漢字的拼音聲母
          /// </summary>
          /// <param name="chinese">Unicode格式的一個漢字</param>
          /// <returns>漢字的聲母</returns>
          public static char Convert(Char chinese)
          {
          Encoding gb2312 = Encoding.GetEncoding("GB2312");
          Encoding unicode = Encoding.Unicode;

          // Convert the string into a byte[].
          byte[] unicodeBytes = unicode.GetBytes(new Char[] {chinese});
          // Perform the conversion from one encoding to the other.
          byte[] asciiBytes = Encoding.Convert(unicode, gb2312, unicodeBytes);

          // 計算該漢字的GB-2312編碼
          int n = (int)asciiBytes[0]<<8;
          n += (int)asciiBytes[1];

          // 根據漢字區域碼獲取拼音聲母
          if (In(0xB0A1,0xB0C4,n)) return 'a';
          if (In(0XB0C5,0XB2C0,n)) return 'b';
          if (In(0xB2C1,0xB4ED,n)) return 'c';
          if (In(0xB4EE,0xB6E9,n)) return 'd';
          if (In(0xB6EA,0xB7A1,n)) return 'e';
          if (In(0xB7A2,0xB8c0,n)) return 'f';
          if (In(0xB8C1,0xB9FD,n)) return 'g';
          if (In(0xB9FE,0xBBF6,n)) return 'h';
          if (In(0xBBF7,0xBFA5,n)) return 'j';
          if (In(0xBFA6,0xC0AB,n)) return 'k';
          if (In(0xC0AC,0xC2E7,n)) return 'l';
          if (In(0xC2E8,0xC4C2,n)) return 'm';
          if (In(0xC4C3,0xC5B5,n)) return 'n';
          if (In(0xC5B6,0xC5BD,n)) return 'o';
          if (In(0xC5BE,0xC6D9,n)) return 'p';
          if (In(0xC6DA,0xC8BA,n)) return 'q';
          if (In(0xC8BB,0xC8F5,n)) return 'r';
          if (In(0xC8F6,0xCBF0,n)) return 's';
          if (In(0xCBFA,0xCDD9,n)) return 't';
          if (In(0xCDDA,0xCEF3,n)) return 'w';
          if (In(0xCEF4,0xD188,n)) return 'x';
          if (In(0xD1B9,0xD4D0,n)) return 'y';
          if (In(0xD4D1,0xD7F9,n)) return 'z';
          return '\0';
          }

          private static bool In(int Lp, int Hp, int Value)
          {
          return ((Value<=Hp)&&(Value>=Lp));
          }

          轉帖自7707(kingfisher)




          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=815541

          re: Java實現漢字轉換為拼音 蘆葦 2006-11-24 15:08  
          根據漢字得到拼音的類庫(三)
          /// <summary>

          /// 存放排好序的漢字-拼音對照字典,格式如下

          /// 漢han

          /// 字zi

          /// 既漢字作為字典的Key,拼音作為value

          /// </summary>

          private SortedDictionary<Char, string> mSortDiction = new SortedDictionary<Char, string>() ;



          private static SpellLib _Instance ;



          /// <summary>

          /// 取漢字拼音類的實例

          /// </summary>

          /// <returns></returns>

          public static SpellLib Instance()

          {

          if (_Instance == null)

          _Instance = new SpellLib();

          return _Instance;

          }



          /// <summary>

          /// 構造函數

          /// </summary>

          private SpellLib()

          {

          BuildSortDiction();

          }



          #region 提供的方法

          /// <summary>

          /// 把給定的字轉化為拼音

          /// </summary>

          /// <param name="word">要轉化的字</param>

          /// <returns>字的拼音</returns>

          /// <example>

          /// string strCode = SpellLib.Instance().GetCodesByWord('字');

          /// </example>

          /// <remarks>如果該字不存在拼音,就返回該字本身</remarks>

          public string GetCodeByWord(Char word)

          {

          if (mSortDiction.ContainsKey(word))

          return mSortDiction[word];

          else

          return word.ToString();

          }

          /// <summary>

          /// 取得字符串第一個字的拼音

          /// </summary>

          /// <param name="word">要轉化的字符串</param>

          /// <returns>字的拼音</returns>

          /// <example>

          /// string strCode = SpellLib.Instance().GetCodesByWord("漢字");

          /// </example>

          /// <remarks>如果第一個字不存在拼音,就返回該字本身</remarks>

          public string GetCodeByWord(string word)

          {

          if (word == null)

          throw new ArgumentNullException("word");



          if (word.Length > 0)

          return GetCodeByWord(word[0]);

          else

          return null;

          }

          /// <summary>

          /// 取得一個字符串中所有字的拼音

          /// </summary>

          /// <param name="sentence"></param>

          /// <returns></returns>

          public string GetCodesByWord(string sentence)

          {

          if (sentence == null)

          throw new ArgumentNullException("sentence");



          bool blAddSpace = false;

          StringBuilder sbResult = new StringBuilder();



          foreach (Char chr in sentence)

          {

          string strCodes = GetCodeByWord(chr) ;



          if (strCodes.Length > 1)

          {

          if (blAddSpace == false)

          {

          sbResult.Append(" ");

          }

          sbResult.Append(strCodes);

          sbResult.Append(" ");

          blAddSpace = true;

          }

          else

          {

          sbResult.Append(strCodes);

          blAddSpace = false;

          }

          }

          return sbResult.ToString();

          }

          /// <summary>

          /// 構造排序字典對象

          /// </summary>

          private void BuildSortDiction()

          {

          // mSortDiction.

          for (int i = 0; i < this.WordList.Length; i++)

          {

          string value = this.CodeList[i];

          string strWord = WordList[i];



          foreach (char key in strWord)

          {

          if (mSortDiction.ContainsKey(key))

          {

          continue;

          }

          else

          {

          mSortDiction.Add(key, value);

          }

          }//end foreach



          }//end for

          }

          /// <summary>

          /// 取得給定拼音的聲母

          /// </summary>

          /// <param name="spell">拼音</param>

          /// <returns>聲母</returns>

          /// <remarks>如果不存在聲母就返回第一個字母,如啊返回a,嗯返回e</remarks>

          public static string GetVoicePart(string spell)

          {

          string strVoicePart = null;

          if (spell.Length == 1)

          {

          strVoicePart = spell;

          }

          else

          {



          char firstChr = spell[0];

          char SecondChr = spell[1];

          strVoicePart = firstChr.ToString();

          if (SecondChr.Equals('h') || SecondChr.Equals('H'))

          strVoicePart += "h";



          switch (strVoicePart.ToLower(System.Globalization.CultureInfo.CurrentCulture))

          {

          case "b":

          case "p":

          case "m":

          case "f":

          case "d":

          case "t":

          case "n":

          case "l":

          case "g":

          case "k":

          case "h":

          case "j":

          case "q":

          case "x":

          case "r":

          case "z":

          case "c":

          case "s":

          case "zh":

          case "ch":

          case "sh":

          break;

          default:

          strVoicePart = firstChr.ToString();

          break;

          }//end switch

          }

          return strVoicePart;

          }

          /// <summary>

          /// 取得給定漢字的聲母部分

          /// </summary>

          /// <param name="word"></param>

          /// <returns></returns>

          /// <example>

          /// string strVoicePart = SpellLib.Instance().GetCodeOfVoicePart("字");

          /// </example>

          /// <remarks>如果不存在聲母就返回第一個字母,如啊返回a,嗯返回e</remarks>

          public string GetCodeOfVoicePart(string word)

          {

          return GetVoicePart(this.GetCodeByWord(word));

          }

          /// <summary>

          /// 取得給定漢字的聲母部分

          /// </summary>

          /// <param name="word"></param>

          /// <returns></returns>

          /// <remarks>如果不存在聲母就返回第一個字母,如啊返回a,嗯返回e</remarks>

          public string GetCodeOfVoicePart(Char word)

          {

          return GetVoicePart(this.GetCodeByWord(word));

          }

          #endregion



          }//end class



          }//end namespace




          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=605219
          re: Java實現漢字轉換為拼音 蘆葦 2006-11-24 15:06  
          JAVA將漢字轉化成拼音的方法
          /** *//**
          #############################################################################
          # DESCRIBE 將漢字轉化成拼音
          # DATE 2006-7-12
          # COMPANY FLX
          # PORJECT JAVA
          #############################################################################
          */
          import java.util.Iterator;
          import java.util.LinkedHashMap;
          import java.util.Set;

          public class CnToSpell ...{
          private static LinkedHashMap spellMap = null;

          static ...{
          if (spellMap == null) ...{
          spellMap = new LinkedHashMap(400);
          }
          initialize();
          System.out.println("Chinese transfer Spell Done.");
          }

          private CnToSpell() ...{
          }

          /** *//**
          * 獲得單個漢字的Ascii.
          * @param cn char
          * 漢字字符
          * @return int
          * 錯誤返回 0,否則返回ascii
          */
          public static int getCnAscii(char cn) ...{
          byte[] bytes = (String.valueOf(cn)).getBytes();
          if (bytes == null || bytes.length > 2 || bytes.length <= 0) ...{ //錯誤
          return 0;
          }
          if (bytes.length == 1) ...{ //英文字符
          return bytes[0];
          }
          if (bytes.length == 2) ...{ //中文字符
          int hightByte = 256 + bytes[0];
          int lowByte = 256 + bytes[1];
          int ascii = (256 * hightByte + lowByte) - 256 * 256;
          return ascii;
          }
          return 0; //錯誤
          }

          /** *//**
          * 返回字符串的全拼,是漢字轉化為全拼,其它字符不進行轉換
          * @param cnStr String
          * 字符串
          * @return String
          * 轉換成全拼后的字符串
          */
          public static String getFullSpell(String cnStr) ...{
          if (null == cnStr || "".equals(cnStr.trim())) ...{
          return cnStr;
          }

          char[] chars = cnStr.toCharArray();
          StringBuffer retuBuf = new StringBuffer();
          for (int i = 0, Len = chars.length; i < Len; i++) ...{
          int ascii = getCnAscii(chars[i]);
          if (ascii == 0) ...{ //取ascii時出錯
          retuBuf.append(chars[i]);
          } else ...{
          String spell = getSpellByAscii(ascii);
          if (spell == null) ...{
          retuBuf.append(chars[i]);
          } else ...{
          retuBuf.append(spell);
          } // end of if spell == null
          } // end of if ascii <= -20400
          } // end of for

          return retuBuf.toString();
          }

          /** *//**
          * 根據ASCII碼到SpellMap中查找對應的拼音
          * @param ascii int
          * 字符對應的ASCII
          * @return String
          * 拼音,首先判斷ASCII是否>0&<160,如果是返回對應的字符,
          *
          否則到SpellMap中查找,如果沒有找到拼音,則返回null,如果找到則返回拼音.
          */
          public static String getSpellByAscii(int ascii) ...{
          if (ascii > 0 && ascii < 160) ...{ //單字符
          return String.valueOf((char) ascii);
          }

          if (ascii < -20319 || ascii > -10247) ...{ //不知道的字符
          return null;
          }

          Set keySet = spellMap.keySet();
          Iterator it = keySet.iterator();

          String spell0 = null;
          ;
          String spell = null;

          int asciiRang0 = -20319;
          int asciiRang;
          while (it.hasNext()) ...{

          spell = (String) it.next();
          Object valObj = spellMap.get(spell);
          if (valObj instanceof Integer) ...{
          asciiRang = ((Integer) valObj).intValue();

          if (ascii >= asciiRang0 && ascii < asciiRang) ...{ //區間找到
          return (spell0 == null) ? spell : spell0;
          } else ...{
          spell0 = spell;
          asciiRang0 = asciiRang;
          }
          }
          }

          return null;

          }

          private static void initialize() ...{
          spellPut("a", -20319);
          spellPut("ai", -20317);
          spellPut("an", -20304);
          spellPut("ang", -20295);
          spellPut("ao", -20292);
          spellPut("ba", -20283);
          spellPut("bai", -20265);
          spellPut("ban", -20257);
          spellPut("bang", -20242);
          spellPut("bao", -20230);
          spellPut("bei", -20051);
          spellPut("ben", -20036);
          spellPut("beng", -20032);
          spellPut("bi", -20026);
          spellPut("bian", -20002);
          spellPut("biao", -19990);
          spellPut("bie", -19986);
          spellPut("bin", -19982);
          spellPut("bing", -19976);
          spellPut("bo", -19805);
          spellPut("bu", -19784);
          spellPut("ca", -19775);
          spellPut("cai", -19774);
          spellPut("can", -19763);
          spellPut("cang", -19756);
          spellPut("cao", -19751);
          spellPut("ce", -19746);
          spellPut("ceng", -19741);
          spellPut("cha", -19739);
          spellPut("chai", -19728);
          spellPut("chan", -19725);
          spellPut("chang", -19715);
          spellPut("chao", -19540);
          spellPut("che", -19531);
          spellPut("chen", -19525);
          spellPut("cheng", -19515);
          spellPut("chi", -19500);
          spellPut("chong", -19484);
          spellPut("chou", -19479);
          spellPut("chu", -19467);
          spellPut("chuai", -19289);
          spellPut("chuan", -19288);
          spellPut("chuang", -19281);
          spellPut("chui", -19275);
          spellPut("chun", -19270);
          spellPut("chuo", -19263);
          spellPut("ci", -19261);
          spellPut("cong", -19249);
          spellPut("cou", -19243);
          spellPut("cu", -19242);
          spellPut("cuan", -19238);
          spellPut("cui", -19235);
          spellPut("cun", -19227);
          spellPut("cuo", -19224);
          spellPut("da", -19218);
          spellPut("dai", -19212);
          spellPut("dan", -19038);
          spellPut("dang", -19023);
          spellPut("dao", -19018);
          spellPut("de", -19006);
          spellPut("deng", -19003);
          spellPut("di", -18996);
          spellPut("dian", -18977);
          spellPut("diao", -18961);
          spellPut("die", -18952);
          spellPut("ding", -18783);
          spellPut("diu", -18774);
          spellPut("dong", -18773);
          spellPut("dou", -18763);
          spellPut("du", -18756);
          spellPut("duan", -18741);
          spellPut("dui", -18735);
          spellPut("dun", -18731);
          spellPut("duo", -18722);
          spellPut("e", -18710);
          spellPut("en", -18697);
          spellPut("er", -18696);
          spellPut("fa", -18526);
          spellPut("fan", -18518);
          spellPut("fang", -18501);
          spellPut("fei", -18490);
          spellPut("fen", -18478);
          spellPut("feng", -18463);
          spellPut("fo", -18448);
          spellPut("fou", -18447);
          spellPut("fu", -18446);
          spellPut("ga", -18239);
          spellPut("gai", -18237);
          spellPut("gan", -18231);
          spellPut("gang", -18220);
          spellPut("gao", -18211);
          spellPut("ge", -18201);
          spellPut("gei", -18184);
          spellPut("gen", -18183);
          spellPut("geng", -18181);
          spellPut("gong", -18012);
          spellPut("gou", -17997);
          spellPut("gu", -17988);
          spellPut("gua", -17970);
          spellPut("guai", -17964);
          spellPut("guan", -17961);
          spellPut("guang", -17950);
          spellPut("gui", -17947);
          spellPut("gun", -17931);
          spellPut("guo", -17928);
          spellPut("ha", -17922);
          spellPut("hai", -17759);
          spellPut("han", -17752);
          spellPut("hang", -17733);
          spellPut("hao", -17730);
          spellPut("he", -17721);
          spellPut("hei", -17703);
          spellPut("hen", -17701);
          spellPut("heng", -17697);
          spellPut("hong", -17692);
          spellPut("hou", -17683);
          spellPut("hu", -17676);
          spellPut("hua", -17496);
          spellPut("huai", -17487);
          spellPut("huan", -17482);
          spellPut("huang", -17468);
          spellPut("hui", -17454);
          spellPut("hun", -17433);
          spellPut("huo", -17427);
          spellPut("ji", -17417);
          spellPut("jia", -17202);
          spellPut("jian", -17185);
          spellPut("jiang", -16983);
          spellPut("jiao", -16970);
          spellPut("jie", -16942);
          spellPut("jin", -16915);
          spellPut("jing", -16733);
          spellPut("jiong", -16708);
          spellPut("jiu", -16706);
          spellPut("ju", -16689);
          spellPut("juan", -16664);
          spellPut("jue", -16657);
          spellPut("jun", -16647);
          spellPut("ka", -16474);
          spellPut("kai", -16470);
          spellPut("kan", -16465);
          spellPut("kang", -16459);
          spellPut("kao", -16452);
          spellPut("ke", -16448);
          spellPut("ken", -16433);
          spellPut("keng", -16429);
          spellPut("kong", -16427);
          spellPut("kou", -16423);
          spellPut("ku", -16419);
          spellPut("kua", -16412);
          spellPut("kuai", -16407);
          spellPut("kuan", -16403);
          spellPut("kuang", -16401);
          spellPut("kui", -16393);
          spellPut("kun", -16220);
          spellPut("kuo", -16216);
          spellPut("la", -16212);
          spellPut("lai", -16205);
          spellPut("lan", -16202);
          spellPut("lang", -16187);
          spellPut("lao", -16180);
          spellPut("le", -16171);
          spellPut("lei", -16169);
          spellPut("leng", -16158);
          spellPut("li", -16155);
          spellPut("lia", -15959);
          spellPut("lian", -15958);
          spellPut("liang", -15944);
          spellPut("liao", -15933);
          spellPut("lie", -15920);
          spellPut("lin", -15915);
          spellPut("ling", -15903);
          spellPut("liu", -15889);
          spellPut("long", -15878);
          spellPut("lou", -15707);
          spellPut("lu", -15701);
          spellPut("lv", -15681);
          spellPut("luan", -15667);
          spellPut("lue", -15661);
          spellPut("lun", -15659);
          spellPut("luo", -15652);
          spellPut("ma", -15640);
          spellPut("mai", -15631);
          spellPut("man", -15625);
          spellPut("mang", -15454);
          spellPut("mao", -15448);
          spellPut("me", -15436);
          spellPut("mei", -15435);
          spellPut("men", -15419);
          spellPut("meng", -15416);
          spellPut("mi", -15408);
          spellPut("mian", -15394);
          spellPut("miao", -15385);
          spellPut("mie", -15377);
          spellPut("min", -15375);
          spellPut("ming", -15369);
          spellPut("miu", -15363);
          spellPut("mo", -15362);
          spellPut("mou", -15183);
          spellPut("mu", -15180);
          spellPut("na", -15165);
          spellPut("nai", -15158);
          spellPut("nan", -15153);
          spellPut("nang", -15150);
          spellPut("nao", -15149);
          spellPut("ne", -15144);
          spellPut("nei", -15143);
          spellPut("nen", -15141);
          spellPut("neng", -15140);
          spellPut("ni", -15139);
          spellPut("nian", -15128);
          spellPut("niang", -15121);
          spellPut("niao", -15119);
          spellPut("nie", -15117);
          spellPut("nin", -15110);
          spellPut("ning", -15109);
          spellPut("niu", -14941);
          spellPut("nong", -14937);
          spellPut("nu", -14933);
          spellPut("nv", -14930);
          spellPut("nuan", -14929);
          spellPut("nue", -14928);
          spellPut("nuo", -14926);
          spellPut("o", -14922);
          spellPut("ou", -14921);
          spellPut("pa", -14914);
          spellPut("pai", -14908);
          spellPut("pan", -14902);
          spellPut("pang", -14894);
          spellPut("pao", -14889);
          spellPut("pei", -14882);
          spellPut("pen", -14873);
          spellPut("peng", -14871);
          spellPut("pi", -14857);
          spellPut("pian", -14678);
          spellPut("piao", -14674);
          spellPut("pie", -14670);
          spellPut("pin", -14668);
          spellPut("ping", -14663);
          spellPut("po", -14654);
          spellPut("pu", -14645);
          spellPut("qi", -14630);
          spellPut("qia", -14594);
          spellPut("qian", -14429);
          spellPut("qiang", -14407);
          spellPut("qiao", -14399);
          spellPut("qie", -14384);
          spellPut("qin", -14379);
          spellPut("qing", -14368);
          spellPut("qiong", -14355);
          spellPut("qiu", -14353);
          spellPut("qu", -14345);
          spellPut("quan", -14170);
          spellPut("que", -14159);
          spellPut("qun", -14151);
          spellPut("ran", -14149);
          spellPut("rang", -14145);
          spellPut("rao", -14140);
          spellPut("re", -14137);
          spellPut("ren", -14135);
          spellPut("reng", -14125);
          spellPut("ri", -14123);
          spellPut("rong", -14122);
          spellPut("rou", -14112);
          spellPut("ru", -14109);
          spellPut("ruan", -14099);
          spellPut("rui", -14097);
          spellPut("run", -14094);
          spellPut("ruo", -14092);
          spellPut("sa", -14090);
          spellPut("sai", -14087);
          spellPut("san", -14083);
          spellPut("sang", -13917);
          spellPut("sao", -13914);
          spellPut("se", -13910);
          spellPut("sen", -13907);
          spellPut("seng", -13906);
          spellPut("sha", -13905);
          spellPut("shai", -13896);
          spellPut("shan", -13894);
          spellPut("shang", -13878);
          spellPut("shao", -13870);
          spellPut("she", -13859);
          spellPut("shen", -13847);
          spellPut("sheng", -13831);
          spellPut("shi", -13658);
          spellPut("shou", -13611);
          spellPut("shu", -13601);
          spellPut("shua", -13406);
          spellPut("shuai", -13404);
          spellPut("shuan", -13400);
          spellPut("shuang", -13398);
          spellPut("shui", -13395);
          spellPut("shun", -13391);
          spellPut("shuo", -13387);
          spellPut("si", -13383);
          spellPut("song", -13367);
          spellPut("sou", -13359);
          spellPut("su", -13356);
          spellPut("suan", -13343);
          spellPut("sui", -13340);
          spellPut("sun", -13329);
          spellPut("suo", -13326);
          spellPut("ta", -13318);
          spellPut("tai", -13147);
          spellPut("tan", -13138);
          spellPut("tang", -13120);
          spellPut("tao", -13107);
          spellPut("te", -13096);
          spellPut("teng", -13095);
          spellPut("ti", -13091);
          spellPut("tian", -13076);
          spellPut("tiao", -13068);
          spellPut("tie", -13063);
          spellPut("ting", -13060);
          spellPut("tong", -12888);
          spellPut("tou", -12875);
          spellPut("tu", -12871);
          spellPut("tuan", -12860);
          spellPut("tui", -12858);
          spellPut("tun", -12852);
          spellPut("tuo", -12849);
          spellPut("wa", -12838);
          spellPut("wai", -12831);
          spellPut("wan", -12829);
          spellPut("wang", -12812);
          spellPut("wei", -12802);
          spellPut("wen", -12607);
          spellPut("weng", -12597);
          spellPut("wo", -12594);
          spellPut("wu", -12585);
          spellPut("xi", -12556);
          spellPut("xia", -12359);
          spellPut("xian", -12346);
          spellPut("xiang", -12320);
          spellPut("xiao", -12300);
          spellPut("xie", -12120);
          spellPut("xin", -12099);
          spellPut("xing", -12089);
          spellPut("xiong", -12074);
          spellPut("xiu", -12067);
          spellPut("xu", -12058);
          spellPut("xuan", -12039);
          spellPut("xue", -11867);
          spellPut("xun", -11861);
          spellPut("ya", -11847);
          spellPut("yan", -11831);
          spellPut("yang", -11798);
          spellPut("yao", -11781);
          spellPut("ye", -11604);
          spellPut("yi", -11589);
          spellPut("yin", -11536);
          spellPut("ying", -11358);
          spellPut("yo", -11340);
          spellPut("yong", -11339);
          spellPut("you", -11324);
          spellPut("yu", -11303);
          spellPut("yuan", -11097);
          spellPut("yue", -11077);
          spellPut("yun", -11067);
          spellPut("za", -11055);
          spellPut("zai", -11052);
          spellPut("zan", -11045);
          spellPut("zang", -11041);
          spellPut("zao", -11038);
          spellPut("ze", -11024);
          spellPut("zei", -11020);
          spellPut("zen", -11019);
          spellPut("zeng", -11018);
          spellPut("zha", -11014);
          spellPut("zhai", -10838);
          spellPut("zhan", -10832);
          spellPut("zhang", -10815);
          spellPut("zhao", -10800);
          spellPut("zhe", -10790);
          spellPut("zhen", -10780);
          spellPut("zheng", -10764);
          spellPut("zhi", -10587);
          spellPut("zhong", -10544);
          spellPut("zhou", -10533);
          spellPut("zhu", -10519);
          spellPut("zhua", -10331);
          spellPut("zhuai", -10329);
          spellPut("zhuan", -10328);
          spellPut("zhuang", -10322);
          spellPut("zhui", -10315);
          spellPut("zhun", -10309);
          spellPut("zhuo", -10307);
          spellPut("zi", -10296);
          spellPut("zong", -10281);
          spellPut("zou", -10274);
          spellPut("zu", -10270);
          spellPut("zuan", -10262);
          spellPut("zui", -10260);
          spellPut("zun", -10256);
          spellPut("zuo", -10254);
          }

          public static void main(String[] args) ...{
          String str = null;
          str = "謝海101普降喜雨";
          System.out.println("Spell=" + CnToSpell.getFullSpell(str));

          str = "張牙舞爪》。,";
          System.out.println("Spell=" + CnToSpell.getFullSpell(str));

          str = "啦啦,可恥下場。";
          System.out.println("Spell=" + CnToSpell.getFullSpell(str));

          str = "豬油,豬八戒。";
          System.out.println("Spell=" + CnToSpell.getFullSpell(str));
          }

          private static void spellPut(String spell, int ascii) ...{
          spellMap.put(spell, new Integer(ascii));
          }
          }
          主站蜘蛛池模板: 东台市| 桂平市| 炎陵县| 前郭尔| 苏尼特右旗| 永城市| 宜川县| 永丰县| 柘城县| 和静县| 达拉特旗| 内丘县| 晋城| 定南县| 蒙城县| 民县| 繁峙县| 左权县| 大厂| 汉阴县| 昭平县| 漳州市| 连山| 大荔县| 武宁县| 互助| 平果县| 玉田县| 阿坝县| 辽中县| 大渡口区| 富顺县| 和林格尔县| 额济纳旗| 那曲县| 黔南| 大同市| 福鼎市| 湘潭市| 威远县| 资中县|