konhon

忘掉過去,展望未來。找回自我,超越自我。
逃避不一定躲的过, 面对不一定最难过, 孤单不一定不快乐, 得到不一定能长久, 失去不一定不再拥有, 可能因为某个理由而伤心难过, 但我却能找个理由让自己快乐.

Google

BlogJava 首页 新随笔 联系 聚合 管理
  203 Posts :: 0 Stories :: 61 Comments :: 0 Trackbacks

#

很多人 特别是新手 做j2ee 项目中
总能受困于 这样或那样的编码问题

这里讨论下 新手学习,高手指教 一起研究下
(以 tomcat mysql 做例子 我推荐所有的编码采用utf-8)

1 工程
工程内所有的 .java .jsp .xml .txt 都有默认的编码 默认的是系统环境的编码
我们中文系统通常是GBK 推荐都采用utf-8
utf-8 的时候 你编译 生成doc 可能会遇到乱码(特别是采用ant 的时候,生成doc你几乎100%会遇到)

解决方法 以ant 为例子
编译 注意 encoding 参数
<target name="build" >
       <mkdir dir="${build.dir}" />
       <javac encoding="utf-8" destdir="${build.dir}" target="1.3" debug="true" deprecation="false" optimize="false" failonerror="true">
           <src path="${src.dir}" />
           <classpath refid="master-classpath" />
       </javac>
   </target>

生成doc 注意 encoding 和 charset
<target name="doc">
<mkdir dir="doc" />
<javadoc charset="utf-8" encoding="utf-8" packagenames="${packages}" sourcepath="src" destdir="doc" author="true" version="true" use="true" splitindex="true" >
<classpath refid="master-classpath" />
</javadoc>
</target>

这里 的encoding 就是指的你 java 文件的编码格式 javac 和javadoc 都有这个参数
charset 指的是 生成 doc 后的编码方式 javadoc 的参数

2 数据库
mysql 的编码最复杂 从4以后 mysql 号称支持多编码 它更灵活了 我们也更麻烦了
mysql 有4个级别的编码
系统级
库级
表级
sql语句级
请保持采用统一的编码 推荐utf-8
其它数据库要简单的多 一般都是一种编码

3 web server
tomcat 为例
tomcat server.xml 中一个参数
<Connectorport="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" URIncoding="utf-8"/>
经测试 这个URIncoding 参数主要是 get 方法中采用编码

4 jsp 显示层
第1条中说明了 jsp 文件本身的格式
很多朋友采用eclipse +myeclipse 生成jsp
它自动生成一个头<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
不要误解 这句话不能保证你在ie里看到的不是乱码
pageEncoding它的意思是 这个页面本身采用的是 utf-8 (似乎只在eclipse 里有效果 ,我不确定)
为了在ie 里不乱码  你还得加一句 <%@ page contentType="text/html; charset=UTF-8"%>
它不能在(myeclispe)自动生成  推荐修改 myeclipse的模板 在下边的目录里
MyEclipse\eclipse\plugins\com.genuitec.eclipse.wizards_4.0.1\Templates
里边的jsp模版 你加上<%@ page contentType="text/html; charset=${encoding}"%>

5 filter
自从tomcat 4 以后 网上就流传了一个SetCharacterEncodingFilter 过滤器 搜一下有很多
很好用 web.xml 中加入
<filter>
 <filter-name>Set Character Encoding</filter-name>
 <filter-class>filters.SetCharacterEncodingFilter</filter-class>
 <init-param>
 <param-name>encoding</param-name>
 <param-value>utf-8</param-value>
 </init-param>
</filter>
 <filter-mapping>
 <filter-name>Set Character Encoding</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>

6 资源文件
首先保证 文件本身是utf-8
然后部署的时候用 native2ascii 转换
这里给出 ant 里的例子
<native2ascii encoding="utf-8" dest="${web.dir}/WEB-INF/classes" src="${src.dir}" includes="**/*.properties" />

总结
到这里 你应该彻底解决了乱码了 嘿嘿
写的有点乱 还请高手们多指点
posted @ 2006-06-13 19:25 konhon 优华 阅读(461) | 评论 (0)编辑 收藏

重要區別:

重音發在第二個音節時一般是動詞
重音發在第一個音節時一般是名詞或形容詞


Welcome to Daily Tips on Learning English. Today’s tip is on how syllable stress can affect the meaning of words.
Remenber that stressed syllables are said louder and are lengthened, and unstressed syllables are pronounced more softly, and often have the vowel sounds reduced.
Sometimes, this difference can be the difference between a verb and a noun, or an adjective.
There are at least 14 pairs of words in which syllable stress alone makes this difference. Some examples include `addict, a`ddict, `convict, con`vict, `perfect, per`fect. Each time the second syllable is stressed, the word is a verb. When the first syllable is stressed, the word is either a noun or an adjective. Let’s look some examples more closely. `Permit, per`mit, a `permit is a noun, it is a piece of paper which authorizes you to do something. For instance, a fishing `permit allows you to go fishing. Per`mit is a verb. It means to allow. For instence, fishing isn’t per`mitted here without a `permit.
Another example is `perfect, per`fect. `Perfect is an adjective. It means 100% correct, no mistakes or errors. The verb is per`fect, it means to make something perfect. For example, “I want to per`fect my English” means “I want to make my English perfect”. Make sure you stress the right syllable. It can be the differece between different parts of speech. This has been today’s daily tip. Till then, tomorrow, for another tip on learning English.

posted @ 2006-06-05 18:53 konhon 优华 阅读(401) | 评论 (0)编辑 收藏

最重要區別: 
發音時如果表示can 則把重音放在 can 後面的動詞上
如果表示Can't則把重音入在Can't上.
仔細看看下這面這段話.
 
Welcome to Daily tips on Learning English. Today's tip is on distinguishing "can" and "cannot" in spoken American English.

"Cannot" is usually contracted to "can't". So many learners of English assume that in order to distinguish between "can" and "can't", one must listen for the final "t" sound /t/. And when speaking, one must pronounce final 't' sound /t/ clearly. However, this is not in fact how native speakers distinguish "can" and "can't". People do not say 'I `can drive a car, but I can't drive a motorcycle.' People say 'I can `drive a car', but I `can't drive a motorcycle.' The difference between "can" and "can't" is in stress. "Can" is not stressed, the verb after it is. "Can't" is stressed. The verb after it is not.

Also since 'can' is not stressed, the vowel is reduced to /a/, so "can" is actually pronounced "can". Listen to another example. "I `can't go on Saturday, but I can `go on Sunday." Did you hear the 't' sound? Did you notice the difference words being stressed? Listening again. "I `can't go on Saturday, but I can `go on Sunday." If you want to understand whether someone is saying he can or can't do something, you have to be listening for a stressed "can't" or a verb stressed after "can". What does this mean? "I can `speak Japanese, but I `can't speak Taiwanese." That's right, I can speak Japanese, but I cannot speak Taiwanese. When you are speaking it is very important that you follow this rule too. When learners of English say I `can help you, native speakers often unsure what is meant because of improper stress. So remember, you can stress "can't", but you `can't stress "can".

This has been today's tip on learning English. Tune in tomorrow for another tip.

posted @ 2006-06-05 01:15 konhon 优华 阅读(3006) | 评论 (0)编辑 收藏

