巍 的个人资料fantasyswall照片日志列表 工具 帮助

日志


2月24日

spring 源码

Spring源代码解析(一):IOC容器:http://www.javaeye.com/topic/86339
Spring源代码解析(二):IoC容器在Web容器中的启动:http://www.javaeye.com/topic/86594
Spring源代码解析(三):Spring JDBC:http://www.javaeye.com/topic/87034
Spring源代码解析(四):Spring MVC:http://www.javaeye.com/topic/87692
Spring源代码解析(五):Spring AOP获取Proxy:http://www.javaeye.com/topic/88187
Spring源代码解析(六):Spring声明式事务处理:http://www.javaeye.com/topic/88189
Spring源代码解析(七):Spring AOP中对拦截器调用的实现:http://www.javaeye.com/topic/107785
Spring源代码解析(八):Spring驱动Hibernate的实现:http://www.javaeye.com/topic/110801
Spring源代码解析(九):Spring Acegi框架鉴权的实现:http://www.javaeye.com/topic/112979
Spring源代码解析(十):Spring Acegi框架授权的实现:http://www.javaeye.com/topic/113436
10月28日

webwork 值栈

WebWork 原理

通过上面的例子,我们已经了解WebWork开发、运行的基本流程(一定要亲自安装,并开发这个Welcome的例子哦)。如果要在实际项目中使用WebWork,我们必须要了解下面的概念和WebWork的原理。

ValueStack( 值堆栈 ) EL( 表达式语言 )

关于ValueStack的描述:

1、 ValueStack其实就是一个放置Java对象的堆栈而已,唯一特别的是可以使用EL来获得值堆栈中对象属性的数据,并可以为值堆栈的对象属性赋值。

2、 EL,全称Express Language,即表达式语言。不要被语言吓倒,它是简单的对象导航语言。有字符串(例如:方法名)和特殊字符组成(例如用.表示调用对应的属性方法)。通过EL,我们可以存、取对象数据,而且还可以直接访问类的静态数据,调用静态方法。

3、 WebWorkValueStack底层有第三方开源项目OGNL实现。所以EL也都遵循OGNL的规范。我们在开发中,几乎不需要知道OGNL的细节。

4、 WebWork为每一次请求构建一个ValueStack,并将所有相关的数据对象(例如:Action对象、Model对象等)放到ValueStack中。再将ValueStack暴露给视图页面,这样页面就可以直接访问后台处理生成的数据。

下面我们用一个雇员类为例,使用Junit框架(单元测试框架)来展示ValueStack的功能。

我们有一个Employee类,它有两个属性:姓名,地址。姓名是一个字符串,地址是一个对象,地址类有国家、城市、街道三个属性。代码如下:

Employee.java代码如下:

public class Employee {

      private String name;

     

      private Address address;

     

      public Employee() {

      }

     

      public String getName() {

            return name;

      }

      public void setName(String name) {

            this.name = name;

      }

      public Address getAddress() {

            if(address == null)

                  address = new Address();

            return address;

      }

     

      public void setAddress(Address address) {

            this.address = address;

      }

}

Address.java代码如下:

public class Address {

            private String country;

            private String city;

            private String street;

           

            ……

            //默认的GetSet方法,省略

           

}

下面出场的是OgnlValueStackTest,它有两个测试方法。分别测试使用ELValueStack中取值和存值。代码如下:

import com.opensymphony.xwork.util.OgnlValueStack;

import junit.framework.TestCase;

public class OgnlValueStackTest extends TestCase {

            private OgnlValueStack valueStack;

            private Employee employee;

           

            @Override

            protected void setUp() throws Exception {

                        valueStack = new OgnlValueStack();

                        employee = new Employee();

                        valueStack.push(employee);

            }

            public void testCouldGetDataFromObjectInOgnlValueStackByEL() throws Exception{

                        employee.setName("Moxie");

                        Address address = new Address();

                        address.setCountry("China");

                        employee.setAddress(address);

                       

                        assertEquals("Moxie",valueStack.findValue("name"));

                        assertEquals("China",valueStack.findValue("address.country"));

            }

           

            public void testCouldSetDataForObjectInOgnlValueStackByEL() throws Exception{

                        valueStack.setValue("name","Moxie");

                        valueStack.setValue("address.country","China");

                       

                        assertEquals("Moxie",employee.getName());

                        assertEquals("China",employee.getAddress().getCountry());

            }

}

这是一个Junit Test,关于Junit的使用不是本篇文章的范畴。作为一个Java开发者,熟悉这样的测试框架是最基本的要求。setUp方法在每个测试方法调用之前都会执行,它用来初始化每个测试方法都需要的对象和数据。我们的setUp方法首先创建两个对象:valueStack对象和employee对象,然后将employee对象入栈。这样,emloyee对象就在值堆栈的最上端。

第一个测试方法testCouldGetDataFromObjectInOgnlValueStackByEL测试可以用表达式语言取得值堆栈里的对象数据。我们首先为值堆栈里的employee对象设置数据,设置了用户名和用户地址所在的国家。

第一个验证断言             assertEquals("Moxie",valueStack.findValue("name"))解释为:我们期望使用表达式语言“name”去ValueStack中查找得到的对象是”Moxie”。即期望valueStack.findValue("name")语句执行返回的数据是”Moxie”对象。再深入下去,这条语句会调用ValueStack里对象的getName方法(即employee对象的getName方法),并返回这个方法返回的数据。

第二个断言assertEquals("China",valueStack.findValue("address.country"))。它期望表达式语言“address.country”取得的数据是对象的address属性对象的country属性,即取得雇员对象的地址所在的国家。深入下去,它也就是调用对象employeegetAddress().getCountry()方法。 第二个测试方法testCouldSetDataForObjectInOgnlValueStackByEL测试通过表达式语言为ValueStack中的对象设置数据。

第一个设值语句valueStack.setValue("name","Moxie"),它通过表达式语言“name”将“”Moxie””赋值给ValueStack里的对象,即调用值堆栈中的对象的setName方法,并把后面的值作为方法的参数。同理,第二个设置语句会调用值堆栈中的对象的getAddress().setCountry()方法,把后面的数据作为setCountry方法的参数。

看了这个例子,我们就会知道如何通过ValueStack进行数据的存取。在我们使用ValueStack时需要注意:

1、 所有存取操作的目标对象都是已放入ValueStack中的对象。所以在使用之前,必须要先将对象入栈。例如我们在setup方法中的语句:valueStack.push(employee)

2、 每一次WebWork请求,在创建Action对象之前都会先生成一个ValueStack对象,再将Action对象入栈。这样我们就可以通过表达式语言来直接存取action对象的数据,所以在WebWork中,action具有数据模型的功能。

3、 在对ValueStack进行存取操作时,我们的操作指令(表达式语言)并不知道它是对哪个对象进行操作。例如,我们在获取员工姓名时,我们给的操作指令是”name”,这时,并不知道ValueStack里面的对象一定就是employeeValueStack会从上而下,遍历栈里面的对象,并试图调用当前遍历对象的getName方法,当它找到了这个方法,并执行之后,就会将执行得到的数据返回。这就是那神秘的ValueStack

