我的评论
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 编码解码
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意味着将关闭默认的外连接抓取.
取值 建议在0到3之间取值
|
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的批量更新.
取值 建议取5到30之间的值
|
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
与Struts结合使用最出名的一个tag主要是显示表格数据很漂亮、完善。
用来在web上显示复杂图形报表的一个jsp tag。
当一个复杂的操作可以加载比较长的时间时,用这个tag。
DbForms!它是一个基于 Java (Servlet,JSP/Taglib)的快速应用程序开发环境,可以帮助开发人员快速建造基于Web的数据库应用程序。
Jakarta Taglibs 是为JSP定制标签库和相关的项目提供的一个开源仓库,如 TagLibraryValidator类,和对页面生成工具的扩展来支持标签库。Jakarta Taglibs 也包括了对JSP Standard Tag Library (JSTL)的参考实现。这个实现基于项目标准。目前,在Jakarta Taglibs 中没有其它标签库代表了Java Community Process (JCP) 标准。
LDAP标签库为JSP程序员和Web页面设计者提供了最容易的方法来执行任意的LDAP操作。
WebJMX标签库项目可以控制你的JMX 接口。WebJMX 这个标签库项目的目的是生成一个JSP标签库,可以让有技巧的JSP开发人员为JMX生成一个可定制的、规范的、基于Web的界面。
JPivot - 是一个JSP 自定制的标签库,可以绘制一个OLAP表格和图表。用户可以执行典型的OLAP导航,如下钻,切片和方块。它使用Mondrian 作为其OLAP服务器。
JSP Tree Tag是一个显示树型结构jsp标签,它只把需要显示的部分送到客户浏览器。
该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。
TableTag是类似于DataGrid的Jsp标签库。通过java.util.List填充数据。
uitags利用这个开源自定义标签可以很容易开发出一个友好的用户界面。
ValueList利用这个标签可以进行数据过滤,排序,分页。而且界面挺漂亮的。
JCE taglib把JCE(Java Cryptographic Extensions)包装成TagLib并且包含了EL函数。使用这个标签能够为jsp应用程序加强安全性。
Prize Tags是一个集许多功能于一身的Jsp标签库。其中最受欢迎的Tree Tag,这个Tag可以为不同节点指定不同的图标,而且可以服务端可以监控客户端节点的展开,关闭,选中与未选中等事件。除了Tree Tag还有日历Tag,Icon Tag,Alternate Tag ,Template Tag 等其它的功能。
Struts -Layout是一个用在Struts的标签库.这个强大的标签库可以用来显示面板(panels),输入框,表格,treeviews, sortable lists,datagrids,popups,日历等.使用这些标签可以不用写HTML代码,甚至可以不用懂得HTML.这个项目还提供一个 Eclipse下的插件Kiwi帮助使用Struts和Struts-Layout来开发Jsp页面.以下是一张例图:
JImageTaglib是一个用在J2EE Web应用程序的Java标签库.它用来在服务端生成与处理图片然后再反馈到JSP页面.可以过滤(filtering)图片,调整图片文件大小,生成条形码等.
uitags是一个开源的JSP custom-tag库.它让开发友好的用户界面变得简单.
AWTaglib是一个Jsp标签可用于创建网格(grid)控件.它还提供一些额外的功能可以把网格中的数据导出为XLS,PDF和CSV(利用JasperReports来实现)并能与Struts框架相结合.
eXtremeTable是一个可扩展的用于以表格的形式来显示数据的一组JSP标签库.
这是一个可用来开发多页选项板(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为使用Java Persistence API提供一个JSP标签库。这个标签库定义了六个标签涉及一些普通的数据存取任务。
em, 获取一个EntityManager
tx, 事务定界
persist, 通过当前EntityManager来把对象持久化
remove, 从数据存储中移除去对象
find, 通过一个给定的主关键字来查找对象
refresh, 刷新对象的内容
这组JSP标签包含了一些常用的UI构件(wizzard, tree, progressBar, list, comboBox和titled panel)。AJAX技术也被尽可能地运用到其中。
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标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。
dt-Source这个标签库让Displaytag标签能够在JSP页面中直接调用数据源(Hibernate,JDBC等)中的数据。dt-Source基于Spring框架开发。
MicroNova YUZU开源基于EL的JSP标签库。这是一个增强的JSTL(兼容JSP1.2与JSP 2.0)。
JSControlsTags 这个JSP标签库提供了一些基于Ajax(Prototype.js/scriptaculous.js)技术的Web UI控件(Autocomplete,Slider/AjaxSlider,Treeview,Swap)。JSControlsTags利用JSON来 在服务器与客户端之间传递信息。
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)低耦合
re: SVN配置 芦苇 2007-10-16 11:17
Subversion安装记录
程序版本:
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
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
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里的那三条记录.
在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));
}
}
|