Sun 官方的中文版 Java API 文档发布了,地址为:http://gceclub.sun.com.cn/download/Java_Docs/html_zh_CN.zip, 下载后请参考如下步骤配合 eclipse3.1 使用

1. 点击菜单 <窗口> - > <设定>
2. 点击左边项目列表中的 <Java> ->  <已安装的 JRE>
3. 选中你已经安装好的 JRE5.0 ,单击右边的编辑
4. 点击对话框下边的库列表中的 rt.jar 左边的加号 “+”,展开 rt.jar 的配置
5. 选中第二项,JavaDoc Location ,单击右边的编辑,如果右边的编辑是灰色的,将库列表上边的“使用默认的系统库” (use default system libraries) 的复选框取消选择。
6. 在弹出的对象框中,上边是使用解压后的文件来进行帮助,下面使用未解压的压缩包帮助。
7. 我们使用未解压的压缩包,选择下面的 javaDoc in Archive.
8. 需要输入两个内容,一个是压缩包所在的位置 (Archive Path ), 可以选择右边的浏览选择,第二个是压缩包里面的路径 ( Paht within Archive),也可以使用右边的浏览进行选择,一直到 api 文件夹为止。完成后,在浏览的下面有一个检验的按钮 (validate) 可以进行检查。
9. 完成后,确定关闭。

现在,在 Java 编辑器中选中一个系统的方法,按 F1 即可在帮助窗口中看到对应的 JavaDoc 的帮助入口,点击后,就可以直接看到对应的 JavaAPI 的 Doc 了。
posted @ 2006-06-04 19:41 konhon 优华 阅读(546) | 评论 (0)编辑 收藏

使用高效的日志工具—Log4J (1)  
作者:赵科 发文时间:2002.11.13 09:52:21

大家在编程时经常不可避免地要使用到一些日志操作,比如开发阶段的调试信息、运行时的日志记录及审计。调查显示,日志代码占代码总量的4%。通常大家可以简单地使用System.out.println()语句输出日志信息,但是往往会有一些判断,比如:

if (someCondition) {
System.out.println("some information.");
}



这些判断造成正常的程序逻辑中混杂了大量的输出语句。而在开发阶段写下的这些判断仅为了调试的语句,在开发完成时需要查找并移除。部署运行后,尤其是在一些企业应用系统中,还经常需要进一步调试,这时就遇到了更大的麻烦。所以,我们需要一套完备的、灵活的、可配置的日志工具。Log4J就是优秀的选择。

Log4J是Apache软件基金会Jakarta项目下的一个子项目,是用Java编写的优秀日志工具包。通过Log4J可以在不修改代码的情况下,方便、灵活地控制任意粒度的日志信息的开启或关闭,然后使用定制的格式,把日志信息输出到一个或多个需要的地方。并且,Log4J还有一条平滑的学习曲线,在三分钟内就可学会它的简单使用。随着使用深入,你会发现Log4J功能的强大,几乎可以满足日志方面的所有需要。


快速入门


先看一段代码,看看Log4J是多么易于上手,代码如下:

package org.javaresearch.log4j;
import org.apache.log4j.*;
public class TestLog4J {
static Logger log = Logger.getLogger(TestLog4J.class.getName());
public static void main(String args[]) {
  BasicConfigurator.configure();
  // logging的各种方法
  cat.debug("Start of main()");
  cat.info("Just testing a log message with priority set to INFO");
  cat.warn("Just testing a log message with priority set to WARN");
  cat.error("Just testing a log message with priority set to ERROR");
  cat.fatal("Just testing a log message with priority set to FATAL");
  // 另一种不方便的格式
  cat.log(Priority.DEBUG, "Testing a log message use a alternate form");
  log.debug("End of main().");
}
}



把这段代码保存在一个目录下,编译运行(注意要把log4j-1.2.7.jar包含入类路径中),程序输出如下:

0 [main] DEBUG TestLog4J  - Start of main()
10 [main] INFO TestLog4J  - Just testing a log message with priority set to INFO
20 [main] WARN TestLog4J  - Just testing a log message with priority set to WARN
30 [main] ERROR TestLog4J  - Just testing a log message with priority set to ERROR
30 [main] FATAL TestLog4J  - Just testing a log message with priority set to FATAL
40 [main] DEBUG TestLog4J  - Testing a log message use a alternate form
50 [main] DEBUG TestLog4J  - End of main().



首先解释一下上面输出结果的意义。第一个数字是指程序开始运行到运行该日志语句所经历的毫秒数(用来做一点运行效率分析也不错),“[main]”是日志事件发生的线程,随后的“DEBUG”、“INFO”等信息是相应日志信息的优先级别,“TestLog4”是当前Logger的实例名,最后是日志信息。

在这段程序中,使用了Log4J提供的一个基本配置类BasicConfigurator对Log4J进行初始化。但在实际使用时通常不这么做,因为这多少有点“硬”编码。今后如果要修改Log4J的配置,就需要修改、重新编译代码,这通常不是大家所希望的。通常,我们都提供一个名为log4j.properties的文件,在第一次调用到Log4J时,Log4J会在类路径中定位这个文件,并读入这个文件完成的配置。这个配置文件告诉Log4J以什么样的格式、把什么样的信息、输出到什么地方。我们来看一个简单的log4j.properties配置文件的示例,代码如下:

log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern= "%-4r [%t] %-5p %c %x - %m%n



把上面的内容存储为log4j.properties,并放到和TestLog4J.class同一目录下(当然也可以放到其它任何目录,只要该目录被包含到类路径中即可)。具体这些配置文件中每行的意义,在以后章节会有详细的说明,现在可以先跳过。现在你可以注释掉上面程序中的“BasicConfigurator. configure();”语句,然后使用log4j.properties属性文件完成Log4J的配置,重新编译、运行,就得到和上面一样的结果。

这样做有什么好处呢?现在就初步领略一些Log4J的灵活、强大功能。比如系统要上线了,希望输出一些警告和错误信息,这时仅需要修改log4j.properties文件中的“log4j.rootCategory=DEBUG, A1”即可,然后设置日志输出的最低级别是WARN,设置为“log4j.root Category=WARN, A1”。此时不需要修改任何代码,重新运行系统,输出结果就变成了:

20 [main] WARN TestLog4J  - Just testing a log message with priority set to WARN
30 [main] ERROR TestLog4J  - Just testing a log message with priority set to ERROR
30 [main] FATAL TestLog4J  - Just testing a log message with priority set to FATAL




原理分析


Log4J有三个主要部件,它们是记录器(Loggers)、输出源(Appenders)和布局(Logouts)。记录器按照布局中指定的格式把日志信息写入一个或多个输出源。输出源可以是控制台、文本文件、XML文件或Socket,甚至还可以把信息写入到Windows事件日志或通过电子邮件发送,这都需要相应的类来处理,这些相关的类是ConsoleAppender、FileAppender、SocketAppender、NtEventLogAppender和JMSAppender。

记录器(Logger)

首先让我们看Logger类,代码如下:

package org.apache.log4j;
public class Logger {
//创建和恢复方法
public static Logger getRootLogger();
public static Logger getLogger(String name);
public static Logger getLogger(Class clazz);
// 打印方法
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);
// 常用打印方法
public void log(Level l, Object message);
}



从这段代码中可以看出Logger的基本使用。首先需要获取一个Logger对象,获取Logger对象的语句为:

Logger logger = Logger.getLogger(JavaLoggingExample.class.getName());



有了这个Logger对象,就可以在需要的地方方便地输出日志信息。对于这些信息是否输出、输出的格式等,都可以通过配置文件方便地配置,而不需要修改代码,这就是Log4J带来的方便之处。

记录器的层次结构

使用Log4J的Logger.getLogger()方法时会得到一个Logger的实例。如果一个应用中包含了上千个类,那么也几乎需要上千个Logger实例。如何对这上千个Logger实例进行方便地配置,就是一个很重要的问题。Log4J采用了一种树状的继承层次巧妙地解决了这个问题。在Log4J中Logger是具有层次关系的。它有一个共同的根,位于最上层,其它Logger遵循类似包的层次,比如:

static Logger root = Logger.getRootLogger();
static Logger log1 = Logger.getLogger("org");
static Logger log2 = Logger.getLogger("org.javaresearch");
static Logger log3 = Logger.getLogger("org.javaresearch.log4j.TestLog4J");



上面代码中,log1是log2的父亲,是log3的祖先,而root是所有log1、log2、log3的祖先,它们都从root中继承。所以,一般情况下,仅需要配置好rootLogger,其它子记录器都会从中继承rootLogger的配置。如果修改了rootLogger的配置,其它所有的子记录器也会继承这种变化。这样就大大地方便了配置。现在回头看看在“快速入门”中的配置文件,我们仅配置了rootLogger,就可以控制所有的Logger的行为。

级别(Level)

Log4J中的一个核心概念是日志级别是有序的。Log4J内置了5种日志级别为:

DEBUG  <  INFO  <  WARN  <  ERROR  <  FATAL



右边的级别比左边的高。每一个Logger实例都有一个日志级别,上面的5种输出方法就是对应于5种不同级别的日志请求。比如,如果c是一个Logger实例,c.info("some information")就是一个INFO级别的日志请求。一个日志请求会不会输出,取决于该Logger实例的日志级别和该日志请求级别的比较。规则如下:

假如在一个级别为p的Logger实例中发生一个级别为q的日志请求,则当q >= p时请求才会启用。

我们先来看实例2代码如下:

// 得到一个logger 实例 "com.foo"
Logger  logger = Logger.getLogger("com.foo")
// 现在设置logger的级别,但正常情况是不需要刻意设置lgger级别的,因为它已经在配置文件中完成了
logger.setLevel(Level.INFO);
Logger barlogger = Logger.getLogger("com.foo.Bar");
//因为 WARN >= INFO,这个请求是可以实现的
logger.warn("Low fuel level.");
// 因为DEBUG < INFO,所以这个请求是无法实现的
logger.debug("Starting search for nearest gas station.");
// logger实例"com.foo.Bar"将从"com.foo"继承级别,这样,因为INFO >=
INFO,所以可以实现下面的请求
barlogger.info("Located nearest gas station.");
//因为DEBUG < INFO,这个请求是不能实现的
barlogger.debug("Exiting gas station search");



布局(Layout)

Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数见表1如下:


%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)


使用高效的日志工具—Log4J (2)  
作者:赵科 发文时间:2002.11.13 09:52:21

基本应用
Log4J的配置

现在来看log4j.properties配置文件的意义。第一行指定了根Logger的级别是DEBUG,并将此指定输出到A1。A1就是第二行定义的org.apache.log4j.ConsoleAppender,此行表示将A1输出到控制台。第三行规定了输出到A1的格式为org.apache.log4j.PatternLayout。第四行规定了输出到A1格式的转换模式为org.javaresearch.log4j.TestLog4J。

很多成熟的服务器类的软件日志信息会输出到控制台,同时输出到日志文件备查。使用Log4J可以在不改变任何代码的情况下,仅通过修改配置文件就可以轻松地完成这项功能。相关配置文件如下:


#### Use two appenders, one to log to console, another to log to a file
log4j.rootCategory=debug, stdout, R

# Print only messages of priority WARN or higher for your category
log4j.category.your.category.name=WARN

#### First appender writes to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller&#39;s file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

#### Second appender writes to a file
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log

# Control the maximum log file size
log4j.appender.R.MaxFileSize=100KB
# Archive log files (one backup file here)
log4j.appender.R.MaxBackupIndex=1

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n




这个配置文件指定了两个输出源stdout和R。前者把日志信息输出到控制台,后者是一个轮转日志文件。最大的文件是100KB,当一个日志文件达到最大尺寸时,Log4J会自动把example.log重命名为example.log.1,然后重建一个新的example.log文件,依次轮转。

在Web应用中使用

在Web应用中,应该在哪儿对Log4J进行配置呢?首先要明确,Log4J必须在应用的其它代码执行前完成初始化。因为Servlet是在Web服务器启动时立即装入的,所以,在Web应用中一般使用一个专门的Servlet来完成Log4J的配置,并保证在web.xml的配置中,这个Servlet位于其它Servlet之前。下面是一个例子,代码如下:


package org.javaresearch.log4j;
import java.io.*;
import javax.servlet.*;
import org.apache.log4j.*;
public class Log4JInit extends HttpServlet {
public void init() throws ServletException {
  String prefix = getServletContext().getRealPath("/");
  String file = getServletConfig().getInitParameter("log4j-config-file");
  // 从Servlet参数读取log4j的配置文件
  if (file != null) {
   PropertyConfigurator.configure(prefix + file);
  }
}
public void doGet(HttpServletRequest request,HttpServletResponse response)throws
IOException, ServletException {}
public void doPost(HttpServletRequest request,HttpServletResponse response)throws
IOException, ServletException {}
}





<servlet>
  <servlet-name>log4jinit</servlet-name>
   <servlet-class>org.javaresearch. log4j.Log4JInit</servlet-class>                  
   <init-param>
   <param-name> log4j-config-file </param-name>
        <param-value>/properties/log4j.properties</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>




注意:上面的load-on-startup应设为1,以便在Web容器启动时即装入该Servlet。log4j.properties文件放在根的properties子目录中,也可以把它放在其它目录中。应该把.properties文件集中存放,这样方便管理。


高级话题


性能

在记录一些日志信息时,会一定程度地影响系统的运行效率,这时日志工具是否高效就是一个关键。Log4J的首要设计目标就是高效,一些关键组件都重写过很多次以不断提高性能。根据Log4J项目小组的报告,在AMD Duron 800MHz + JDK1.3.1的环境下,Log4J判断一条日志语句是否需要输出仅需要5纳秒。实际的日志语句执行的也非常快速,从使用SimpleLayout的21微秒(几乎与System.out.println一样快),到使用TTCCLayout的37微秒不等。

嵌套诊断环境NDC

在多用户并发的环境下,通常是由不同的线程分别处理不同的客户端请求。此时要在日志信息中区分出不同的客户端,你可以为每一个线程生成一个Logger,从而从一堆日志信息中区分出哪些信息是属于哪个线程的,但这种方式并不高效。Log4J巧妙地使用了Neil Harrison提出的“NDC(嵌套诊断环境)”机制来解决这个问题。Log4J为同一类别的线程生成一个Logger,多个线程共享使用,而它仅在日志信息中添加能够区分不同线程的信息。NDC是什么?举例来说,如果一个Servlet接到并发请求时,为每一个客户端创建一个新的线程,然后分配一个用于保存该请求上下文的NDC堆栈。该上下文可能是发出请求的主机名、IP地址或其它任何可以用于标识该请求的信息。这样,由于不同的客户端处理线程具有不同的NDC堆栈,即使这个Servlet同时生成多个线程处理不同的请求,这些日志信息仍然可以区分出来,就好像Log4J为每一个线程都单独生成了一个Logger实例一样。在Log4J中是通过org.apache.log4j.NDC实现这种机制的。使用NDC的方法也很简单,步骤如下:

1. 在进入一个环境时调用NDC.push(String),然后创建一个NDC;

2. 所做的日志操作输出中包括了NDC的信息;

3. 离开该环境时调用NDC.pop方法;

4. 当从一个线程中退出时调用NDC.remove方法,以便释放资源。

下面是一个模拟记录来自不同客户端请求事件的例子,代码如下:

import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
public class TestNDC {
static Logger log = Logger.getLogger(TestNDC.class.getName());
public static void main(String[] args) {
  log.info("Make sure %x is in your layout pattern!");
  // 从客户端获得IP地址的例子
  String[] ips = {"192.168.0.10","192.168.0.27"};
  for (int i = 0; i<ips.length ; i++)  // 模拟一个运行方法
  {
   // 将IP放进 NDC中
   NDC.push(ips[i]);
   log.info("A NEW client connected, who&#39;s ip should appear in this log message.");
   NDC.pop();
  }
  NDC.remove();
  log.info("Finished.");
}
}



注意配置文件中的布局格式中一定要加上%x。系统输出如下:

INFO   - Make sure %x is in your layout pattern!
INFO  192.168.0.10 - A NEW client connected, who&#39;s ip should appear in this log
message.
INFO  192.168.0.27 - A NEW client connected, who&#39;s ip should appear in this log
message.
INFO   - Finished.



使用Log4J还是JDK logging API

从JDK 1.4.0开始,引入了java.util.logging包。虽然Log4J小组曾竭力游说JCP(Java Community Process)采用Log4J作为JDK 1.4的“标准”日志API,虽然最终因Sun的日志API规范的负责人Graham Hamilton的一句“Merlin的开发已经到了最后阶段,这时不允许再对主要API做出改变”而没有被采纳,但Log4J还是对新的日志API产生了重要影响。那么,我们到底应该采用Log4J还是java.util.logging包呢?下面仅对两者做一简单的比较。

1. Log4J更加成熟,从1999年10月开始至今已经有3年的时间,并且已经在许多项目中有着成熟的应用。而JDK中的logging包是在1.4之后才引入的,并且不能运行于JDK 1.3之前的版本。Log4J则可以良好地运行于JDK 1.1之后的所有版本。

2. Log4J已经被移植到多种环境下,包括log4c(C)、log4cpp(C++)、log4perl(Perl)、log4net(.net)等。在这些环境下,可以感受到几乎一致的配置和使用方式。这是JDK中的logging API所不能比拟的。

3. Log4J还具有更加强力的格式化系统,可以使记录输出时实现简单的模式。但是,它不会增加类而导致格式化工具的扩展。众多的附加程序和处理器使得Log4J数据包成为一个绝佳的选择,所有你所需要的都可能加以实现。

4. Log4J在性能上做了最大的优化。

Logging API对于简单的使用是足够的,但它缺少了许多Log4J所具有的功能。所以,如果你需要一个强力的logging机制,就应坚持使用Log4J;而如果只是需要一些简单的控制或文件记录,那么可以使用已经内建在JDK之中的logging API。

虽然Log4J和JDK logging API是一种竞争关系,但在logging API还在JCP中讨论(JSR47)时,两者之间就已经开始相互影响了。

FAQ

1. 如何让Log4J使用指定的配置文件

在启动你的应用时植入系统属性。例如,可以把上面的log4j.properties文件放到\properties的相对路径下,并改名为log.properties,此时如果让Log4J能够找到这个配置文件并正确地初始化,需要这样运行程序:

D:\..\java -Dlog4j.configuration=. \properties\log.properties YourAppName



为什么一定要使用系统属性,而不在配置文件中指定呢?很显然,如果把它写入配置文件,那么,Log4J读到它时已经迟了。

2. 如何查看到Log4J的配置过程

可以类似1中的那样,设置系统属性log4j.debug=true,从而打开Log4J的Verbose模式,此时会输出Log4J的初始化过程,这样就会对Log4J的启动有一个更详细的了解。下面是Log4J启动信息的一个示例:

log4j: Trying to find [log4j.xml] using context classloader
sun.misc.Launcher$AppClassLoader@92e78c.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$ExtClassLoader@9fbe93class
loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader
sun.misc.Launcher$AppClassLoader@92e78c.
log4j: Using URL [file:/D:/java/logging/src/log4j.properties] for automatic log4j
configuration.
log4j: Reading configuration from URL file:/E:/java/logging/src/log4j.properties
log4j: Parsing for [root] with value=[DEBUG, A1].
log4j: Level token is [DEBUG].
log4j: Category root set to DEBUG
log4j: Parsing appender named "A1".
log4j: Parsing layout options for "A1".
log4j: Setting property [conversionPattern] to [%d %l %-5p %c [%t] - %m%n].
log4j: End of parsing for "A1".
log4j: Parsed "A1" options.
log4j: Finished configuring.
......  // 下面就是应用的日志信息,省略。
posted @ 2006-05-30 07:17 konhon 优华 阅读(684) | 评论 (0)编辑 收藏