4、 关于值堆栈的context map,它是一个放置值堆栈上下文数据的对象。通过符号“#“再加上对象的名称,可以访问这些数据(只可以访问)。一些JavaServlet相关的数据都放在这个容器中。这个对webwork的标签库特别有用,这样我们可以直接通过表达式语言去访问requestattributesessionapplication里的数据。例如:用property标签库打印出所有请求参数的数据,代码如下:<ww:property value="%{#request}"/>

5、 其它。“top”是ValueStack里面的关键字,通过它可以找到ValueStack中最上面的那个对象。可以试着打印一下valueStack.findValue("top"))看看。表达式语言除了可以调用基于JavaBean规范的getset方法之外,还可以调用一般的Java方法(这是需要使用方法的全名,并传入需要的参数),也可以直接访问Java类的静态字段和静态方法。具体的使用,可以查看WebWork的官方文档。

9月25日

Apache Jakarta Commons 工具集简介[转]

Apache Jakarta Commons 工具集简介[转] 
Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。我选了一些比较常用的项目做简单介绍。文中用了很多网上现成的东西,我只是做了一个汇总整理。 

一、Commons BeanUtils 

http://jakarta.apache.org/commons/beanutils/index.html 

说明:针对Bean的一个工具集。由于Bean往往是有一堆get和set组成,所以BeanUtils也是在此基础上进行一些包装。 

使用示例:功能有很多,网站上有详细介绍。一个比较常用的功能是Bean Copy,也就是copy bean的属性。如果做分层架构开发的话就会用到,比如从PO(Persistent Object)拷贝数据到VO(Value Object)。 

传统方法如下: 

//得到TeacherForm 

TeacherForm teacherForm=(TeacherForm)form; 

//构造Teacher对象 

Teacher teacher=new Teacher(); 

//赋值 
teacher.setName(teacherForm.getName()); 
teacher.setAge(teacherForm.getAge()); 
teacher.setGender(teacherForm.getGender()); 
teacher.setMajor(teacherForm.getMajor()); 
teacher.setDepartment(teacherForm.getDepartment()); 

//持久化Teacher对象到数据库 
HibernateDAO= ; 
HibernateDAO.save(teacher); 

使用BeanUtils后,代码就大大改观了,如下所示: 

//得到TeacherForm 
TeacherForm teacherForm=(TeacherForm)form; 
//构造Teacher对象 
Teacher teacher=new Teacher(); 

//赋值 
BeanUtils.copyProperties(teacher,teacherForm); 

//持久化Teacher对象到数据库 
HibernateDAO= ; 
HibernateDAO.save(teacher); 

二、Commons CLI 

http://jakarta.apache.org/commons/cli/index.html 

说明:这是一个处理命令的工具。比如main方法输入的string[]需要解析。你可以预先定义好参数的规则,然后就可以调用CLI来解析。 

使用示例: 

// create Options object 
Options options = new Options(); 
// add t option, option is the command parameter, false indicates that 
// this parameter is not required. 

options.addOption(“t”, false, “display current time”); 
options.addOption("c", true, "country code"); 

CommandLineParser parser = new PosixParser(); 
CommandLine cmd = parser.parse( options, args); 

if(cmd.hasOption("t")) { 
// print the date and time 
}else { 
// print the date 
} 

// get c option value 
String countryCode = cmd.getOptionValue("c"); 

if(countryCode == null) { 
// print default date 
}else { 
// print date for country specified by countryCode 
} 

三、Commons Codec 

http://jakarta.apache.org/commons/codec/index.html 

说明:这个工具是用来编码和解码的,包括Base64,URL,Soundx等等。用这个工具的人应该很清楚这些,我就不多介绍了。 

四、Commons Collections 

http://jakarta.apache.org/commons/collections/ 

说明:你可以把这个工具看成是java.util的扩展。 

使用示例:举一个简单的例子 

OrderedMap map = new LinkedMap(); 
map.put("FIVE", "5"); 
map.put("SIX", "6"); 
map.put("SEVEN", "7"); 
map.firstKey(); // returns "FIVE" 
map.nextKey("FIVE"); // returns "SIX" 
map.nextKey("SIX"); // returns "SEVEN" 

五、Commons Configuration 

http://jakarta.apache.org/commons/configuration/ 

说明:这个工具是用来帮助处理配置文件的,支持很多种存储方式 

1. Properties files 
2. XML documents 
3. Property list files (.plist) 
4. JNDI 
5. JDBC Datasource 
6. System properties 
7. Applet parameters 
8. Servlet parameters 

使用示例:举一个Properties的简单例子 

