|
我的评论
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')
模式字符串简介:
%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个字符,就将左边多出的字符截掉。
一 最好与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
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
总之,合理地创建对象可以有效的提供可读性、降低耦合度、提高系统的封装性和可移植性,我们应当引起重视。
|
一个优秀软件开发人员的必修课:GRASP(2)低耦合
|