Spring是一个服务于所有层面的application framework:提供了bean的配置基础,AOP的支持,JDBC的提取框架,抽象事务支持,等等。它有一个非常显著的特点:在某个层面上如果你不需要Spring的支持,你就可以不使用String的class,只使用它的某一部分的功能。从它的设计理念,你可以看到String帮助你实现了真正的逻辑层和web层的分离。

  相对于EJB来说,Spring是一个轻量级的J2EE应用开发框架。这里提到的轻量级指的是Spring框架本身,而不是说Spring只能适用于轻量级的应用开发。Spring的轻盈体现在其框架本身的基础结构以及对其他应用工具的支持和装配能力,与EJB这种庞然大物相比,Spring使我们把各个技术层次之间的风险降低。EJB的内聚性较强,比如数据持久层管理、事务管理、生命周期管理都全部交给了EJB容器中管理,内聚性的白盒特征使我们必须放弃一部分可控性而去信任容器能力。而Spring则是考虑如何“不造轮子”,如何更好的组装这些轮子,让他们更好的转动。比如数据持久层管理可以使用hibernate,日志管理可以使用jakartacommonlogging。一个比较恰当的比喻就是“我们要钉几个钉子,为了完成这个目的,锤子生产商生产了大大小小一系列的锤子,每个锤子都有一套复杂的使用方法,用来钉某种特别的钉子,结果令我们头疼不堪。解决锤子过多的问题,通过spring,我们可以使用几种锤子,但用起来象是只有一个锤子”。(注:这段话是在网上看见的,这里引用这个比喻,我个人觉得很生动)关于这个框架也有一些简单的总结:“Spring有几个主要的部分:Bean+ApplicationContext,以一种统一的、IoC的方式查找、管理、组装、使用系统的组件,取代一切工厂;持久化框架;web框架。“J2EE框架”是RodJohnson的愿景,他希望Spring为J2EE轻量级解决方案提供自底至顶的全面基础设施支持。”
  上面是关于一个新的Framework的简单介绍,据说是未来J2EE发展的方向。以前在论坛上有关于J2EE最佳组合的讨论,听说这个JSTL+Struts(或webwork)+Spring+Hibernate的组合很被看好,如果你感兴趣的话,可以到SpringFramework中文论坛上看看。下面转入本文的正题。

  Spring 标记库介绍及用法:

  本文将重点介绍Spring 提供的标记库及其用法:

  当你在项目中用Spring Framework的时候,表现层可以选择Spring Framework自带的标记库。当然,这不是你唯一的选择。你可以选择其它标记库或模板替换技术。Spring Framework 并没有为应用提供非常丰富的标记库。Spring Framework 提供的标记库仅仅是为了够用就行,它并不是无所不包的。呵呵,这点与Struts丰富的标记库不一样。其实这点符合RodJohnson的出发点,既“不造轮子”。当然,Spring Framework标记库有它自身的特点,可以说是个有益的补充吧。

  Spring 标记库分类如下:

  1、spring:hasBindErrors

  2、spring:bind

  3、spring:transform

  4、spring:message

  5、spring:htmlEscape

  6、spring:theme

  下面我们来具体介绍一下用法:

  1、spring:hasBindErrors

  对应org.springframework.web.servlet.tags.BindErrorsTag标记库处理类。

  这个标记提供用于绑定对象的errors,如果这个标记被用到的话,那么关于这个对象的错误将在页面上显示出来。使用这个标记的前提条件是要先使用<spring:bind>标记,并且<spring:hasBindErrors>这个标记不能用来表示对象的状态,它仅仅可以绑定对象本身和对象的属性。 具体用法如下:

<spring:hasBindErrors name="priceIncrease"> <b>Please fix all errors!</b> </spring:hasBindErrors>

  通过这个简单的例子,我来具体说一下这个标记的属性吧。

  name:是要被检查的Bean的名字。这个属性是必需要的。

  这里是简单用法,所以就不介绍它包含的errors变量了。具体看英语文档。下同。

  2、spring:bind

  对应org.springframework.web.servlet.tags.BindTag标记库处理类

  这个标记用来为某个bean或bean 的属性赋值,通常和form一起用,相当于action的作用。它指明表单要提交到那个类或类的属性中去。

  其中path属性是必须的,指明转到的类的路径。举例如下:

<form method="post">
<table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
<tr>
<td alignment="right" width="20%">Increase (%):</td>
<spring:bind path="priceIncrease.percentage">
<td width="20%">
<input type="text" name="percentage" value="<c:out value="${status.value}"/>">
</td>
<td width="60%">
<font color="red"><c:out value="${status.errorMessage}"/></font>
</td>
</spring:bind>
</tr>
</table>
<br>
……………………省略
</form>

 3、spring:transform

  对应org.springframework.web.servlet.tags.TransformTag标记库处理类,这个标记用来转换表单中不与bean中的属性一一对应的那些属性,通常和<spring:bind>一起使用。<spring:transform>标记为<spring:bind>使用提供了更好的支持。

  属性如下:

  value:必需要的。和当前<spring:bind>标记指向的bean类相同。就是你要转换的实体类名。

  var:不是必需的。这个字符串被用来绑定输出结果到page,request, session或application scope.默认情况输出到jsp中。

  scope:不是必需的。前提条件var必须设置的情况下。它的值可以是page,request, session或application。

  4、spring:message 对应org.springframework.web.servlet.tags.MessageTag标记库处理类

  这个标记用来帮助springframework支持国际化。和JSTL的fmt:message标记类似。当然这个标记可以很好的工作的本地的springframework框架下。

  属性如下:

  code:不是必需的。用来查找message,如果没有被使用的话,text将被使用。

  text:不是必需的。假如code不存在的话,默认是text输出。当code和text都没有设置的话,标记将输出为null.

  var:不是必需的。这个字符串被用来绑定输出结果到page,request, session或application scope.默认情况输出到jsp中。

  scope:不是必需的。前提条件var必须设置的情况下。它的值可以是page,request, session或application。

  5、spring:htmlEscape

  对应org.springframework.web.servlet.tags.HtmlEscapeTag标记库处理类

  不常用,这里省略

  6、spring:theme

  对应org.springframework.web.servlet.tags.ThemeTag标记库处理类

  不常用,这里省略

  学习完这些用法后,让我们来看个具体的例子吧。

  配置步骤如下:

  目录结构图:

-spirngapp
-WEB-INF
-classes
-lib
-src
-war

  1、将spring.tld拷贝到WEB-INF目录。

  2、将spring.jar拷贝到WEB-INF\lib包下

  举例如下:

  在web.xml中配置好taglib属性,代码如下:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'> 
<web-app> 
<servlet> 
<servlet-name>springapp</servlet-name> 
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
<load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
<servlet-name>springapp</servlet-name> 
<url-pattern>*.htm</url-pattern> 
</servlet-mapping> 
<welcome-file-list> 
<welcome-file> index.jsp </welcome-file> 
</welcome-file-list> 
<taglib> 
<taglib-uri>/spring</taglib-uri> 
<taglib-location>/WEB-INF/spring.tld</taglib-location> 
</taglib> 
</web-app> 

  jsp页面代码如下:

<%@ include file="/WEB-INF/jsp/include.jsp" %> 
<%@ taglib prefix="spring" uri="/spring" %> 
<html> 
<head> 
<title><fmt:message key="title"/></title> 
</head> 
<body> 
<h1> 
<fmt:message key="priceincrease.heading"/> 
</h1> 
<form method="post"> 
<table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5"> 
<tr> 
<td alignment="right" width="20%">Increase (%):</td> 
<spring:bind path="priceIncrease.percentage"> 
<td width="20%"> 
<input type="text" name="percentage" value="<c:out value="${status.value}"/>"> 
</td> 
<td width="60%"> 
<font color="red"> 
<c:out value="${status.errorMessage}"/> 
</font> 
</td> 
</spring:bind> 
</tr> 
</table> 
<br> 
<spring:hasBindErrors name="priceIncrease"> 
<b>Please fix all errors!</b> 
</spring:hasBindErrors> <br><br> 
<input type="submit" alignment="center" value="Execute"> 
</form> 
<a href="<c:url value="hello.htm"/>">Home</a> 
</body> 
</html> 

  <spring:bind>标记经常用来绑定<input>表单元素以便提交给PriceIncrease.java,其实PriceIncrease.java中就是包含一些getter和setter的方法的类。当用户按下按钮提交的时候,其表单中的值实际上就被framework放到了PriceIncrease.java中。<spring:bind>经常和form一起使用.这个${status.errorMessage}和${status.value}是一个framework定义的特殊变量,它们被用来显示错误信息和当前表单中的数据。呵呵,今天就到此为止吧,关于Spring Framework标记库的详细用法,请参考其文档。
posted @ 2006-05-28 20:11 konhon 优华 阅读(391) | 评论 (0)编辑 收藏

 

热键篇:
TemplateAlt + /
修改处:窗口->喜好设定->工作台->按键->编辑->内容辅助。
个人习惯:Shift+SPACE(空白)
简易说明:编辑程序代码时,打sysout +Template启动键,就
会自动出现:System.out.println();
设定Template的格式:窗口->喜好设定->Java->编辑器->模板。