# usergui.properties, definining the GUI, 
colors.background = #FFFFFF 
colors.foreground = #000080 
window.width = 500 
window.height = 300 

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); 
config.setProperty("colors.background", "#000000); 
config.save(); 

config.save("usergui.backup.properties);//save a copy 
Integer integer = config.getInteger("window.width"); 

六、Commons DBCP 

http://jakarta.apache.org/commons/dbcp/ 

例子: 

import java.sql.*; 

import com.gwnet.games.antiLord.util.*; 

import org.apache.commons.dbcp.ConnectionFactory; 

import org.apache.commons.dbcp.BasicDataSource; 

import org.apache.commons.dbcp.DataSourceConnectionFactory; 



private static BasicDataSource bds=new BasicDataSource(); 

private static ConnectionFactory fac=null; 



//初始化连接池 

bds.setDriverClassName(“org.postgresql.Driver”); //数据库驱动程序 

bds.setUrl(“jdbc:postgresql://localhost:5432/myDB”); //数据库url 

bds.setUsername(“postgres”); //dba帐号 

bds.setPassword(“XXXXXXXX”); //密码 

bds.setInitialSize(100); //初始化连接数量 

bds.setMaxIdle(10); //最大idle数 

bds.setMaxWait(1000*60); //超时回收时间 

fac=new DataSourceConnectionFactory(bds); //得到连接工厂 

Connection conn=fac.createConnection(); //从池中获得连接 

conn.close(); //释放连接,回到池中 



//销毁连接池 

bds.close(); 
bds=null; 
fac=null; 

七、Commons DbUtils 

http://jakarta.apache.org/commons/dbutils/ 

说明:我以前在写数据库程序的时候,往往把数据库操作单独做一个包。DbUtils就是这样一个工具,以后开发不用再重复这样的工作了。值得一体的是,这个工具并不是现在流行的OR-Mapping工具(比如Hibernate),只是简化数据库操作,比如 

QueryRunner run = new QueryRunner(dataSource); 

// Execute the query and get the results back from the handler 
Object[] result = (Object[]) run.query("SELECT * FROM Person WHERE name=?", "John Doe"); 

八、Commons FileUpload 

http://jakarta.apache.org/commons/fileupload/ 

说明:jsp的上传文件功能怎么做呢? 

使用示例: 

// Create a factory for disk-based file items 
FileItemFactory factory = new DiskFileItemFactory(); 
// Create a new file upload handler 
ServletFileUpload upload = new ServletFileUpload(factory); 

// Parse the request 
List /* FileItem */ items = upload.parseRequest(request); 
// Process the uploaded items 
Iterator iter = items.iterator(); 
while (iter.hasNext()) { 
FileItem item = (FileItem) iter.next(); 
if (item.isFormField()) { 
processFormField(item); 
} else { 
processUploadedFile(item); 
} 
} 

九、Commons HttpClient 

http://jakarta.apache.org/commons/httpclient/ 

说明:这个工具可以方便通过编程的方式去访问网站。 

使用示例:最简单的Get操作 

GetMethod get = new GetMethod("http://jakarta.apache.org"); 

// execute method and handle any error responses. 

... 

InputStream in = get.getResponseBodyAsStream(); 
// Process the data from the input stream. 
get.releaseConnection(); 

十、Commons IO 

http://jakarta.apache.org/commons/io/ 

说明:可以看成是java.io的扩展,我觉得用起来非常方便。 

使用示例: 

1.读取Stream 

标准代码: 

InputStream in = new URL( "http://jakarta.apache.org" ).openStream(); 
try { 
InputStreamReader inR = new InputStreamReader( in ); 
BufferedReader buf = new BufferedReader( inR ); 
String line; 
while ( ( line = buf.readLine() ) != null ) { 
System.out.println( line ); 
} 
} finally { 
in.close(); 
} 

使用IOUtils 

InputStream in = new URL( "http://jakarta.apache.org" ).openStream(); 
try { 
System.out.println( IOUtils.toString( in ) ); 
} finally { 
IOUtils.closeQuietly(in); 
} 

2.读取文件 

File file = new File("/commons/io/project.properties"); 
List lines = FileUtils.readLines(file, "UTF-8"); 

3.察看剩余空间 
long freeSpace = FileSystemUtils.freeSpace("C:/"); 

十一、Commons JXPath 

http://jakarta.apache.org/commons/jxpath/ 

说明:Xpath你知道吧,那么JXpath就是基于Java对象的Xpath,也就是用Xpath对Java对象进行查询。这个东西还是很有想像力的。 

使用示例: 
Address address = (Address)JXPathContext.newContext(vendor). 
getValue("locations[address/zipCode='90210']/address"); 

上述代码等同于 
Address address = null; 
Collection locations = vendor.getLocations(); 
Iterator it = locations.iterator(); 
while (it.hasNext()){ 
Location location = (Location)it.next(); 
String zipCode = location.getAddress().getZipCode(); 
if (zipCode.equals("90210")){ 
address = location.getAddress(); 
break; 
} 
} 

十二、Commons Lang 

http://jakarta.apache.org/commons/lang/ 

说明:这个工具包可以看成是对java.lang的扩展。提供了诸如StringUtils, StringEscapeUtils, RandomStringUtils, Tokenizer, WordUtils等工具类。 

十三、Commons Logging 

http://jakarta.apache.org/commons/logging/ 

说明:你知道Log4j吗? 

十四、Commons Math 

http://jakarta.apache.org/commons/math/ 

说明:看名字你就应该知道这个包是用来干嘛的了吧。这个包提供的功能有些和Commons Lang重复了,但是这个包更专注于做数学工具,功能更强大。 

十五、Commons Net 

http://jakarta.apache.org/commons/net/ 

说明:这个包还是很实用的,封装了很多网络协议。 

1. FTP 
2. NNTP 
3. SMTP 
4. POP3 
5. Telnet 
6. TFTP 
7. Finger 
8. Whois 
9. rexec/rcmd/rlogin 
10. Time (rdate) and Daytime 
11. Echo 
12. Discard 
13. NTP/SNTP 

使用示例: 
TelnetClient telnet = new TelnetClient(); 
telnet.connect( "192.168.1.99", 23 ); 
InputStream in = telnet.getInputStream(); 
PrintStream out = new PrintStream( telnet.getOutputStream() ); 
... 
telnet.close(); 

十六、Commons Validator 

http://jakarta.apache.org/commons/validator/ 

说明:用来帮助进行验证的工具。比如验证Email字符串,日期字符串等是否合法。 

使用示例: 

// Get the Date validator 
DateValidator validator = DateValidator.getInstance(); 
// Validate/Convert the date 
Date fooDate = validator.validate(fooString, "dd/MM/yyyy"); 
if (fooDate == null) { 
// error...not a valid date 
return; 
} 

十七、Commons Virtual File System 

http://jakarta.apache.org/commons/vfs/ 

说明:提供对各种资源的访问接口。支持的资源类型包括 

1. CIFS 
2. FTP 
3. Local Files 
4. HTTP and HTTPS 
5. SFTP 
6. Temporary Files 
7. WebDAV 
8. Zip, Jar and Tar (uncompressed, tgz or tbz2) 
9. gzip and bzip2 
10. res 
11. ram 

这个包的功能很强大,极大的简化了程序对资源的访问。 

使用示例: 

从jar中读取文件 

// Locate the Jar file 
FileSystemManager fsManager = VFS.getManager(); 
FileObject jarFile = fsManager.resolveFile( "jar:lib/aJarFile.jar" ); 

// List the children of the Jar file 
FileObject[] children = jarFile.getChildren(); 
System.out.println( "Children of " + jarFile.getName().getURI() ); 
for ( int i = 0; i < children.length; i++ ){ 
System.out.println( children[ i ].getName().getBaseName() ); 
} 

从smb读取文件 
StaticUserAuthenticator auth = new StaticUserAuthenticator("username", "password", null); 
FileSystemOptions opts = new FileSystemOptions(); 
DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, auth); 
FileObject fo = VFS.getManager().resolveFile("smb://host/anyshare/dir", opts); 

十八、Commons-Email 

commons-email是apache提供的一个开源的API,是对javamail的封装,因此在使用时要将javamail.jar加到 class path中,主要包括SimpleEmail,MultiPartEmail,HtmlEmail,EmailAttachment四个类。 

SimpleEmail:发送简单的email,不能添加附件 
MultiPartEmail:文本邮件,可以添加多个附件 
HtmlEmail:HTML格式邮件,同时具有MultiPartEmail类所有“功能” 
EmailAttchment:附件类,可以添加本地资源,也可以指定网络上资源,在发送时自动将网络上资源下载发送。 

发送基本文本格式邮件: 
============== 
SimpleEmail email = new SimpleEmail(); 
//smtp host 
email.setHostName("mail.test.com"); 
//登陆邮件服务器的用户名和密码 
email.setAuthentication("test","testpassword"); 
//接收人 
email.addTo("jdoe@somewhere.org", "John Doe"); 
//发送人 
email.setFrom("me@apache.org", "Me"); 
//标题 
email.setSubject("Test message"); 
//邮件内容 
email.setMsg("This is a simple test of commons-email"); 
//发送 
email.send(); 

发送文本格式,带附件邮件: 
================== 
//附件,可以定义多个附件对象 
EmailAttachment attachment = new EmailAttachment(); 
attachment.setPath("e:\\1.pdf"); 
attachment.setDisposition(EmailAttachment.ATTACHMENT); 
attachment.setDescription("Picture of John"); 
// 
MultiPartEmail email = new MultiPartEmail(); 
//smtp host 
email.setHostName("mail.test.com"); 
//登陆邮件服务器的用户名和密码 
email.setAuthentication("test","testpassword"); 
//接收人 
email.addTo("jdoe@somewhere.org", "John Doe"); 
//发送人 
email.setFrom("me@apache.org", "Me"); 
//标题 
email.setSubject("Test message"); 
//邮件内容 
email.setMsg("This is a simple test of commons-email"); 
//添加附件 
email.attach(attachment); 
//发送 
email.send(); 

发送HTML格式带附件邮件: 
================= 
//附件,可以定义多个附件对象 
EmailAttachment attachment = new EmailAttachment(); 
attachment.setPath("e:\\1.pdf"); 
attachment.setDisposition(EmailAttachment.ATTACHMENT); 
attachment.setDescription("Picture of John"); 
// 
HtmlEmail email = new HtmlEmail (); 
//smtp host 
email.setHostName("mail.test.com"); 
//登陆邮件服务器的用户名和密码 
email.setAuthentication("test","testpassword"); 
//接收人 
email.addTo("jdoe@somewhere.org", "John Doe"); 
//发送人 
email.setFrom("me@apache.org", "Me"); 
//标题 
email.setSubject("Test message"); 
//邮件内容 
email.setHtmlMsg("This is a simple test of commons-email"); 
//添加附件 
email.attach(attachment); 
//发送 

十九、 Commons Pool 

使用Jakarta Commons Pool可以根据需要快速的实现自己的对象池,只需要实现PoolableObjectFactory或者 KeyedPoolableObjectFactory接口。KeyedPoolableObjectFactory和 PoolableObjectFactory的不同之处在于KeyedPoolableObjectFactory的每个方法都比 PoolableObjectFactory多了一个Object key的参数,使用这个参数可以使得对象池中的每个对象都有所不同。 
PoolableObjectFactory定义了五个方法(摘至Jakarta Commons Pool API文档): 

1. makeObject is called whenever a new instance is needed. 
2. activateObject is invoked on every instance before it is returned from the pool. 
3. passivateObject is invoked on every instance when it is returned to the pool. 
4. destroyObject is invoked on every instance when it is being "dropped" from the pool (whether due to the response from validateObject, or for reasons specific to the pool implementation.) 
5. validateObject is invoked in an implementation-specific fashion to determine if an instance is still valid to be returned by the pool. It will only be invoked on an "activated" instance. 


二十、Commons Digester 

它能方便地将XML文档所定义的元素转化为JAVA对象,其实它的用法有点象栈(当然内在的原理就是那个古老的东西,只是提供了更高一层的封装)。 

//生成一个digester。主要需要引进commons-logging.jar、commons-collections.jar、commons- beanutils.jar 
Digester digester = new Digester(); 

//设置对XML文档资料是否进行DTD验证 
digester.setValidating( false ); 

//当遇见 catalog 元素的时候,产生一个Catalog对象 
digester.addObjectCreate( "catalog", Catalog.class ); 

//当遇见 catalog 元素下面的book的时候,产生一个Book对象 
digester.addObjectCreate( "catalog/book", Book.class ); 
// 当遇见 catalog 元素下面的book的author时候,调用author属性的Set方法 
digester.addBeanPropertySetter( "catalog/book/author", "author" ); 
digester.addBeanPropertySetter( "catalog/book/title", "title" ); 
//当再一次遇见 catalog 元素下面的book的时候,调用catalog类的addBook()方法 
digester.addSetNext( "catalog/book", "addBook" ); 

digester.addObjectCreate( "catalog/magazine", Magazine.class ); 
digester.addBeanPropertySetter( "catalog/magazine/name", "name" ); 

digester.addObjectCreate( "catalog/magazine/article", Article.class ); 
//addSetProperties()是将对应元素的属性赋值。 
digester.addSetProperties( "catalog/magazine/article", "page", "page" ); 
digester.addBeanPropertySetter( "catalog/magazine/article/headline" ); 
digester.addSetNext( "catalog/magazine/article", "addArticle" ); 

digester.addSetNext( "catalog/magazine", "addMagazine" ); 
//"F:\\Digester\\catalog.xml"为XML文档 
File input = new File( "F:\\Digester\\catalog.xml" ); 
Catalog c = (Catalog)digester.parse( input ); 
System.out.println( c.toString() );
6月13日

send request only once

      if(str.indexOf("Referer: ")!=-1){
       String[] strs = str.split("\r\n");
       for(String temp:strs){
        if(temp.indexOf("Referer: ")!=-1){
         if(!referer.equals(temp)){
          referer = temp;
          System.out.println("++++++++++++++++++++++++++++++++++");
         }
        }
       }
      }
5月30日

HtmlBrowser

package com.test.hello;

import java.io.IOException;
import java.net.URL;
import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;

public class HtmlBrowser extends JFrame {
 JPanel contentPane; // 包含整个框架的容器
 BorderLayout borderLayoutAll = new BorderLayout();
 JLabel jLabelPrompt = new JLabel(); // 状态提示框
 JPanel jPanelMain = new JPanel();
 BorderLayout borderLayoutMain = new BorderLayout();
 JTextField textFieldURL = new JTextField(); // URL输入框
 JEditorPane jEditorPane = new JEditorPane(); // 显示网页内容的容器

 public HtmlBrowser() { // 定义构造方法
  try {
   jbInit(); // 初始化并显示界面
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 private void jbInit() throws Exception { // 界面初始化
  contentPane = (JPanel) getContentPane();
  contentPane.setLayout(borderLayoutAll);
  jPanelMain.setLayout(borderLayoutMain);
  jLabelPrompt.setText("请输入URL");
  textFieldURL.setText(""); // 清空文本框
  textFieldURL.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(ActionEvent e) {
    textFieldURL_actionPerformed(e);
   }
  });
  jEditorPane.setEditable(false); // 设置不可编辑
  jEditorPane
    .addHyperlinkListener(new javax.swing.event.HyperlinkListener() {
     public void hyperlinkUpdate(HyperlinkEvent e) {
      jEditorPane_hyperlinkUpdate(e);
     }
    });
  JScrollPane scrollPane = new JScrollPane();
  scrollPane.getViewport().add(jEditorPane);
  jPanelMain.add(textFieldURL, "North");
  jPanelMain.add(scrollPane, "Center");
  contentPane.add(jLabelPrompt, "North");
  contentPane.add(jPanelMain, "Center");
  enableEvents(AWTEvent.WINDOW_EVENT_MASK);
  this.setSize(new Dimension(600, 500));
  this.setTitle("迷你IE ");
  this.setVisible(true);
 }

 void textFieldURL_actionPerformed(ActionEvent e) { // 输入地址后响应回车
  try {
   jEditorPane.setPage(textFieldURL.getText()); // 显示URL
  } catch (IOException ex) {
   JOptionPane msg = new JOptionPane();
   JOptionPane.showMessageDialog(this, "URL地址不正确:"
     + textFieldURL.getText(), "输入不正确!", 0);
  }
 }

 void jEditorPane_hyperlinkUpdate(HyperlinkEvent e) { // 响应页面打开超链接消息
  if (e.getEventType() == javax.swing.event.HyperlinkEvent.EventType.ACTIVATED) {
   try {
    URL url = e.getURL(); // 从消息中得到URL
    jEditorPane.setPage(url); // 显示页面内容
    textFieldURL.setText(url.toString()); // 显示URL
   } catch (IOException io) {
    JOptionPane msg = new JOptionPane();
    JOptionPane.showMessageDialog(this, "打开该链接失败!", "输入不正确!", 0);
   }
  }
 }

 protected void processWindowEvent(WindowEvent e) { // 处理窗体事件
  super.processWindowEvent(e);
  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
   System.exit(0); // 关闭
  }
 }

 public static void main(String[] args) { // Main函数
  new HtmlBrowser();
 }
}

5月23日

java client for http

package com.test.hello;
import java.net.*;  
 
import java.io.*;  
 
import java.util.Properties;  
 
import java.util.Enumeration;  
 
 
/** 
 
 Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的 
 
 是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜。本文根据HTTP 
 
 协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序. 
 
 
 <pre> 
 
 
 1.Socket类: 
 
 了解TCP/IP协议集通信的读者知道,协议间的通信是通过Socket完成的。在 
 
 Java.net包中,Socket类就是对Socket的具体实现。它通过连接到主机后,返回一个 
 
 I/O流,实现协议间的信息交换。 
 
 
 2 . HTTP协议 
 
 HTTP协议同其它TCP/IP协议集中的协议一样,是遵循客户/服务器模型工作的。客 
 
 户端发往服务端的信息格式如下: 
 
 ------------------------------ 
 
 请求方法 URL HTTP协议的版本号 
 
 提交的元信息 
 
 **空行** 
 
 实体 
 
 ------------------------------ 
 
 请求方法是对这次连接工作的说明,目前HTTP协议已经发展到1.1版,它包括GET、 
 
 HEAD、POST、DELETE、OPTIONS、TRACE、PUT七种。元信息是关于当前请求的信息。通 
 
 过分析元信息,可以检查实体数据是否完整,接收过程是否出错,类型是否匹配等。元 
 
 信息的引入使HTTP协议通信更加稳妥可靠。实体是请求的具体内容。 
 
 将上述报文发往Web服务器,如果成功,应答格式如下: 
 
 -------------------------------- 
 
 HTTP协议的版本号 应答状态码 应答状态码说明 
 
 接收的元信息 
 
 **空行** 
 
 实体 
 
 -------------------------------- 
 
 以上报文发向客户端,并且接收成功,彼此间关闭连接,完成一次握手。 
 
 下面用最常用的GET方法,来说明具体的报文应用 
 
 ---------------------------------- 
 
 GET http://www.youhost.com HTTP/1.0 
 
 accept: www/source; text/html; image/gif; image/jpeg; */* 
 
 User_Agent: myAgent 
 
 **空行** 
 
 ----------------------------------- 
 
 这个报文是向www.youhost.com主机请求一个缺省HTML文档。客户端HTTP协议版本 
 
 号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分 
 
 隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码: 
 
 ------------------------------------ 
 
 HTTP/1.1 200 OK 
 
 Date: Tue, 14 Sep 1999 02:19:57 GMT 
 
 Server: Apache/1.2.6 
 
 Connection: close 
 
 Content-Type: text/html 
 
 **空行** 
 
 <html><head>...</head><body>...</body></html> 
 
 ------------------------------------ 
 
 HTTP/1.1表示这个HTTP服务器是1.1版,200是服务器对客户请求的应答状态码,OK 
 
 是对应答状态码的解释,之后是这个文档的元信息和文档正文。(相关应答状态码和元 
 
 信息的解释请参阅Inetrnet标准草案:RFC2616)。 
 
 
 注: 程序中只实现GET、HEAD、POST三种方法。其他几种因不常使用,暂且忽略。 
 
 
 </pre> 
 
 
 */ 
 
 
import java.net.*;
import java.io.*;
import java.util.Properties;
import java.util.Enumeration;

/**
 Http客户端程序已集成在Java语言中,可以通过URLConnection类调用。遗憾的
 是,由于SUN没有公布Http客户程序的源码,它实现的细节仍是一个谜。本文根据HTTP
 协议规范,用Java.net.Socket类实现一个HTTP协议客户端程序.

 <pre>

 1.Socket类:
 了解TCP/IP协议集通信的读者知道,协议间的通信是通过Socket完成的。在
 Java.net包中,Socket类就是对Socket的具体实现。它通过连接到主机后,返回一个
 I/O流,实现协议间的信息交换。

 2 . HTTP协议
 HTTP协议同其它TCP/IP协议集中的协议一样,是遵循客户/服务器模型工作的。客
 户端发往服务端的信息格式如下:
 ------------------------------
 请求方法 URL HTTP协议的版本号
 提交的元信息
 **空行**
 实体
 ------------------------------
 请求方法是对这次连接工作的说明,目前HTTP协议已经发展到1.1版,它包括GET、
 HEAD、POST、DELETE、OPTIONS、TRACE、PUT七种。元信息是关于当前请求的信息。通
 过分析元信息,可以检查实体数据是否完整,接收过程是否出错,类型是否匹配等。元
 信息的引入使HTTP协议通信更加稳妥可靠。实体是请求的具体内容。
 将上述报文发往Web服务器,如果成功,应答格式如下:
 --------------------------------
 HTTP协议的版本号 应答状态码 应答状态码说明
 接收的元信息
 **空行**
 实体
 --------------------------------
 以上报文发向客户端,并且接收成功,彼此间关闭连接,完成一次握手。
 下面用最常用的GET方法,来说明具体的报文应用
 ----------------------------------
 GET http://www.youhost.com HTTP/1.0
 accept: www/source; text/html; image/gif; image/jpeg; */*
 User_Agent: myAgent
 **空行**
 -----------------------------------
 这个报文是向www.youhost.com主机请求一个缺省HTML文档。客户端HTTP协议版本
 号是1.0版,元信息包括可接收的文件格式,用户代理,每一段之间用回车换行符分
 隔,最后以一个空行结束。发向服务器后,如果执行过程正常,服务器返回以下代码:
 ------------------------------------
 HTTP/1.1 200 OK
 Date: Tue, 14 Sep 1999 02:19:57 GMT
 Server: Apache/1.2.6
 Connection: close
 Content-Type: text/html
 **空行**
 <html><head>...</head><body>...</body></html>
 ------------------------------------
 HTTP/1.1表示这个HTTP服务器是1.1版,200是服务器对客户请求的应答状态码,OK
 是对应答状态码的解释,之后是这个文档的元信息和文档正文。(相关应答状态码和元
 信息的解释请参阅Inetrnet标准草案:RFC2616)。

 注: 程序中只实现GET、HEAD、POST三种方法。其他几种因不常使用,暂且忽略。

 </pre>

 */
public class Http{
    protected Socket client;
    protected BufferedOutputStream sender;
    protected BufferedInputStream receiver;
    protected ByteArrayInputStream byteStream;
    protected URL target;
    private int responseCode = -1;
    private String responseMessage = "";
    private String serverVersion = "";
    private Properties header = new Properties();

    public Http(){}

    public Http(String url){
        GET(url);
    }
    public static void main(String[] args){
     Http http = new Http("http://localhost:8080/test/index.html");
     System.out.println(http.getResponseMessage());
    }
    /* GET方法根据URL,会请求文件、数据库查询结果、程序运行结果等多种内容 */
    public void GET(String url){
        try{
            checkHTTP(url);
            openServer(target.getHost(),target.getPort());
            String cmd = "GET " + getURLFormat(target) + " HTTP/1.0\r\n" +
            getBaseHeads() + "\r\n";
            sendMessage(cmd);
            receiveMessage();
        }
        catch(ProtocolException p){
            p.printStackTrace();
            return;
        }
        catch(UnknownHostException e){
            e.printStackTrace();
            return;
        }
        catch(IOException i){
            i.printStackTrace();
            return;
        }
    }

    /*
     * HEAD方法只请求URL的元信息,不包括URL本身。若怀疑本机和服务器上的
     * 文件相同,用这个方法检查最快捷有效。
     */
    public void HEAD(String url){
        try{
            checkHTTP(url);
            openServer(target.getHost(),target.getPort());
            String cmd = "HEAD " + getURLFormat(target) + " HTTP/1.0\r\n" +
            getBaseHeads() + "\r\n";
            sendMessage(cmd);
            receiveMessage();
        }
        catch(ProtocolException p){
            p.printStackTrace();
            return;
        }
        catch(UnknownHostException e){
            e.printStackTrace();
            return;
        }
        catch(IOException i){
            i.printStackTrace();
            return;
        }
    }

    /*
     * POST方法是向服务器传送数据,以便服务器做出相应的处理。例如网页上常用的
     * 提交表格。
     */
    public void POST(String url,String content){
        try{
            checkHTTP(url);
            openServer(target.getHost(),target.getPort());
            String cmd = "POST " + getURLFormat(target) + " HTTP/1.0\r\n" +
            getBaseHeads();
            cmd += "Content-type: application/x-www-form-urlencoded\r\n";
            cmd += "Content-length: " + content.length() + "\r\n\r\n";
            cmd += content + "\r\n";
            sendMessage(cmd);
            receiveMessage();
        }
        catch(ProtocolException p){
            p.printStackTrace();
            return ;
        }
        catch(UnknownHostException e){
            e.printStackTrace();
            return ;
        }
        catch(IOException i){
            i.printStackTrace();
            return ;
        }

    }

    protected void checkHTTP(String url) throws ProtocolException{
        try{
            URL target = new URL(url);
            if(target == null ||
               !target.getProtocol().toUpperCase().equals("HTTP")){
                throw new ProtocolException("这不是HTTP协议");
            }
            this.target = target;
        }
        catch(MalformedURLException m){
            throw new ProtocolException("协议格式错误");
        }
    }

    /*
     * 与Web服务器连接。若找不到Web服务器,InetAddress会引发UnknownHostException
     * 异常。若Socket连接失败,会引发IOException异常。
     */
    protected void openServer(String host,int port) throws UnknownHostException,
    IOException{
        header.clear();
        responseMessage = "";
        responseCode = -1;

        if(client != null){
            closeServer();
        }
        if(byteStream != null){
            byteStream.close();
            byteStream = null;
        }

        InetAddress address = InetAddress.getByName(host);
        client = new Socket(address,port == -1 ? 80 : port);
        client.setSoTimeout(5000);
        sender = new BufferedOutputStream(client.getOutputStream());
        receiver = new BufferedInputStream(client.getInputStream());
    }

    /* 关闭与Web服务器的连接 */
    protected void closeServer() throws IOException{
        if(client == null){
            return;
        }
        try{
            client.close();
            sender.close();
            receiver.close();
        }
        catch(IOException i){
            throw i;
        }

        client = null;
        sender = null;
        receiver = null;
    }

    protected String getURLFormat(URL target){
        String spec = "http://" + target.getHost();
        if(target.getPort() != -1){
            spec += ":" + target.getPort();
        }

        return spec += target.getFile();
    }

    /* 向Web服务器传送数据 */
    protected void sendMessage(String data) throws IOException{
        sender.write(data.getBytes(),0,data.length());
        sender.flush();
    }

    /* 接收来自Web服务器的数据 */
    protected void receiveMessage() throws IOException{
        byte data[] = new byte[1024];
        int count = 0;
        int word = -1;
        // 解析第一行
        while( (word = receiver.read()) != -1){
            if(word == '\r' || word == '\n'){
                word = receiver.read();
                if(word == '\n') {
                    word = receiver.read();
                }
                break;
            }
            if(count == data.length) {
                data = addCapacity(data);
            }
            data[count++] = (byte) word;
        }
        String message = new String(data,0,count);
        int mark = message.indexOf(32);
        serverVersion= message.substring(0,mark);
        while(mark < message.length() && message.charAt(mark + 1) == 32) {
            mark++;
        }
        responseCode = Integer.parseInt(message.substring(mark + 1,mark += 4));
        responseMessage = message.substring(mark,message.length()).trim();
        // 应答状态码和处理添加
        switch(responseCode){
            case 400:
                throw new IOException("错误请求");
            case 404:
                throw new FileNotFoundException(getURLFormat(target));
            case 503:
                throw new IOException("服务器不可用");
        }
        if(word == -1){
            throw new ProtocolException("信息接收异常终止");
        }
        int symbol = -1;
        count = 0;
        // 解析元信息
        while(word != '\r' && word != '\n' && word > -1){
            if(word == '\t') {
                word = 32;
            }
            if(count == data.length) {
                data = addCapacity(data);
            }
            data[count++] = (byte) word;
            parseLine:{
                while( (symbol = receiver.read()) > -1){
                    switch(symbol){
                        case '\t':
                            symbol = 32;
                            break;
                        case '\r':
                        case '\n':
                            word = receiver.read();
                            if(symbol == '\r' && word == '\n'){
                                word = receiver.read();
                                if(word == '\r') {
                                    word = receiver.read();
                                }
                            }
                            if(word == '\r' || word == '\n' || word > 32){
                                break parseLine;
                            }
                            symbol = 32;
                            break;
                    }
                    if(count == data.length) {
                        data = addCapacity(data);
                    }
                    data[count++] = (byte) symbol;
                }
                word = -1;
            }
            message = new String(data,0,count);
            mark = message.indexOf(':');
            String key = null;
            if(mark > 0) {
                key = message.substring(0,mark);
            }
            mark++;
            while(mark < message.length() && message.charAt(mark) <= 32) {
                mark++;
            }
            String value = message.substring(mark,message.length());
            header.put(key,value);
            count = 0;
        }
        // 获得正文数据
        while( (word = receiver.read()) != -1){
            if(count == data.length) {
                data = addCapacity(data);
            }
            data[count++] = (byte) word;
        }
        if(count > 0) {
            byteStream = new ByteArrayInputStream(data,0,count);
        }
        data = null;
        closeServer();
    }

    public String getResponseMessage(){
        return responseMessage;
    }

    public int getResponseCode(){
        return responseCode;
    }

    public String getServerVersion(){
        return serverVersion;
    }

    public InputStream getInputStream(){
        return byteStream;
    }

    public synchronized String getHeaderKey(int i){
        if(i >= header.size()){
            return null;
        }
        Enumeration enumss = header.propertyNames();
        String key = null;
        for(int j = 0; j <= i; j++){
            key = (String) enumss.nextElement();
        }
        return key;
    }

    public synchronized String getHeaderValue(int i){
        if(i >= header.size()){
            return null;
        }
        return header.getProperty(getHeaderKey(i));
    }

    public synchronized String getHeaderValue(String key){
        return header.getProperty(key);
    }

    protected String getBaseHeads(){
        String inf = "User-Agent: ZealHttp/1.0\r\nAccept: www/source; text/html; image/gif; */*\r\n";
        return inf;
    }

    private byte[] addCapacity(byte rece[]){
        byte temp[] = new byte[rece.length + 1024];
        System.arraycopy(rece,0,temp,0,rece.length);
        return temp;
    }
}

 
3月12日

JAVA中文编码问题

深入剖析JAVA编程中的中文问题

JAVA中文编码问题
先介绍一个概念:本地编码,所谓本地编码是操作系统采用的中文编码格式,一般是“GBK”或“GB2312”,可以用System.getProperty("file.encoding")。

本文从以下几个方面来对JAVA中的中文编码进行说明。
1.中文存储方式
2.编码变换问题
3.解决方法

第一:中文存储方式
本部分分控制台应用,WEB应用来分析:
对控制台应用:
JAVA文件--->CLASS文件---->虚拟机- - - >控制台输出
本地编码     UTF-8         UTF-8       本地编码
编辑源文件并保存,中文以本地编码方式保存, 利用javac编译后中文以UTF-8方式存在与类文件中,程序运行时,中文也是以UTF-8的格式存在,进行相关处理后,在控制台输出时,再从UTF-8转换为本地编码显示在控制台上.

对WEB应用:
JSP文件--->临时Servlet文件--->Servlet类文件--->虚拟机
本地编码 本地编码(缺省) UTF-8 UTF-8

WEB应用中客户端与服务器数据交互:
客户端---->传递---->服务器---->传递---->GBK
GBK ISO-8859-1 GBK ISO-8859-1 GBK
用户在表单中输入汉字时,编码格式肯定是本地编码,在发送之前IE把中文转换成ISO-8859-1,再发送到服务器,服务器接收到ISO-8859-1格式码流后,再变换成本地编码,服务器进行处理后,如果返回到客户端的是中文,也需要先变换成ISO-8859-1,然后再传递到客户端,客户端再用本地编码进行解释并显示。

数据库应用:
JAVA文件--->CLASS文件---->虚拟机- - - >传递
本地编码 UTF-8 UTF-8 本地编码
缺省在程序与数据库之间传递数据是以ISO-8859-1方式,JDBC首先把UNICODE格式的串转化为ISO-8859-1,然后传递到数据库,数据库进行处理后,把GBK编码的中文首先编码成ISO-8859-1再返回到客户端。

第二:编码变换问题
中文(不管是GBK还是GB2312),英文(ISO-8859-1),UTF-8三种不同的字符集之间存在映射表,通过映射表可以实现彼此之间的转换。可以实现中文<->英文、中文->UTF-8、英文UTF-8之间的变换,中英文到UTF-8的转换主要是虚拟机实现的。变换的过程就是编码和解码的过程,比如从中文”世界“转换成UTF-8格式,”世界“的中文编码为0xCAC0BDE7,在类文件和虚拟机中的编码为0xE4B898E7958C,在中文与UTF-8的映射表中肯定存在这么一项,如果在程序中有如下代码:
1. String str = "世界";//在虚拟机中的形式为0xE4B898E7958C
2. byte[] buf = str.getBytes("GBK");//编码,从UTF-8为GBK,buf中存放的肯定是0xCAC0BDE7
3. System.out.println(str); //控制台输出
4. System.out.println(new String(buf)); //解码为中文”世界“并显示
5. buf = str.getBytes("ISO-8859-1"); //编码,从UTF-8到ISO-8859-1,此时出现问题
6. System.out.println(new String(buf)); //解码为中文,显示 ??,说明出现了编码错误
7. System.out.println(new String(buf, "ISO-8859-1")); //编码为ISO-8859-1,显示 ??,说明出现编码错误
第5行代码出现问题,因为目前内存中的UNICODE 0xE4B898E7958C是从GBK的0xCAC0BDE7转换过来的,如果编码成ISO-8859-1,在UTF-8<->ISO-8859-1的映射表中根本不存在该表目,所以在该行开始出现编码错误。如果显示的是??肯定是编码错误,如果是乱码,往往是显示问题。此时,无论如何也不能由buf中的数据再变换到正确的编码。

第三:解决方法
解决中文编码问题的大原则就是:编解码必须保持一致。
比如程序中第2行就是从UTF-8编码到中文(GBK),跟前面的从中文(GBK)解码为UTF-8保持一致。也就是先从0xCAC0BDE7到0xE4B898E7958C,然后在第2行,再由0xE4B898E7958C到0xCAC0BDE7,此时控制台可以正确显示中文。即便没有第2行代码,那么在控制台显示前,控制台会先完成虚拟机中的0xE4B898E7958C到0xCAC0BDE7的转换,再进行显示。
在WEB开发中,为避免中文问题,可考虑采用如下方法:
在Servlet的doGet和doPost方法中:
request.setCharacterEncoding("GB2312"); //设置输入编码格式
response.setContentType("text/html;charset=GB2312");//设置输出编码格式
在JSP中:
<%@page contentType="text/html;charset=GBK"%>
<%request.setCharacterEncoding("GBK");%>
在数据库编程时,要首先保证数据库使用的是中文编码、另外再需要时设置数据库连接的编码格式为中文。
只要你全面掌握了中文的源文件、类文件、虚拟机和传输过程中的编码格式,并牢记编解码一致的原则,相信你能解决所有的中文问题。

5月24日

一场介于篮球与橄榄球之间的运动(二)

一般人认为要是和学校行政组的人打球肯定得输,因为对方是校领导啊,以后很多方面还得他们照顾。但是我发现我们组里的人丝毫没有放水的嫌疑,个个打得都非常的狠,都把一个副校长打得噢噢的了。我还发现这里打球的一个特点:没有犯规。特别是我们组里的场上核心球员,那简直就是摔跤队的,也许这就是他能做核心的一个因素吧。中场的时候他还悄悄地把他打球的秘籍传授给我了:要坚定不移地把投篮的人拉下来。我当然不会这么干,但是别人总是对我这么干,于是越来越觉得那个篮球简直就是一个祸害,只要这个球一传到你的手里就会有一群恶狼似的人围过来干你,直到把你的手打红了,把你的球打掉了为止。那场面真可以用惨烈来形容,因为那群人跑过来的时候都是带着沙扬着土过来的,然后把一个人围在中间一阵暴打。上篮的时候更加的惨,就好像是一只可怜的苍蝇刚要起飞就有三四个硕大的苍蝇拍狠狠地打了下来。于是我决定我再也不做那只苍蝇了,拿到球后就把它交给我们的核心去处理,直到最后比赛结束了,我才确信自己能够活下来了。
4月27日

一项介于篮球与橄榄球之间的运动(一)

今天跟当地的老师打了一场篮球赛,我代表初二年级组跟行政队比赛。
平时大家都是老师,可是到了场上那就不一样了。这一次我总算是开了眼界了,原来篮球还可以这么玩。
这个学校的篮球场是一块沙地,除了在两个篮筐下面的地方被人踩得结结实实不会滑倒之外,其他任何一寸土地都有可能滑倒。然后再看看上场老师们的打扮:我们这一波除了一个体育老师的穿着像是在打篮球外,其他老师穿得更像是去做一个讲座,或是参加什么重要的颁奖典礼:大部分兄弟都穿了衬衫西裤,夸张一点的还有穿了西装套装的;有个别分子穿了发着耀眼光芒的皮鞋,还有打了领带的,更让人吃惊的是还有个哥们带了一副墨镜,我真是越想越不明白了,这个星球上的人们难道把体育运动看成是这么文雅的一件事?
本来以为那帮中年人会非常斯文的处理这次比赛,但当比赛开始后我才发现自己错了,他们不是来讲座的,也不是来打篮球的,而是来打橄榄球的:原本以为儒雅之士却露出了为人所不知的另一面,只听开始比赛的哨声刚响,操场上便尘土飞扬,电闪雷鸣,劈哩呱啦,稀里哗啦,就好像是两个村村民为了村头的一个厕所而展开了一场斗殴群挑
4月14日

冰火两重天

今天雪终于化了。这雪是两天前下的,是我一辈子活到现在所见过的最大的雪,没想到是在四月份下的。三天前当地的温度还稳定在20多度,然后突然之间就降到了零下,真是很突然,太突然了,受不了哇。更没有想到的是第二天早晨竟然飘雪了。不对,不是飘雪,简直就是暴风雪,不是雪花,而是雪粒子,就是打到脸上会疼得那种。到了当天晚上雪才停,当时积雪已经超过10公分了,最厚的地方超过了30公分,已经到了步履艰难的地步了。看着窗外雪白的世界,我暗暗庆幸:幸好没有把羽绒服给洗了,不然有得拿出来穿,还得多花10块钱去洗,太明智了,呵呵
4月13日

狂想曲

      最近回了一趟北京,从那个破旧的北京北站下车,直接映在我面前的就是一个繁华都市的景象:座座发着耀眼光芒的高楼,从不知道疲惫的车流,还有那来去匆匆不知道去往何方的人们。这种景象与我所支教的内蒙农村实在是相去甚远,在那个鸟不拉屎的地方最主要的交通工具是驴,放眼望去都是平房,还有一天到晚都无所事事好像每天都在等死的人们。但奇怪的是这次回北京,当看到让人眼花的霓虹灯时并没有那种回归都市的兴奋,我只是很平静地看着眼前的一切。
      一列火车也许可以把我从一个地方带到了另外一个地方,它也许也可以把我从十九世纪八十年代带到二十一世纪,但是这一次,它这一路走来带给我的却是更多的思考。
      我抬头看着这些高楼,它是我们现代文明的标志,是人类物质文明发展的见证。在经济高度发达的今天,它们是权力,财富的象征;再看看北京街头涌动的人们,是的,他们不知道疲惫,他们在高度的社会压力下在努力地为这个社会创造价值,同时也为自己美好的生活奋斗。也许在城市人看来,那些生活在农村的人是多么的落后,不仅是在物质生活上,在精神世界里他们同样很落后。物质生活的落后大家能够看在眼里,差距是非常的大,而在精神世界呢?当我刚到内蒙这个名为察右前旗的地方时,我对当地人的生活习惯有着强烈的鄙视。因为在距离他们三百公里的地方(北京),有许许多多的人正在早出晚归的工作,而他们却宁愿拉上几个人一起聊天织毛衣也不愿去多挣一分钱。在我看来他们都是一群没有生活目标的人们,他们心中没有追求,没有什么人生价值的思考,最令他们愉悦的事情莫过于吃得饱饱的,喝得足足的,然后睡上一觉,在精神世界的空虚昭然若揭。于是我自然而然的产生了这样的观点:正是他们这样的人存在影响到了我们社会的进步。然而事实是这样吗?
      何为社会进步?什么样子的社会才是我们所希望看到的社会?现在的中国经济飞速发展,人民生活水平日益提高,但是这样快速发展的经济带给人民的到底是什么?
可以这么说察右前旗的今天也许正是几十年前的北京,从这两者之间人们的观念的差别我们可以看出人民所谓的进步。一谈起这种精神上的差别,我们也许会万分自豪,因为几十年前我们没有像今天这么独立思考过,也没有像今天这样可以大胆得为自己所谓的人生目标追求过,总觉得自己是大大地进步了。那我现在就说几个例子让大家感受一下这样的进步:
察右前旗的郊区住着农民,他们家里很多都养着猪,但是他们的猪都是放养的,就在村子里走来走去,每天它们也都会按时回家。我们不禁要问:猪在村里面自由走动难道就不怕有人把它给偷偷宰了卖了?
当地的商店里卖的东西很少有人会讨价还价,当我们第一次杀价时都快把老板弄哭了却只砍下几毛钱,老板说他们每件商品就赚几毛钱,实际上也是这样的,像一瓶康师傅的矿泉水他们商店里只卖一块钱,跟我们在超市里卖的价钱差不多。我们不禁要问:他们为什么不把价格定得高一点,这样就算有人砍价他们同样可以挣到更多的钱?
我们在这个旗上打台球,当地的规矩是桌面上的球都可以打,不管是不是自己的球。我们不禁要问:万一我的球摆在洞口,对方直接把我的球打出来怎么办?
当地的房屋都是平房,一家墙挨着一家墙,但是他们直接的墙都特别的矮,一个成年人可以毫不费劲的翻过墙去。我们又不禁要问:这么矮的墙难道就不怕邻居翻墙行窃?
      这样的问题我不会去问当地人,因为问了也白问,他们压根就不会想到我的那些顾虑。他们就是这样简简单单地活着,而我们是不是想得太多了?
      是我们想得太多还是这个社会让我们想得太多?几十年前我们也许也不会这么想,现在社会进步了,反而有了那么多的想法。于是发现这个社会进步的只是物质社会,而实际在我们脑海里留下的是比以前社会强上无数倍的物资欲,还有被这种物资欲所奴役的人性。也许我们的老祖先猿人都不会产生象我们现代人所产生的种种龌龊想法,我们现在为了自己的利益是不是做了太多对不起他人的事?我们平时对待生活是不是想太多了?
      再回来看看北京街头涌动的人们,虽然他们自认为自己有理想,有道德,有文化,但是渐渐发现他们并不比这个穷山恶水里的人高尚;虽然他们自认为拥有更高的物质生活条件,但是渐渐发现他们对金钱的态度并不比这里的人高明。
于是当我回到北京时,我没有丝毫的兴奋,因为这里并不比那里进步多少。
于是我更愿意做一个在城市里生活着的乡下人。
3月10日

无聊的夜

我终于不能忍受了,自从我拥有自己的个人空间之后,有无数的人对我进行了攻击,焦点都只有一个,大概就是像我这么懒的人不配拥有一个个人空间。我个人也觉得挺不好意思的,所以决定今后多多写写文章,抒发抒发自己的情感,好让那些关心我的同志们更好的了解我目前的处境
11月25日

我的第一次

终于有了第一次,第一次创建了这个共享空间。希望自己以后不要太懒,能常关心一下这个属于我的天地