程序代码自动排版:Ctrl+Shift+F
修改处:窗口->喜好设定->工作台->按键->程序代码->格式。
个人习惯:Alt+Z
自动排版设定:窗口->喜好设定->Java->程序代码格式制作程序。
样式页面->将插入tab(而非空格键)以内缩,该选项取消勾选
,下面空格数目填4,这样在自动编排时会以空格4作缩排。

快速执行程序:Ctrl + F11
个人习惯:ALT+X
修改处:窗口->喜好设定->工作台->按键->执行->启动前一次的启动作业。
简易说明:第一次执行时,它会询问您执行模式,
设置好后,以后只要按这个热键,它就会快速执行。
<ALT+Z(
排版完)ATL+X(执行)>..我觉得很顺手^___^

自动汇入所需要的类别:Ctrl+Shift+O
简易说明:
假设我们没有Import任何类别时,当我们在程序里打入:

BufferedReader buf =
new BufferedReader(new InputStreamReader(System.in));

此时Eclipse会警示说没有汇入类别,这时我们只要按下Ctrl+Shift+O
,它就会自动帮我们Import类别。

查看使用类别的原始码:Ctrl+鼠标左键点击
简易说明:可以看到您所使用类别的原始码。

将选取的文字批注起来:Ctrl+/
简易说明:Debug时很方便。
修改处:窗口->喜好设定->工作台->按键->程序代码->批注

视景切换:Ctrl+F8
个人习惯:Alt+S
修改处:窗口->喜好设定->工作台->按键->窗口->下一个视景。
简易说明:可以方便我们快速切换编辑、除错等视景。

密技篇:
一套Eclipse可同时切换,英文、繁体、简体显示:
1.
首先要先安装完中文化包。
2.
在桌面的快捷方式后面加上参数即可,
英文-> -nl "zh_US"
繁体-> -nl "zh_TW"
简体-> -nl "zh_CN"
(
其它语系以此类推)
像我2.1.2中文化后,我在我桌面的Eclipse快捷方式加入参数-n1 "zh_US"
"C:\Program Files\eclipse\eclipse.exe" -n "zh_US"
接口就会变回英文语系噜。

利用Eclipse,在Word编辑文书时可不必将程序代码重新编排:
Eclipse程序编辑区的程序代码整个复制下来(Ctrl+C),直接贴(Ctrl+V)
Word
WordPad上,您将会发现在Word里的程序代码格式,跟Eclipse
所设定的完全一样,包括字型、缩排、关键词颜色。我曾试过JBuilder
GELNetBeans...使用复制贴上时,只有缩排格式一样,字型、颜
色等都不会改变。

外挂篇:
外挂安装:将外挂包下载回来后,将其解压缩后,您会发现features
plugins
2个数据夹,将里面的东西都复制或移动到Eclipsefeatures
plugins数据夹内后,重新启动Eclipse即可。

Eclipse可以像JBuilderX一样使用拖拉方式建构GUI的外挂:
1.Jigloo SWT/Swing GUI Builder

http://cloudgarden.com/jigloo/index.html
下载此版本:Jigloo plugin for Eclipse (using Java 1.4 or 1.5)
安装后即可由档案->新建->其它->GUI Form选取要建构的GUI类型。

2.Eclipse Visual Editor Project

http://www.eclipse.org/vep/
点选下方Download Page,再点选Latest Release 0.5.0进入下载。
除了VE-runtime-0.5.0.zip要下载外,以下这2个也要:
EMF build 1.1.1: (build page) (download zip)
GEF Build 2.1.2: (build page) (download zip)

3.0 M8
版本,请下载:
EMF build I200403250631
GEF Build I20040330
VE-runtime-1.0M1

安装成功后,便可由File->New->Visual Class开始UI设计。
安装成功后,即可由新建->Java->AWTSwing里选择
所要建构的GUI类型开始进行设计。VE必须配合着对应
版本,才能正常使用,否则即使安装成功,使用上仍会
有问题。

使用Eclipse来开发JSP程序:
外挂名称:lomboz(下载页面)
http://forge.objectweb.org/project/showfiles.php?group_id=97
请选择适合自己版本的lomboz下载,lomboz.212.p1.zip表示2.1.2版,
lomboz.3m7.zip
表示M7版本....以此类推。
lomboz
安装以及设置教学:
Eclipse开发JSP-教学文件

Java
exe篇:
实现方式:Eclipse搭配JSmooth(免费)
1.
先由Eclipse制作包含ManifestJAR
制作教学
2.
使用JSmooth将做好的JAR包装成EXE
JSmooth
下载页面:
http://jsmooth.sourceforge.net/index.php
3.
制作完成的exe文件,可在有装置JREWindows上执行。

Eclipse-Java
编辑器最佳设定:
编辑器字型设定:工作台->字型->Java编辑器文字字型。
(
建议设定Courier New -regular 10)

编辑器相关设定:窗口->喜好设定->Java->编辑器

外观:显示行号、强调对称显示的方括号、强调显示现行行、
显示打印边距,将其勾选,Tab宽度设4,打印编距字段设80
程序代码协助:采预设即可。
语法:可设定关键词、字符串等等的显示颜色。
附注:采预设即可。
输入:全部字段都勾选。
浮动说明:采预设即可。
导览:采预设即可。

使自动排版排出来的效果,最符合Java设计惯例的设定:
自动排版设定:窗口->喜好设定->Java->程序代码制作格式。

换行:全部不勾选。
分行:行长度上限设:80
样式:只将强制转型后插入空白勾选。
内缩空格数目:设为4

Eclipse
的教学文件:
Eclipse 3.0系列热键表 - 中英对照解说版 (by sungo) ~New~
Window+GCC+CDT用Eclipse开发C、C++ (by sungo) ~New~

其它:
扩充Eclipse的Java 开发工具(中文)
使用Eclipse开发J2EE 应用程序(中文)
使用Eclipse平台进行除错(中文)
用Eclipse进行XML 开发(中文)
开发Eclipse外挂程序(中文)
国际化您的Eclipse外挂程序(英文)
将Swing编辑器加入Eclipse(英文)
如何测试你的Eclipse plug-in符合国际市场需求(英文)

Eclipse
的相关网站:
http://eclipse-plugins.2y.net/eclipse/index.jsp
http://www.eclipseplugincentral.com/
Eclipse相关教学[简体]

posted @ 2006-05-26 03:37 konhon 优华 阅读(477) | 评论 (0)编辑 收藏

我們經常為每一個Action撰寫一個Controller類別,很快的,您發現到您的Web應用程式下越來越多的Controller類別,而事實上當中的方法是可以組織在一起成為一個類別檔案,例如與資料庫操作相關的list()、add()、delete()等方法,就可以組織為一個類別。

 要將相關的方法組織在一個檔案中,只使用一個handleRequest()方法似乎是不夠的,我們希望同一個Controller中可以根據我們的指定來Action中的某個方法,而不只是使用handleRequest()方法。

 作為org.springframework.web.servlet.mvc.AbstractController下的另一個子類別:org.springframework.web.servlet.mvc.multiaction.MultiActionController,它可以讓我們在一個Controller類別中定義多個方法,並根據我們的請求來呼叫當中的某個方法來執行。

 如果您瞭解Struts,其DispatchAction就類似於Spring的MultiActionController類別,所不同的是,MultiActionController擁有比Struts的DispatchAction更多樣化的方式來參數化與組織這些Action。

 要使用MultiActionController,您要配合一個MethodNameResolver的實例,MultiActionController預設是InternalPathMethodNameResolver,這是最簡單的方式,根據您所給的網址最後的檔案名稱來判斷要執行Action中的哪一個方法,但通常我們不會使用InternalPathMethodNameResolver,因為這就失去了使用MultiActionController的一些優點,像是依請求參數來決定要呼叫的方法。

 我們通常會使用ParameterMethodNameResolver或PropertiesMethodNameResolver,在一個網址上結合請求參數,以參數來決定要執行哪一個Action,這邊以ParameterMethodNameResolver為例,首先,我們可以在bean定義檔中這麼撰寫:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
        <property name="mappings"> 
            <props> 
                <prop key="/book.do">bookAction</prop> 
            </props> 
        </property> 
    </bean> 
    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
        <property name="viewClass"> 
            <value>org.springframework.web.servlet.view.InternalResourceView</value> 
        </property> 
        <property name="prefix"> 
            <value>/WEB-INF/jsp/</value> 
        </property> 
        <property name="suffix"> 
            <value>.jsp</value> 
        </property> 
    </bean> 

    <bean id="paraMethodResolver" 
        class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> 
        <property name="paramName"><value>method</value></property> 
        <property name="defaultMethodName"><value>list</value></property> 
    </bean> 
        
    <bean id="bookAction" class="onlyfun.caterpillar.GuestBookAction"> 
        <property name="methodNameResolver"> 
            <ref bean="paraMethodResolver"/> 
        </property> 
        <property name="testPage"> 
            <value>test</value> 
        </property> 
    </bean> 
</beans>

 在paraMethodResolver中,我們使用paramName定義在http請求中使用method參數來指定要呼叫的方法,若是請求中沒有指定method參數,則會使用defaultMethodName所指定的方法,這邊指定的是list()方法。

 GuestBookAction是個繼承MultiActionController的類別,當中我們可以定義我們在method參數指定下所要呼叫的方法,例如:

GuestBookAction.java
package onlyfun.caterpillar; 

import javax.servlet.http.*; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.multiaction.MultiActionController; 

public class GuestBookAction extends MultiActionController { 
    privateString testPage; 
    
    public ModelAndView list(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "list"); 
    } 
    
    public ModelAndView add(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "add"); 
    } 
    
    public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "delete"); 
    } 
    
    publicString getTestPage() { 
        return testPage; 
    } 
    
    public void setTestPage(String testPage) { 
        this.testPage = testPage; 
    } 
}

 注意到我們的方法必須包括HttpServletRequest與HttpServletResponse作為參數,您也可以使用帶有第三個參數HttpSession的版本。

 上面的類別只是一個簡單的範例,用於測試MultiActionController的運作,我們測試用的JSP網頁如下:

<html> 
<head><title>Test</title></head> 
<body> 
    <H1> "${executed}" method is executed.</H2> 
</body> 
</html>

 當您使用以下的網址請求資源時:
http://localhost:8080/springapp/book.do?method=add

 我們的測試網頁將傳回以下的內容:

<html> 
<head><title>Test</title></head> 
<body> 
    <H1> "add" method is executed.</H2> 
</body> 
</html>

 您也可以將所有相對應的方法專門組織在一個委託(delegate)物件中,而不是撰寫在Controller類別中,當請求來到時,將委託給這個物件來執行指定的方法,您只要定義MultiActionController的delegate屬性即可,例如我們的委託物件如下:

BookActionDelegate.java
package onlyfun.caterpillar; 

import javax.servlet.http.*; 
import org.springframework.web.servlet.ModelAndView; 

public class BookActionDelegate { 
    privateString testPage; 
    
    public ModelAndView list(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "list"); 
    } 
    
    public ModelAndView add(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "add"); 
    } 
    
    public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) { 
        returnnew ModelAndView(this.getTestPage(),"executed", "delete"); 
    } 
    
    publicString getTestPage() { 
        return testPage; 
    } 
    
    public void setTestPage(String testPage) { 
        this.testPage = testPage; 
    } 
}

 現在我們不用定義GuestBookAction了,直接使用MultiActionController,只要定義Bean定義檔就好了:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
        <property name="mappings"> 
            <props> 
                <prop key="/book.do">bookAction</prop> 
            </props> 
        </property> 
    </bean> 
    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
        <property name="viewClass"> 
            <value>org.springframework.web.servlet.view.InternalResourceView</value> 
        </property> 
        <property name="prefix"> 
            <value>/WEB-INF/jsp/</value> 
        </property> 
        <property name="suffix"> 
            <value>.jsp</value> 
        </property> 
    </bean> 

    <bean id="paraMethodResolver" 
        class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> 
        <property name="paramName"><value>method</value></property> 
        <property name="defaultMethodName"><value>list</value></property> 
    </bean> 

    <bean id="bookActionDelegate" class="onlyfun.caterpillar.BookActionDelegate"> 
        <property name="testPage"> 
            <value>test</value> 
        </property> 
    </bean> 
    
    <bean id="bookAction" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController"> 
        <property name="methodNameResolver"> 
            <ref bean="paraMethodResolver"/> 
        </property> 
        <property name="delegate"> 
            <ref bean="bookActionDelegate"/> 
        </property> 
    </bean>    
</beans>

 測試的結果與上面是相同的。

 以上說明的是ParameterMethodNameResolver,而PropertiesMethodNameResolver的設定方法是類似的,有興趣的話,可以看一下Spring參考手冊中有關MultiActionController的說明,當中也有個簡明的設定範例。

posted @ 2006-05-25 20:07 konhon 优华 阅读(979) | 评论 (0)编辑 收藏

Hibernate3提供了DetachedCriteria,使得我们可以在Web层构造detachedCriteria,然后调用业务层Bean,进行动态条件查询,根据这一功能,我设计了通用的抽象Bean基类和分页类支持,代码来自于Quake Wang的javaeye-core包的相应类,然后又做了很多修改。

分页支持类:
package com.javaeye.common.util; 

import java.util.List; 

public class PaginationSupport { 

        
public final static int PAGESIZE = 30

        
private int pageSize = PAGESIZE; 

        
private List items; 

        
private int totalCount; 

        
private int[] indexes = new int[0]; 

        
private int startIndex = 0

        
public PaginationSupport(List items, int totalCount) { 
                setPageSize(PAGESIZE); 
                setTotalCount(totalCount); 
                setItems(items);                
                setStartIndex(
0); 
        } 

        
public PaginationSupport(List items, int totalCount, int startIndex) { 
                setPageSize(PAGESIZE); 
                setTotalCount(totalCount); 
                setItems(items);                
                setStartIndex(startIndex); 
        } 

        
public PaginationSupport(List items, int totalCount, int pageSize, int startIndex) { 
                setPageSize(pageSize); 
                setTotalCount(totalCount); 
                setItems(items); 
                setStartIndex(startIndex); 
        } 

        
public List getItems() { 
                
return items; 
        } 

        
public void setItems(List items) { 
                
this.items = items; 
        } 

        
public int getPageSize() { 
                
return pageSize; 
        } 

        
public void setPageSize(int pageSize) { 
                
this.pageSize = pageSize; 
        } 

        
public int getTotalCount() { 
                
return totalCount; 
        } 

        
public void setTotalCount(int totalCount) { 
                
if (totalCount > 0) { 
                        
this.totalCount = totalCount; 
                        
int count = totalCount / pageSize; 
                        
if (totalCount % pageSize > 0
                                count
++
                        indexes 
= new int[count]; 
                        
for (int i = 0; i < count; i++) { 
                                indexes[i] 
= pageSize * i; 
                        } 
                } 
else { 
                        
this.totalCount = 0
                } 
        } 

        
public int[] getIndexes() { 
                
return indexes; 
        } 

        
public void setIndexes(int[] indexes) { 
                
this.indexes = indexes; 
        } 

        
public int getStartIndex() { 
                
return startIndex; 
        } 

        
public void setStartIndex(int startIndex) { 
                
if (totalCount <= 0
                        
this.startIndex = 0
                
else if (startIndex >= totalCount) 
                        
this.startIndex = indexes[indexes.length - 1]; 
                
else if (startIndex < 0
                        
this.startIndex = 0
                
else { 
                        
this.startIndex = indexes[startIndex / pageSize]; 
                } 
        } 

        
public int getNextIndex() { 
                
int nextIndex = getStartIndex() + pageSize; 
                
if (nextIndex >= totalCount) 
                        
return getStartIndex(); 
                
else 
                        
return nextIndex; 
        } 

        
public int getPreviousIndex() { 
                
int previousIndex = getStartIndex() - pageSize; 
                
if (previousIndex < 0
                        
return 0
                
else 
                        
return previousIndex; 
        } 

}

抽象业务类
java代码: 
/** 
* Created on 2005-7-12 
*/ 
package com.javaeye.common.business; 

import java.io.Serializable; 
import java.util.List; 

import org.hibernate.Criteria; 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.criterion.DetachedCriteria; 
import org.hibernate.criterion.Projections; 
import org.springframework.orm.hibernate3.HibernateCallback; 
import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 

import com.javaeye.common.util.PaginationSupport; 

public abstract class AbstractManager extends HibernateDaoSupport { 

        
private boolean cacheQueries = false

        
private String queryCacheRegion; 

        
public void setCacheQueries(boolean cacheQueries) { 
                
this.cacheQueries = cacheQueries; 
        } 

        
public void setQueryCacheRegion(String queryCacheRegion) { 
                
this.queryCacheRegion = queryCacheRegion; 
        } 

        
public void save(final Object entity) { 
                getHibernateTemplate().save(entity); 
        } 

        
public void persist(final Object entity) { 
                getHibernateTemplate().save(entity); 
        } 

        
public void update(final Object entity) { 
                getHibernateTemplate().update(entity); 
        } 

        
public void delete(final Object entity) { 
                getHibernateTemplate().delete(entity); 
        } 

        
public Object load(final Class entity, final Serializable id) { 
                
return getHibernateTemplate().load(entity, id); 
        } 

        
public Object get(final Class entity, final Serializable id) { 
                
return getHibernateTemplate().get(entity, id); 
        } 

        
public List findAll(final Class entity) { 
                
return getHibernateTemplate().find("from " + entity.getName()); 
        } 

        
public List findByNamedQuery(final String namedQuery) { 
                
return getHibernateTemplate().findByNamedQuery(namedQuery); 
        } 

        
public List findByNamedQuery(final String query, final Object parameter) { 
                
return getHibernateTemplate().findByNamedQuery(query, parameter); 
        } 

        
public List findByNamedQuery(final String query, final Object[] parameters) { 
                
return getHibernateTemplate().findByNamedQuery(query, parameters); 
        } 

        
public List find(final String query) { 
                
return getHibernateTemplate().find(query); 
        } 

        
public List find(final String query, final Object parameter) { 
                
return getHibernateTemplate().find(query, parameter); 
        } 

        
public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria) { 
                
return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, 0); 
        } 

        
public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int startIndex) { 
                
return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, startIndex); 
        } 

        
public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize, 
                        
final int startIndex) { 
                
return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() { 
                        
public Object doInHibernate(Session session) throws HibernateException { 
                                Criteria criteria 
= detachedCriteria.getExecutableCriteria(session); 
                                
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue(); 
                                criteria.setProjection(
null); 
                                List items 
= criteria.setFirstResult(startIndex).setMaxResults(pageSize).list(); 
                                PaginationSupport ps 
= new PaginationSupport(items, totalCount, pageSize, startIndex); 
                                
return ps; 
                        } 
                }, 
true); 
        } 

        
public List findAllByCriteria(final DetachedCriteria detachedCriteria) { 
                
return (List) getHibernateTemplate().execute(new HibernateCallback() { 
                        
public Object doInHibernate(Session session) throws HibernateException { 
                                Criteria criteria 
= detachedCriteria.getExecutableCriteria(session); 
                                
return criteria.list(); 
                        } 
                }, 
true); 
        } 

        
public int getCountByCriteria(final DetachedCriteria detachedCriteria) { 
                Integer count 
= (Integer) getHibernateTemplate().execute(new HibernateCallback() { 
                        
public Object doInHibernate(Session session) throws HibernateException { 
                                Criteria criteria 
= detachedCriteria.getExecutableCriteria(session); 
                                
return criteria.setProjection(Projections.rowCount()).uniqueResult(); 
                        } 
                }, 
true); 
                
return count.intValue(); 
        } 

用户在web层构造查询条件detachedCriteria,和可选的startIndex,调用业务bean的相应findByCriteria方法,返回一个PaginationSupport的实例ps。

ps.getItems()得到已分页好的结果集
ps.getIndexes()得到分页索引的数组
ps.getTotalCount()得到总结果数
ps.getStartIndex()当前分页索引
ps.getNextIndex()下一页索引
ps.getPreviousIndex()上一页索引

 

 

posted @ 2006-04-06 21:37 konhon 优华 阅读(1525) | 评论 (1)编辑 收藏

那与jdk的版本没关系吧.

那是Eclipse提供这个提示功能给你吧.
你点它warning的icon两下Eclipse就会自动给定.
如果你不喜欢,可以把它关掉,
windows -> preferences -> compiler -> Error/Warnings
-> Potential Programming problems
将Serializable class without serialVersionUID的warning改成ignore.

其实如果你没有考虑到兼容性问题时,那就把它关掉吧.
其实有这个功能是好的.
只要任何类别实作了Serializable这个介面,
如果没有加入serialVersionUID,Eclipse都会给你warning提示,
这个serialVersionUID为了让该类别Serializable後兼容.

考虑一下,如果今天你的类Serialized存到硬碟里,
可是後来你却更改了类别的field(增加或减少或改名).
当你Deserialize时,就会出现Exception.这样就会做成不兼容性的问题.

但当serialVersionUID相同时,它就会将不一样的field以type的预设值Deserialize.
这个可以避开不兼容性的问题.

自於你说内存的问题,我觉得没差多少吧.
posted @ 2006-04-06 20:03 konhon 优华 阅读(4408) | 评论 (0)编辑 收藏

仅列出标题
共21页: First 上一页 2 3 4 5 6 7 8 9 10 下一页 Last