posts - 78, comments - 34, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2009年12月1日

       我们的课程即将结束,有一种想立即进入公司工作的冲动,也有一种对这种整日在学校学习生活的眷恋。

      

       培训学校都是骗子,这是在网上见得多的传言。在我想找一家培训机构提升自己的技术时,现实和这些话语让我有些的警觉。为了找一家好的培训机构,我使用了两个月的业余时间不停的在网上转悠,不停的对比各培训机构的课程,对比视频,对比网上的评论...。因为我已经有近三年的桌面相关开发经验,我需要的课程内容是提高技术。最终找到了感觉上适合我的传智播客!(价钱也比较合理)

 

       我是2009115日班的,来到北京我不大喜欢学校推介的住宿环境,幸好我提前两天来到这里。第二天便与几个同学在外面找了个租处——唐家岭, 这里的环境还算不错,来到之后才知道唐家岭已经是全国知名的地境(蚂族)。这里吃饭的地方比较多,价格还算合理,多尝试了几家饭店,选择了我们比较喜欢的长吃(6-10元)。这里也有早餐,我一般都在饭店里吃(3元左右),特殊情况我才会在马路边上摆的摊子买点早餐。

 

       上了几天的课程,我已深觉到我的选择是正确的。来之前,家人和朋友还担心学校的可信度,现在他们是放心了。授课内容和方式正如传智播客所倡导的——深度,这是他们的文化,这是正确的道路。

 

       传智播客提倡学生们写学习日志,按要求完成后还有奖金,这是一个非常好的激励学习方式,当然也这是一个非常好的推广学校的方式。这一点也非常吸引我,所以在我来之前就做了写学习日志的决定。因为我知道我不想终生做为一个技术人员,即使做为一个技术人员做到一定的时候写些东西是必须的。可能会写技术文章、项目文档...。其次,我想将学习的每一项技术详细认真的总结,深入他们的原理。这些促使做了写日志的决定。

 

       但来到学校学习了几天才发现,要详细认真的总结所学习的内容那是不可能的。课后的每天晚上我都坚持写学习日志,忙的时候写到凌晨2:00(偶尔)。如果我能详细认真的总结出每天的学习内容,那我已经可以出三四本书籍了。

 

       至于写学习日志这一点,要适力而为。如果想写好学习日志,就要投入时间和精力,这样就减少了动手练习的时间,对于新人来说这是致命的。我一般都是使用休息的时间来动手。所以,写学习日志自己要打量好了,要写到什么程度、要做多少练习。

 

       在来传智之前,也有看到网上骂传智的贴子。这帖子无论是来自真实的学员、还是来自某些竞争对手。强大而美好的东西自然能证实自己。一个再好的人,怎么会得到所有的人认可!在学校里学习的都是好学生吗?都是努力学习的学生吗?肯定不是,似乎在哪里都能看到这一部分人,当然我以前也不那么喜欢学习。既然远远来到这里学习,也想找一份好工作,那就努力学习吧!

 

       在近期课程将要结束时,有到学校来招聘的公司。这些信息是即时在学校的网站上发布。

有的同学已经与公司签订了合同。但来直接来学校招聘的公司一般给的工资都不会太高,也有给的还算理想的,主要看个人能力。我想回大连工作,没有参加他们的面试。课程结束后我就回大连,虽然老师们不建议我回去...

 

       我要感谢传智播客那些认真、负责、可爱的老师,张孝祥、方力勋、冯威、佟刚、汤阳光、徐培成、毛伟、黎活明,他们让我大丰收。感谢他们的殷勤付出,祝他们身体健康,工作愉快!(话外,上老张和老黎的课要注意下课时及时打水和去卫生间,这两人太尿性了。)

 

       现在WEB开发、桌面开发对我来说已经没多大神秘了,但需要我学习的内容仍然很多很多!    

 

       我时而为自己的命运庆幸,我的道路让我深感到了他的正确!

 

posted @ 2010-03-16 21:27 長城 阅读(2992) | 评论 (6)编辑 收藏

    剩下5天的内容是ERP进销存项目和Linux,这几天我将为今后的工作做准备,所以可能不再学习总结了!

posted @ 2010-03-11 21:11 長城 阅读(1522) | 评论 (0)编辑 收藏

       今日继续我们的Axis学习,我只进行一下简单的总结。有机会再补上吧!

 

       昨天我们学习了,使用WebService进行运程调用,传递基本类型数据和类实体数据。在传递基本数据类型时,我们不需要进行任何操作。但在传递类实体类型数据时,我们需要在服务器端和客户端进行序列化和反序列化注册。那还有哪些数据传递是我们需要注意的?

 

       基本数据类型数组和集合、类类型数组和集合、远程异常。在传递基本类型数组或集合时,我们不需要添加任何声明。但在传递类类型数组或集合时,需要添加与传递类实例进行相同的注册。远程异常应该如何传递?

 

       远程异常,需要通过fault元素注册一个 远程异常。

 

       上面我们对基本数据类型和类类型的简单传输有了基本的认识,但是复合类型应该如何传递呢?类套类,这样下去,难道我们需要手动添加注册信息吗?当然不需要,Axis为我们提供了相应的工具,通过WSDL生成客户端和服务器端Java类,通过Java类(接口)生成WSDL文档,在此我就不详细总结了。

 

       除了Axis,老徐又给我们介绍了xfire,它也是WebService的一种实现工具。在此也不做总结了。

 

       有位网友跟我说还有一种WebService——xcf,是目前最流行的,我并未对此进行埋阅。但我想说的是,以后可能还会有其他流行的WebService实现,但无论出什么样的新东西,它的核心思想都是一样的。这也是我来传智学习的一大原因,如果只知道一种工具如何使用,而不知道它的道理,确实不高明。如果掌握了它的道理,那就是以不变应万变了!

 

posted @ 2010-03-10 21:42 長城 阅读(1522) | 评论 (0)编辑 收藏

     摘要:        WebService课程由徐培成老师主讲,依然发扬传智播客的特点——深入理论和实践。今天老徐讲的原理的专业术语比较多,但我只做WebService的应用总结。如果你的Java和JavaWeb基础好些,我想你看到WebService的应用,自然就能想到它的实现原理。      &nbs...  阅读全文

posted @ 2010-03-08 22:40 長城 阅读(3229) | 评论 (1)编辑 收藏

     摘要: 一、Android中的通知          一般手机上边都有一个状态条,显示电池电量、信号强度、未接来电、短信...。Android的屏幕上方也具有状态条。这里所说的通知,就是在这个状态条上显示通知。          发送通知的步骤如下: &n...  阅读全文

posted @ 2010-03-07 12:41 長城 阅读(2262) | 评论 (0)编辑 收藏

     摘要:          今日课程内容较多,我们的课上到晚7:20。   一、创建新的Activity        在进行桌面开发时,我们可以通过一个窗口上的控件事件打开另一个新的窗口。在WEB应用开发时,我们也可以通过一个连接打开一个新的页面。通过...  阅读全文

posted @ 2010-03-07 10:42 長城 阅读(6120) | 评论 (0)编辑 收藏

     摘要:        我们编写的是Andorid的HTTP多线程断点下载应用程序。因为之间我们学习的学习积累,直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。那么,多线程断点下载的难点在哪里?1.多线程下载,2.支持断点。          多线程下载: &...  阅读全文

posted @ 2010-03-04 14:35 長城 阅读(5403) | 评论 (1)编辑 收藏

     摘要:        昨天我们只对Android接收网络数据进行了简单介绍,今天我们完成了Android数据存储网络部分的所有内容。在此我将对这非常重要的内容进行总结。          本篇日志是对Android与WEB应用服务之间进行数据交互的总结,下篇日志是一个经典...  阅读全文

posted @ 2010-03-04 11:34 長城 阅读(6182) | 评论 (0)编辑 收藏

既然是3G开发,网络重要性自然不必多说!Android的网络存储使用HTTP协议,我们编写的Android网络应用就相当于一个浏览器。由于Android的应用是使用Java来开发的,所以网络应用使用的也是J2SE的包。

 

       Android如何与服务器交互数据?我们可以建立一个WEB应用,这对我们来说是一件十分容易的事。在WEB应用的相关请求处理中接收Andorid提交的数据、返回XML数据或JSON数据。Android发送相应的请求并接收服务相应的数据。这就是AndroidWEB应用的数据交互。

 

       Android发送请求和获取数据如下:

String path = "http://www.android.com/images/opensourceproject.gif";

URL url = new URL(path);

HttpURLConnection conn = (HttpURLConnection)url.openConnection();

conn.setConnectTimeout(6 * 1000);

InputStream inStream = conn.getInputStream();

 

       既然获得了InputStream,那么对数据进行操作就比较容易了。

 

       通过上面的代码,可见Android的网络应用是如此容易!

 

       这只是个开始,明天继续学习网络部分!

 

posted @ 2010-03-02 22:53 長城 阅读(1476) | 评论 (0)编辑 收藏

     摘要:        早上我们简要的对SQLite进行回顾,然后将SQLite的事务管理和SQLiteDataBase提供的Insert、Update、Delete、Query方法进行了简单的讲解。          今日的重点内容是ContentProvider(内容提...  阅读全文

posted @ 2010-03-02 22:12 長城 阅读(4459) | 评论 (4)编辑 收藏

     摘要: 前两篇日志我已经总结了本地数据存储的前两种:文件和配置项。还剩下最后一种数据库存储——SQLite。   一、SQLite简介   在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型虽然只有五种,但实际上sqli...  阅读全文

posted @ 2010-03-01 22:58 長城 阅读(5802) | 评论 (5)编辑 收藏

     摘要:        在此之前的学习内容是数据存储之一文件存储。在本地存储中常用的有,文件、配置文件、数据库。前面的学习主要是针对本地文件的。我认为可以把SharedPreferences看做是配置文件,虽然它也是采用XML格式存储的。          比如我们使用的桌...  阅读全文

posted @ 2010-03-01 15:01 長城 阅读(2434) | 评论 (0)编辑 收藏

     摘要:        今日继续学习Android中使用Pull的XML解析技术实现对XML文件的解析和创建。由于明天休息,时间比较充裕,所以我也将昨天未总结的SAX解析技术在此做个总结。   一、SAX解析技术        Sax使用的是事件驱动的流式解析技术。事件驱...  阅读全文

posted @ 2010-03-01 12:01 長城 阅读(2940) | 评论 (0)编辑 收藏

     摘要:        今日重点内容是Adnroid的数据存储和访问。Android的数据存储有五种:文件 SharedPreferences、SQLite数据库、内容提供者(Content provider)、网络。今天老黎讲解Android的单元测试、文件存储和访问以及解析XML文件。   一、Android的单元测试 &nb...  阅读全文

posted @ 2010-02-27 21:31 長城 阅读(4775) | 评论 (4)编辑 收藏

 一、创建 Android工程

Project name:SendMessage

BuildTarget:Android2.1

Application name:发送短信

Package name:com.changcheng.Activity

Create Activity:SendMessage

Min SDK Version:7


二、编辑工程

1.编辑strings.xml文件内容为:

<?xml version="1.0" encoding="utf-8"?>

<resources>

<string name="hello">请输入手机号码:</string>

<string name="app_name">发送短信</string>

<string name="content">请输入信息内容:</string>

<string name="send">发送</string>

</resources>


2.编辑main.xml文件内容为:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<!-- 请输入手机号码标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/hello" />

<!-- 手机号码编辑框 -->

<EditText android:layout_width="fill_parent"

android:layout_height="wrap_content" android:id="@+id/mobile" />

<!-- 请输入信息内容标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/content" />

<!-- 信息内容编辑框 -->

<EditText android:layout_width="fill_parent"

android:layout_height="wrap_content" android:minLines="3"

android:id="@+id/message" />

<!-- 发送按钮 -->

<Button android:layout_width="wrap_content"

android:layout_height="wrap_content" android:text="@string/send"

android:id="@+id/send"/>

</LinearLayout>

注意,我们在电话号码输入框和拨打电话按钮中添加了android:id属性。如电话号码输入框的android:id=”@+id/mobile”@代码R.java+id代码添加id静态内部类,mobile代表向id类中添加一个常量成员。ADT将自动为我们生成常量值。

android:minLines设置信息内容编辑框的最小行数。


3.编辑Call.java内容:

package com.changcheng.activity;


import java.util.List;

import android.app.Activity;

import android.os.Bundle;

import android.telephony.SmsManager;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;


public class SendMessage extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// 根据ID获取按钮

Button button = (Button) this.findViewById(R.id.send);

// 注册按钮被单击事件

button.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// 根据ID获取手机号码编辑框

EditText mobileText = (EditText) findViewById(R.id.mobile);

// 获取手机号码

String mobile = mobileText.getText().toString();

// 根据ID获取信息内容编辑框

EditText messageText = (EditText) findViewById(R.id.message);

// 获取信息内容

String message = messageText.getText().toString();

// 移动运营商允许每次发送的字节数据有限,我们可以使用Android给我们提供 的短信工具。

if (message != null) {

SmsManager sms = SmsManager.getDefault();

// 如果短信没有超过限制长度,则返回一个长度的List

List<String> texts = sms.divideMessage(message);

for (String text : texts) {

sms.sendTextMessage(mobile, null, text, null, null);

}

}

}

});

}

}

sms.sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliveryIntent)

destinationAddress:接收方的手机号码

scAddress:发送方的手机号码

text:信息内容

sentIntent:发送是否成功的回执,以后会详细介绍。

DeliveryIntent:接收是否成功的回执,以后会详细介绍。


4.编辑AndroidManifest.xml内容:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.changcheng.activity" android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".SendMessage" android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

<uses-sdk android:minSdkVersion="7" />

<!-- 注册发送短信的权限 -->

<uses-permission android:name="android.permission.SEND_SMS" />

</manifest>

注册发送短信的权限,如果没有注册这个,将使用不了系统的发送短信功能。以后在我们的应用程序开发中,有使用到系统功能的必须在这个文件中进行注册。我们可以查看Android的帮助手册都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html


三、启动模拟器

我们给谁发短信?我们可以启动两个模拟器。使用一个模拟器给另一个模拟器发信息。首先我们使用工具栏上的手机图标再添加一个Android2.1的模拟器,另记一个名称。


在启动两个模拟器之前,我们需要模拟器能“接收到信号”。如果我们的机器是联网的,启动模拟器后,主界面显示信号强度的旁边会有一个3G的字样,这说明模拟器已经能接收到信号了。如果我们的机器不能联网,那么将自己的IP地址、网关和DNS服务器都设置为相同的值,比如都设置为192.168.0.100。如果我们的机器是在局域网下,但没有联网,那么将自己的网关和DNS设置为路由的IP即可,一般情况下路由的IP192.168.0.1


OK,现在我们启动两个模拟器!


四、发送短信

我们启动模拟器后,可以看到模拟器窗口的标题栏上有555455556的字样。这是模拟器监听的端口即——127.0.0.15554


在工程上右键,Run As Android Application,选择其中的一个模拟器。比如选择了端口为5554的模拟器。OK,程序被加载到模拟器中了,会被自动运行。


我们在电话号码编辑框中输入5556(接收端模拟器的端口号),点击发送按钮!


OK,你看到效果了吗?5556主界面,显示信号强度的旁边显示收到新短信。


五、使用ADT插件发送短信给模拟器

如果机器太慢,无法启动两个模拟器,我们可以只启动一个模拟器。然后在菜单windows->show view->other->Android->Emulator Control打开Emulator Control面板。


Telephony Actions分组框中,Voice是呼叫,SMS是发送短信。Incoming number是模拟器的端口号,我们也可以使用这个功能给我们的模拟器拨打电话或发送短信。


posted @ 2010-02-27 00:20 長城 阅读(3500) | 评论 (0)编辑 收藏

 

一、创建 Android工程

Project name:Call

BuildTarget:Android2.1

Application name:拨打电话

Package name:com.changcheng.Activity

Create Activity:Call

Min SDK Version:7


二、编辑工程

1.编辑strings.xml文件内容为:

<?xml version="1.0" encoding="utf-8"?>

<resources>

<string name="hello">请输入 手机号码:</string>

<string name="app_name">拨打电话</string>

<string name="button_call">呼叫</string>

</resources>



2.编辑main.xml文件内容为:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<!-- 标题标签 -->

<TextView android:layout_width="fill_parent"

android:layout_height="wrap_content" android:text="@string/hello" />

<!-- 电话号码输入框 -->

<EditText android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/mobile"/>

<!-- 拨打电话按钮 -->

<Button android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/button_call"

android:id="@+id/button_call"/>

</LinearLayout>

注意,我们在电话号码输入框和拨打电话按钮中添加了android:id属性。如电话号码输入框的android:id=”@+id/mobile”@代码R.java+id代码添加id静态内部类,mobile代表向id类中添加一个常量成员。ADT将自动为我们生成常量值。


3.编辑Call.java内容:

package com.changcheng.Activity;


import android.app.Activity;

import android.content.Intent;

import android.net.Uri;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;


public class Call extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// 根据ID获取按钮

Button button = (Button) this.findViewById(R.id.button_call);

// 为按钮添加被单击事件

button.setOnClickListener(new OnClickListener(){


@Override

public void onClick(View v) {

// 根据ID获取编辑框

EditText editText = (EditText) findViewById(R.id.mobile);

// 获取电话号码

String mobile = editText.getText().toString();

// 生成呼叫意图

Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ mobile));

// 开始呼叫

startActivity(intent);

}

});

}

}



4.编辑AndroidManifest.xml内容:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.changcheng.Activity"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".Call"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>


</application>

<uses-sdk android:minSdkVersion="7" />

<!-- 注册使用拨打电话功能的权限 -->

<uses-permission android:name="android.permission.CALL_PHONE"/>

</manifest>

注册使用拨打电话功能的权限,如果没有注册这个,将使用不了系统的拨打电话功能。以后在我们的应用程序开发中,有使用到系统功能的必须在这个文件中进行注册。我们可以查看Android的帮助手册都有哪些功能。(.../android-sdk-windows/docs/reference/android/Manifest.permission.html


三、启动模拟器

我们给谁打电话?我们可以启动两个模拟器。使用一个模拟器给另一个模拟器拨打。首先我们使用工具栏上的手机图标再添加一个Android2.1的模拟器,另记一个名称。


在启动两个模拟器之前,我们需要模拟器能“接收到信号”。如果我们的机器是联网的,启动模拟器后,主界面显示信号强度的旁边会有一个3G的字样,这说明模拟器已经能接收到信号了。如果我们的机器不能联网,那么将自己的IP地址、网关和DNS服务器都设置为相同的值,比如都设置为192.168.0.100。如果我们的机器是在局域网下,但没有联网,那么将自己的网关和DNS设置为路由的IP即可,一般情况下路由的IP192.168.0.1


OK,现在我们启动两个模拟器!


四、拨打电话

我们启动模拟器后,可以看到模拟器窗口的标题栏上有555455556的字样。这是模拟器监听的端口即——127.0.0.15554


在工程上右键盘,Run As Android Application,选择其中的一个模拟器。比如选择了端口为5554的模拟器。OK,程序被加载到模拟器中了,会被自动运行。


我们在电话号码编辑框中输入5556(接收端模拟器的端口号),点击呼叫按钮!


OK,你看到效果了吗?5554模拟器显示正在呼叫,5556模拟器有来电显示...


五、使用ADT插件呼叫模拟器

如果机器太慢,无法启动两个模拟器,我们可以只启动一个模拟器。然后在菜单windows->show view->other->Android->Emulator Control打开Emulator Control面板。


Telephony Actions分组框中,Voice是呼叫,SMS是发送短信。Incoming number是模拟器的端口号,我们也可以使用这个功能给我们的模拟器拨打电话或发送短信。

 

posted @ 2010-02-26 23:00 長城 阅读(3709) | 评论 (0)编辑 收藏

     摘要:   万众瞩目,Android终于开课了。本课程有黎活明老师主讲,讲课细致而流畅。想做细他的课程总结,那我没时间和精力了。也是总结个框框,虽然是个框框,但如果看着我的日志跟着我做,也能做起Android开发。 今日的重点内容是,3G简介、Android简介、Android的开发环境搭建、HelloWorld程序、Android程序运行过程、拨打电话小程序、发送短信小程序。我们跳...  阅读全文

posted @ 2010-02-26 21:21 長城 阅读(5335) | 评论 (2)编辑 收藏

 我今天用Struts2Spring整合,但部署到Tomcat(tomcat-6.0.20)时,WabAppClassLoader却给我抛出了一个异常:ClassNotFindException:xxx.ActionServletActionServletStruts1中使用的Action控制器。但我使用的是Struts2啊!

我反复查看自己的配置文件和使用到的Jar包,没有任何问题。然后到网上搜索答案,出现这个问题的人还不少。有的是使用Strut1出现这个问题,那么他可能是没有导入Struts1的核心包导致的。至于使用Struts2也出现这个问题多少就有些奇怪了。

一些网友给出答案,是将Tomcat删除,然后安装一个新的Tomcat这样就可以解决问题。确实如此,我使用这个方法解决了问题。但为什么会出现这个问题呢?我最先想到的是Tomcat可能有缓存功能,于是我查看Tomcat的目录。发现它有一个temp目录和一个work目录,temp目录是做什么用的我不知道,work目录是为我们生成JSPclass文件。

问题就可能出现在这两个目录,所以以后遇见莫名其妙的问题可以删除这两个目录中的内容,然后再试一试。

posted @ 2010-02-25 23:58 長城 阅读(439) | 评论 (0)编辑 收藏

       Struts2第四天,正如预期Struts2的内容还没有讲完,还需要再加一天课。按照正常的授课方式,Struts2在四天内是可以讲完的,但这可能是老张最后一次讲Struts2,所以他要讲得细致些。

 

       今天的重点内容是Struts2的表单错误信息排版、Struts2中的FreeMark、和Struts2中的UI标签。老张计的比较细致,我做总结就不做的那么细致了。

 

一、Struts2的表单错误信息排版

       Struts2的表单错误信息排版是一个比较常见的问题,但网给所见到的解决方案似乎并不正统。老张给出了他的解决方法。

 

       通过之前的学习,我们知道Struts2中的大部分数据交互操作是由ValueStack来完成的。错误信息也是如此。我们在后台使用配置文件校验或硬编码校验,Struts2将错误信息存放在类型为MapfieldErrors对象中。

 

       我们可以在页面表单字段的后边添加此错误信息,比如在user.name表单字段后边添加<s:property value="fieldErrors['user.name'][0]"/>,这样错误信息可以显示在对应的字段后边。这是针对我们使用非struts2ui标签时(使用提htmlui标签)。但这里有一个问题,如果我的表单字段特别的多,难道我要手动为每个字段添加一个这样的错误信息,这多少有些麻烦,而且以后字段有什么变化还需要行动更改...

 

       Struts2在各方面都做的非常细致和人性化,Struts2UI标签等主要是使用FreeMark来实现的。Struts2使用FreeMar来实现模板和主题,那么我们回显表单数据和错误信息也可以使用FreeMark来实现。此时我们的表单需要使用struts-tags提供的标签来定义,然后我们修改它的ftl模板文件。

 

       下面我们看看一下应该如何修改ftl模板文件,我们以UI标签<s:textarea>为例。Struts2的模板文件存在哪?在Struts2的核心包中的template.xhtml中,textarea.ftl文件内容:

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />

<#include "/${parameters.templateDir}/simple/textarea.ftl" />

<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

      

       我们只需修改 controlheader.ftlcontrolfooter.ftl即可,难道我们需要修改Struts2核心包中的内容?当然不用,这一点Struts2已经为我们考虑到了。我们将这两个文件解压缩并放到WebRoot目录下的”template/xhtml”目录,必须是xhtml目录。看default.properties文件中的这断配置:

### Standard UI theme

### Change this to reflect which path should be used for JSP control tag templates by default

struts.ui.theme=xhtml

struts.ui.templateDir=template

#sets the default template type. Either ftl, vm, or jsp

struts.ui.templateSuffix=ftl

Struts2会先到我们的WebRoot目录搜索相关ftl文件,如果没有才到自己的包中找。

 

       我们的目标,要使用Struts2UI标签并将错误信息显示在标签的旁边。所以我们修改这两个文件的内容为:

controlheader.ftl

<#--

       Only show message if errors are available.

       This will be done if ActionSupport is used.

-->

<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>

<#if parameters.labelposition?default("") == 'top'>

    <td align="left" valign="top" colspan="2"><#rt/>

<#else>

    <td class="tdLabel"><#rt/>

</#if>

<#if parameters.label??>

    <label <#t/>

<#if parameters.id??>

        for="${parameters.id?html}" <#t/>

</#if>

<#if hasFieldErrors>

        class="errorLabel"<#t/>

<#else>

        class="label"<#t/>

</#if>

    ><#t/>

<#if parameters.required?default(false) && parameters.requiredposition?default("right") != 'right'>

        <span class="required">${stack.findValue("getText('requiredmark')")}</span><#t/>

</#if>

${parameters.label?html}<#t/>

<#if parameters.required?default(false) && parameters.requiredposition?default("right") == 'right'>

 <span class="required"><@s.text name="requiredmark"></@s.text></span><#t/>

</#if>

${parameters.labelseparator?default(":")?html}<#t/>

<#include "/${parameters.templateDir}/xhtml/tooltip.ftl" />

</label><#t/>

</#if>

    </td><#lt/>

<#-- add the extra row -->

<#if parameters.labelposition?default("") == 'top'>

</tr>

<tr>

</#if>

 

controlfooter.ftl

${parameters.after?if_exists}<#t/>

    </td><#lt/>

<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>

<#if hasFieldErrors>

    <td ><#rt/>

<#list fieldErrors[parameters.name] as error>

        <span class="errorMessage">${error?html}</span><#t/>

</#list>       

    </td><#lt/>

</#if>

<#--

       if the label position is top,

       then give the label it's own row in the table

-->

<tr>   

</tr>

 

至于为什么这么修改,一看便知,我就不多做解释了。

 

二、Struts2如何使用Freemarker

       Struts2是如何使用Freemarker的?在struts2的核心包中有一个default.properties配置文件,Struts2的默认配置都在这个文件中。有一些配置是开启的有一些配置是关闭的。我们要想打开被关闭的配置可以在struts.xml中,添加<constant name="配置项名" value="配置项值"></constant>元素。

 

       default.properties中有一个struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager配置,Struts2是通过FreemarkerManager类来实现对Freemarker的操作的。

 

       通过查看源代码,我们知道通过调用FreemarkerManager类的buildTemplateModel方法生成一个model对象,然后将这个对象放在ValueStack中提供给Freemarker的引擎使用。model中都包含发哪些数据?Freemark的模板信息自然不用说,它还包含RequestApplicationResponse等这些在WEB应用中常用到的对象。具体我就不详细列出了,大家可以查看源代码。我们在上边两个模板文件中使用到的 parameters.name也是存储在model中的。

 

       在此特别提出一个被叫做UIBean的类型,UIBean就是对应Struts2UI标签的对象实体。比如标签有namethemeid等数据,这些都会被封装到UIBean中。Freemarker也正是使用这个东东给我们生成了相应该的页面文件。    

 

三、Struts2中的UI标签

       关于各UI标签的详细使用方式,在此就不做总结了。

 

       在实际开发中有一个重要的问题需要我们解决,比如有一个选择个人喜好的表单。我们需要通过一个Action的方法(likesUI)将喜好列表提供给页面,可以让用户选择。但在应用提交选择进行表单校验时,用户提交的数据不合法,我们需要重新返回到用户选择的界面。此时,我们需要调用 likesUI,获取列表将数据提供给用户选择的界面。

 

       我们可以在Action中添加”<result name="input" type="chain">likesUI</result>”,使其发生错误时直接跳转到likesUI,我们也需要在likesUI中添加一个 名称为inputresult标签,但这个标签的值不能为likesUI,否则会递归调用,直到缓存溢出。我们应将它的值指定为likesUI.jsp页面。但即使指定了这个页面,Struts2的内部实现方式也不会调用likesUI方法从,不会将数据传递给likesUI.jsp页面,而它直接跳转到likesUI.jsp页面。

 

       看来我们不能这么做,通过张老师对源代码的详细解析,我们只需要将likesUIAction中的likesUI的方法命名为input(),并只在likeUIAction中添加”<result name="input">/WEB-INF/pages/user/likesUI.jsp</result>“即可。为什么呢?

 

       在表单校验发生错误并使用 chain进行跳转时,会被chain拦截器给拦截了(ActionChainResult)。然后又会被拦截器validation给拦截了,它再进行表单校验进还是以前的数据,还是会出错然后它就直接跳转到我们指定的页面了。注意配置文件中的validation

<interceptor-ref name="validation">

       <param name="excludeMethods">input,back,cancel,browse</param>

</interceptor-ref>

它忽略请求为 input,back,cancel,browse请求路径。所以我们需要将我们的方法名定义为 input()

 

       我只是泛泛而结,如果想了解Struts2的更多细节请下载老张的视频看吧!

 

       最后送给大家一个Struts2开发用例参考模式图:

clip_image002
       1.用户申请注册,打开注册页面。

       2.用户提交注册申请,表单校验错误。

       3.表单校验错误不要跳转到regUser.jsp页面,而是应该跳转到RegUserUI这个Action方法。

       4.用户提交注册申请,表单校验通过。

       5.表单校验通过,调用RegUser这个Action方法进行注册。

       6.注册成功后,不要跳转到list.jsp页面。而是应该调用ListAction这个Action方法。

       7.ListAction获取所有用户信息后,跳转到list.jsp

 

       一定要记得老张还有一天的Struts2的课程,下一次课程的重点内容应该是Struts2的文件上传与下载,Struts2的防止表单重复提交,Struts2SpringAJAX整合,Struts2的插件。

 

       接下来的课程内容让我等的好久啊——Android!虽然听学习过的同学们说十分简单,但我还是迫不及待的想Android的一睹真容。我想很多人都是这样吧!那就关注我接下来6天课程的总结日志吧!

posted @ 2010-02-25 21:32 長城 阅读(573) | 评论 (0)编辑 收藏

       Struts2第三天。如果老张他喜欢头发,他肯定会把头上的头发有多少根,一根一根的数出来。他搞的太细了!

 

       今天的重点内容是国际化、表单与Action数据交互、表单校验,不多说了开始总结。

 

一、Struts2国际化

       在我们学习WEB基础的时候就讲到了国际化,Struts2中的国际化实现方式与我们之前所学习到的国际化相同。但是Struts2中对国际化做了强化支持!

 

       我们通过在struts.xml文件中加入”<constant name="struts.custom.i18n.resources" value="*.properties"></constant>”为指定全局国际化资源文件。Struts2会根据浏览器设置的语言信息运行对应的国际化文件,如果没找到就根据操作系统的语言查找指定的文件,还是没有,那就使用默认的。我们必须在struts.xml中使用定义在struts-default.xml文件中的defaultStack拦截器堆栈。使用defaultStack我们必须在package中添加extends="struts-default"属性。如果在我们的Action中没有使用任何拦截器,defaultStack默认被使用。如果有使用任何其他拦截器,我们必须手动加入defaultStack拦截器堆栈。Struts2将使用defaultStack拦截器堆栈中的i18n拦截器,为我们提供国际化支持。

 

       引入多个全局资源包的方法是在上面的value属性中添加以”,”分隔的多个资源文件。排在最后的资源包的优先级别最高(如果有重复的资源名称)。那如果有时我想在JSP页面中使用第一个资源包中的资源怎么办?Struts2为我们提供了一个标签“<s:i18n name="first.properties"></s:i18n>”,在标签体内使用到的国际化资源,全以first.properties为先。

 

       我们可以为每个Action指定一个资源包,资源包的名称与Action的名称相同。Struts2的国际化模块会先找与Action对应的资源包,如果没有就找它上一级的资源包,就这样逐级向上。如果直到类所在包的是后一层目录也没找到就使用全局资源。这有什么好处?我们可能会有多个Action使用同一个或多个相同的资源,难道我们要在每个Action对应的资源包里定义它吗?当然不需要,我们只需要把它定义在这几个Action的上级且同一目录即可。

 

       我们如何在JSP页面有使用国际化资源?Struts2tags为我们提供了“<s:text name=""></s:text>”标签,它是专门用来访问国际化资源的。除此之外我们也可以使用“<s:property value=”getText(key)”>”,这个getText()是哪来的?当然是ValueStack中的某个对象的方法喽!是类型为com.opensymphony.xwork2.DefaultTextProvider对象的。Struts2中使用OGNL操作ValueStackContextMapOGNL看到getText(key)时,它会在ValueStack中从上向上反射每一个对象,如果哪一个对象最先具有这个方法,则OGNL就调用这个对象的getText(key)方法。

 

       除了在JSP页面中需要使用到国际化资源,我们在Action中也需要使用国际化资源。此时,我们需要将我们的Action类继承自ActionSupport类,它实现了专门用于操作国际化的接口TextProviderActionSupport还实现了其他非常有用的接口,我们在下面会总结。此后,我们只需要调用getText()方法,即可获得相应的资源信息。我们的Action也可以继承自DefaultTextProvider类,但它默认情况下去搜索全局资源包,不会找Action的资源包。而ActionSUpport正如我们在上面所说,以Action的资源包优先级最高...

 

       我们知道我们可以为国际化资源指定参数,比如“regNameError={0} is invalid.”。我们在JSP页面中可以通过<s:param></s:param>标签来指定,如:

<s:text name=”regNameError”>

       <s:param></s:param>

</s:text>

<s:text name=”getText('regNameError','xxx')”></s:text>。在Action中直接使用getText(“regNameError”,”xxx”)

 

       我们之所以能够如此方便的使用国际化支持,JDK中的java.util.Locale为此做了很大的贡献。目前我们使用国际化操作,无不基于java.util.Locale。因为OGNL的强大,我们也可以在JSP页面中使用java.util.Locale还记得吗?在OGNL中调用XXX类的静态方法或成员的方式,比如调用java.util.LocalegetCountry()<s:property value=”@java.util.Locale@getDefault()”/>

 

二、表单与Action数据交互

       相比Struts1,在Strut2中的一大变化是我们不需要ActionForm了。我们在使用Struts1时,为了操作表单数据,我们需要额外定义一个继承自ActionFormFormBean。然后再将FormBean中的数据CopyBean中。

 

       Struts2是如何实现对表单数据的操作呢?Struts2ValueStack一直发辉着它的作用,ValueStack像是能完成Struts2的在所在操作,上面的国际化也是使用的ValueStack存储的。在Struts2中操作表单数据,我们需要在我们Action定义属性。在Action添加的属性可以是基本数据类型也可以是复合类型。

 

       进行表单与Action数据交互时,我们的Action类无需实现任何接口或继承自任何类。但是,我们必须在struts.xml中使用定义在struts-default.xml文件中的defaultStack拦截器堆栈。使用defaultStack我们必须在package中添加extends="struts-default"属性。如果在我们的Action中没有使用任何拦截器,defaultStack默认被使用。如果有使用任何其他拦截器,我们必须手动加入defaultStack拦截器堆栈。

 

       Struts2正是使用在defaultStack中的params拦截器,来为我们的Action设置属性值。如何使用基本类型属性和复合类型属性与JSP页面交互呢?比如在我们的RegUserAction中有一个User属性和一个字符串型的password2属性。那么我们在JSP页面中应该这样使用:

<s:form action=”RegUserAction”>

    <s:textfield name=”user.name”/>

    <s:textfield name=”user.password”/>

    <s:textfield name=”user.email”/>

    <s:textfield name=”password2”/>

    <s:submit value=”注册”></s:submit>

</s:form>

 

       点击注册按钮后,Struts2正是使用params拦截器将数据设置到RegUserAction的属性中。

 

       因为这些表单字段数据是被保存在ValueStack中,所以我们在JSP页面我们可以使用EL表达试,如:${user.name},也可以使用OGNL表达式,如:<s:property value=”user.name”/>来获取数据。

 

       除此之外,我们可以让Action实现ModelDriven接口,并将User做为它的泛型参数。如果被ModelDriven接管的实体类型中有与我们的Action属性相同的,ModelDriven的优先级高。Struts2会设置ModelDriven接管的实体类型的是属性,而忽略Action的同名属性。但这并不会引起错误,因为我们的数据全部放在ValueStack中,使用OGNL可以正确获取。我们不推荐使用ModelDriven

 

三、表单校验

       表单校验在Struts2中实现比较简单,表单数据的校验分为前台校验和后台校验。同样我们需要开启defaultStack拦截器堆栈,首先我们来看看后台校验。

 

       后台校验,我们的Action可以继承ValidationAwareSupport类和实现Validateable接口。因为我们同时需要在类中使用到国际化表单校验,所以我们可以直接继承ActionSupport类。Action类需要实现validate方法。

 

       validate方法中进行Action的属性校验,并且我们可以调用ActionSupport类的addActionError(String)方法,添加错误信息。我们可以在这里使用国际化支持,而在JSP页面中需要使用<s:fieldError>取出所有错误信息,或者指定字段名而取出某个字段的错误信息。

 

       但有一个问题,一个Action类可以有多个方法分别用于处理不同的请求。Struts2每当调用其中一个方法时都会进行表单校验,这没必要啊!所以我们在不需要进行表单校验的方法上添加“@SkipValiation”注解,这样就会被Struts2过滤掉。

 

       我们也可以添加”ActionClassName-validation.xml”配置文件,来为指定名称的Action(ActionClassName)添加表单校验。具体的配置可以参看struts2包中所带的例子程序。我们也可以使用“ActionClassName-actionname-validation.xml”来为Action类中的某个具体方法指定表单校验。

 

       前台校验,前台校验的好处不再说明了。前提我们以配置文件的方式为Action指定的表单校验,那么在JSP页面中,我们可以直接引用配置文件中的数据,实现前台校验。Struts2中的struts-tags为我们提供的表单标签中可以引用配置文件中对应的校验数据。在我们访问到某个JSP页面时,Struts2的标签会为我们自动生成相应的JavaScript代码,但Struts2的表单前台校验的这种功能还不够强大。在此就不多做总结了。

 

       老张讲得比较细致,我也仅仅是泛泛而总结。按照正常的进程,我们明天还有一天的Struts2课程,但由于时间不够,老张决定哪天同学们休息时再为我们补一天,太好了!

posted @ 2010-02-23 23:39 長城 阅读(530) | 评论 (0)编辑 收藏

     摘要: Struts2第二天,大家似乎没有从年假中苏醒过来,上课显得有些疲惫。不过还好,听课效果还不错。今日的主要内容是OGNL,Struts2使用OGNL访问contextMap和valueStack。老张很执着,他在研究Struts2时遇到的一些问题,一定要解决,并且要详细解决。通过他在讲课中,我们可以看出这一点。有开发经验的人都知道,我们时而被陌生技术的一个小细节搞的晕头转向,耗费了大半天的时间我们...  阅读全文

posted @ 2010-02-22 16:59 長城 阅读(739) | 评论 (0)编辑 收藏

     摘要:          春节假期终于结束了,假期内在北京只出去转了两天,感觉很好!剩余时间呆在屋子里写了个练习程序收获颇丰。          依然迫不及待,迫不及待的学完课程赶紧回大连。我想除了我,很多同学和网友也都期待着今天由张考祥老师主讲的Strut...  阅读全文

posted @ 2010-02-20 23:56 長城 阅读(572) | 评论 (0)编辑 收藏

     摘要:          今日教育办公系统结束。新内容有:导出数据到PDF文档、生成图表(饼图、柱图...),整体上操作比较简单。   一、创建PDF文档          我们使用iText创建PDF文档,需要到http://itext...  阅读全文

posted @ 2010-02-09 01:25 長城 阅读(478) | 评论 (0)编辑 收藏

     摘要:          今日我们已经将权限模块与员工管理整合完毕,但下午有学习新的内容。将数据导出为excel表格,或从excel表格导入数据。这一项功能比较常用!在Windows平台下微软有为我们提供Office的COM套件,Apache为我们提供的poi正是为Java打造的Office套件。    &...  阅读全文

posted @ 2010-02-08 00:30 長城 阅读(381) | 评论 (0)编辑 收藏

spring-security最后一天,今天的主要内容是将需要指定权限才可以访问的资源放到数据库中,脱离applicationContext.xml配置文件。然后我们将近两天学习的srping-security整合到教育办公系统中。


我们继续昨天的内容,将资源文件信息保存到数据库中。



1.applicationContext.xml

将昨天applicationContext.xml“配置SpringSecurityhttp安全服务”部分的内容替换为:

<sec:http auto-config="true" session-fixation-protection="none" />

<bean

class="org.springframework.security.intercept.web.FilterSecurityInterceptor"

autowire="byType">

<sec:custom-filter before="AUTHENTICATION_PROCESSING_FILTER"/>

<property name="objectDefinitionSource" ref="objectDefinitionSource"/>

</bean>

这里的objectDefinitionSource是下边的类,cutom-filter是在调用AUTHENTICATION_PROCESSING_FILTER过滤器之前调用FilterSecurityInterceptor


2.添加数据表

resc表与role表是多对多关系。


1).resc

image

2).resc_role

image

3.相关类

要让spring-security可以从数据库中获取相关资源信息,我们必须编写一个实现FactoryBean接口的类。

package cn.itcast.cc.spring.security;


import java.util.LinkedHashMap;

import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.FactoryBean;

import org.springframework.security.ConfigAttributeDefinition;

import org.springframework.security.ConfigAttributeEditor;

import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;

import org.springframework.security.intercept.web.RequestKey;

import org.springframework.security.util.AntUrlPathMatcher;

import org.springframework.security.util.UrlMatcher;

import org.springframework.stereotype.Component;


@Component("objectDefinitionSource")

public class DefaultFilterInvocationDefinitionSourceImpl implements FactoryBean {


@Resource

ResourceDetailsService resourceDetailsService;


private UrlMatcher getUrlMatcher() {

UrlMatcher urlMatcher = new AntUrlPathMatcher();

return urlMatcher;

}


@Override

public Object getObject() throws Exception {

UrlMatcher urlMatcher = this.getUrlMatcher();

// 获取数据Map

Map<String, String> srcMap = resourceDetailsService.buildRequestMap();

LinkedHashMap<RequestKey, Object> requestMap = new LinkedHashMap<RequestKey, Object>();

ConfigAttributeEditor editor = new ConfigAttributeEditor();

// 转换数据Map

for (Map.Entry<String, String> entry : srcMap.entrySet()) {

String url = entry.getKey();

String roles = entry.getValue();

if (roles != null) {

editor.setAsText(roles);

requestMap.put(new RequestKey(url), editor.getValue());

} else {

requestMap.put(new RequestKey(url), ConfigAttributeDefinition.NO_ATTRIBUTES);

}

}

// 生成并返回对象

return new DefaultFilterInvocationDefinitionSource(urlMatcher,

requestMap);

}


@Override

public Class getObjectType() {

return null;

}


@Override

public boolean isSingleton() {

return false;

}


}


其中ResourceDetailsService接口的实现类如下:

package cn.itcast.cc.spring.security;


import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.annotation.Resource;

import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;

import org.springframework.stereotype.Component;


@Component("userDetailsService")

public class ResourceDetailsServiceImpl implements ResourceDetailsService {


@Resource

private SimpleJdbcTemplate jdbcTemplate;

@Override

public Map<String, String> buildRequestMap() {

// 注意:这里需要使用左外连接查询,是因为有些页面没有指定role

// 即,任何权限都不可以访问的页面!

String sql = "SELECT res_string as url,r.name as role " +

"FROME resc LEFT JOIN resc_role rr ON rr.resc_id = resc.id " +

"LEFT JOIN role r ON rr.role_id = r.id";

List<Map<String, Object>> results = this.jdbcTemplate.queryForList(sql);

Map<String, String> srcMap = new HashMap<String, String>();

// 将查询后的数据拼接并放入到Map

for(Map<String,Object> val:results){

String url = (String) val.get("url");

String role = (String) val.get("role");

if(srcMap.containsKey(url)){

role = srcMap.get(url) + "," + role;

}

srcMap.put(url, role);

}

return srcMap;

}

}


Spring-security还为我们提供了其他实用的辅助功能,具体的google一下吧!

posted @ 2010-02-04 23:18 長城 阅读(404) | 评论 (0)编辑 收藏

     摘要:          有没有发现一个问题,我们之前做的所有练习,都没的权限管理这个模块。我们的WEB应用中的同一个帐户可以在多台机器上同时登陆,每一个用户可以操作所有功能模块。这样在以后的应用开发中是结对不可行的!          &nb...  阅读全文

posted @ 2010-02-03 23:52 長城 阅读(2621) | 评论 (0)编辑 收藏

 

        今天重点内容是AJAX技术在教育办公系统中V层的应用,实现的功能有:AJAX分页查询、AJAX删除、AJAX修改。

        还记得学习AJAX时使用JQuery向服务器发送请求,并在回调函数中将返回的数据动态插入到DOM的某处吗?Yes,我们今天主要就是玩这个技术。感觉没什么好总结的,就是叠代码、串代码,没什么新鲜东西。


        但我想说的是看着佟佟搞着代码,操作着页面多少有些恶心。因为我以前是做桌面的组件没这么麻烦,也没这么灵活,但目标都是一样的——显示数据,提供给用户查询或编辑。所以我要思考一个问题,将分页、DAOAJAX操作封装成像桌面软件的组件那样方便易用,其实已经实现了通用分页和DAO。关于页面AJAX并不理想,虽然JQuery有很多插件,但从这两天的内容来看插件的操作并不理想,有时间我要为此多研究研究。

        明天的内容比较有吸引力!哈哈!


 

posted @ 2010-02-02 21:33 長城 阅读(290) | 评论 (0)编辑 收藏

 

         每次学习项目或者新的知识时,都 不能建立宏观的了解。中午或者晚上需要回来整理一下,才能对所学的知识有个宏观的了解(框架的了解)。我们现在做的这个项目,似乎一直学习的是新知识,其实并不是。而是Java的高级用法,它让我感觉到了Java的强悍。


         今日重点通用分页功能,几乎每一个像样些的练习都有分页功能,它如此重要!今天的分页功能是通用的,适用于任何WEB应用。基于昨天的两个工具类,今天新添加了一个HibernateDao 扩展了SimpleHibernateDao。这个DAO除了进行常规的CURD操作,还为我们提供了分页功能和多条件模糊查询功能,用起来更方便。

 

         下面是查询分页信息操作的时序图:


         (如有需要代码的,可以给我留言!)   

 

    项目整体上来说并不难,只要抓住了项目的框架和重点内容。什么才是最难的?自己动手实践才是最难的。来传智播客学习已经三个月了,我一直坚持着整理学习日志,想将每天的学习重点都详细的整理出来,但那根本不现实,因为学习内容太丰富了。我也有动手去实践那些重点的内容,但效果并不另我满意。我想我应该拿出更多的时间去实践,但写日志占用了我大部分时间!

 

         有失必有得,这都是个人的选择。我之所以写日志,是想练习自己对文章框架和知识结构的整理能力。做为一个优秀的程序员,我想这一点是十分重要的。我在这方面得到了一定的提升,别我欣慰。但仍然需要继续努力!说心里话,我的文章结构还差的很,因为没有经过细心整理和校验。

 

         我想我应该灵活的去处理实践与写作的时间,当实践变得重要时就应该拿出大部分时间给实践。当理论性知识重要时,更应该拿出些时间去写日志。嗯,就这么做吧!还有一个月20天课程就结束了!

posted @ 2010-01-31 23:55 長城 阅读(2046) | 评论 (5)编辑 收藏

     摘要:          东西好多啊,我的编写进度是跟不上了。把重点日志好好整理一下!以前编写的练习主要是练习基本功,现今的练习是要是怎么快怎么来。比如分页功能,以前是靠自己手动一点一点的写。而如今一个插件搞定,而且功能十分强大。          ...  阅读全文

posted @ 2010-01-30 23:11 長城 阅读(949) | 评论 (0)编辑 收藏

     摘要: 今天是教育办公系统的第一天,我本以为这个系统是一个全面些,功能强的项目。实际确实如此,功能强大、全面!但我们只需要完成其中的一小部分,核心的部分。其实想想,这么好的一个系统,如果真把它做出来并通过测试,我估计至少需要二个月左右的时间。而我们只有9天的时间,这9天的时间将项目的核心部分学习一下还是相当不错的。 其实在企业开发中,这种规模的项目是不可以由一个人来完成的。所以从这个角度考虑,我...  阅读全文

posted @ 2010-01-30 00:31 長城 阅读(619) | 评论 (0)编辑 收藏

     摘要: 今日的三大主要内容:Spring中的数据库操作事务、Spring整合hibernate、Spring整合Struts1.X,最来再来一个SSH整合。 数据库操作、数据库事务管理、hibernate、Sturts,这些大家都已经十分熟悉了。所以将他们与Spring整合使课程内容比较简单。Spring的特性是什么?不就是IOC的DI和AOP吗!简单在大脑里回顾一下,SSH整合正是使用这些特性。 一...  阅读全文

posted @ 2010-01-28 17:23 長城 阅读(652) | 评论 (0)编辑 收藏

     摘要: 这知识越学越简单了。其实现在学习的Spring和之前学习的Hibernate等框架等,他们的实现都是我们之前学习的Java基础和JavaWeb基础。再加之做了几个总结性的练习,巩固了基础。所以现在学习起来就比较容易了。 今日的课程内容为两部分:Spring中的AOP面向切面编程和Spring对JDBC的支持。   一、Spring-AOP AOP面向切面编程(Aspect-Orie...  阅读全文

posted @ 2010-01-26 22:49 長城 阅读(371) | 评论 (0)编辑 收藏

     摘要: “你用过什么框架?我用过Srping,但不要说成我用过春!”,哈哈。刚开课,佟佟就把大家斗乐了,非常开心。佟佟这称号是同学私底下叫的,比较亲切。他无论在哪个班上课,都可以听到那个班的欢声笑语。 大名鼎鼎的Spring大家都听过,spring是一个开源框架,Spring为简化企业级应用开发而生。使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。Spring是一个DI(依...  阅读全文

posted @ 2010-01-24 23:23 長城 阅读(1012) | 评论 (1)编辑 收藏

今日学习版本管理软件——SVN,我在以前的工作中正是使用SVN做为版本管理的。使团队合作更加轻松、方便、快捷。

 

SVN在当今软件项目开发中占的比重较大,在外国的软件行业中几乎全部使用SVN进行版本管理的。在国内的大中型企业也在使用,可能存在部分小型公司没有使用。

 

在当今开源的世界中SVN的应用屡见不鲜,今日的课程就是学习如何假设SVNCVS服务器,还有SVNCVS的客户端使用。Eclipse的经典更不用说,她真是一个和谐的大家庭!

 

SVNCVS的配置在互联网,或其官网“http://www.subversion.org.cn/ ”已经非常全面细至了。

 

我们平时自己写个项目时,都将代码备份到自己的本地其他逻辑空间中,定期也将代码发到自己的邮箱中备份。但Google为我们提供了免费的代码托管“http://code.google.com/intl/zh-CN/projecthosting/ ”使用起来十分方便!

 

我十分喜欢Google

posted @ 2010-01-23 21:45 長城 阅读(359) | 评论 (0)编辑 收藏

     摘要: EJB3的功能很是强大,但中小企业很少使用它做开发,一般应用SSH足以应付。JAVAEE是做什么的?她是分布式企业级应用的规范,那EJB就是为实现这样的应用而开发的。 什么是分布式应用?听着名字很大。比如咱们的在线支付系统,淘宝、china-pub和amazon等都支持支付宝在线支付。难道它们分别都要将支付宝模块放在自己的服务器上?完全没必要。支付宝模块单独放在一个服务器上,其他服务器使用(调用...  阅读全文

posted @ 2010-01-22 11:40 長城 阅读(343) | 评论 (0)编辑 收藏

     摘要: 今天内容为两个版块JPA与EJB,从学习hibernate、UML到JPA。他们都涉及到一个极为重要的细节——类与类、接口与接口或类与接口之间的四类关联关系。今日上午到下午3点左右内容为JPA中处理这四类关系。我想我应该将他们系统的做一下总结,这项任务就留着后天休息来完成吧! 近三天的课程内容除了带给我知识上的获取和见识的增长,更让我感觉到一种力量!在学习WEB之前,这些互联网的东西让我满头雾水...  阅读全文

posted @ 2010-01-20 23:20 長城 阅读(749) | 评论 (0)编辑 收藏

     摘要: 今后三天的课程内容为:JPA与EJB。我们的班型是JAVAEE精品就业班,我们学习的是JAVAEE吗?JAVAEE是分布式企业级应用,我们之前学习的JSP与Servlet都是JAVAEE的内容,是基础内容。那么JAVAEE的核心是什么?没有学习JAVAEE的核心还算是学习过JAVAEE吗?JAVAEE的核心是EJB! EJB具体是做什么的?目前还不清楚,这部分内容在明天和后天会学习。今日的重点内...  阅读全文

posted @ 2010-01-19 23:46 長城 阅读(576) | 评论 (0)编辑 收藏

UML,是我在整套课程中比较期盼的内容。虽说是对UML的期盼,更是对CMM标准化项目开发的期盼。软件工程的概念是参照建筑工程等流程提出来的,与建筑工程相同,软件工程需要可行性分析、需求分析、概要设计、详细设计...。建筑需要图纸,软件也需要图纸,设计软件图纸的工具就是UML(统一建模语言)。

到传智播客学习,了解和运用软件工程也是我的重要目标之一。因为我受够了没有经过软件工程标准化开发,而直接编码所带来的痛苦。今日的课程内容比较简单,上课的氛围比较轻松。有机会听徐老师谈一谈国内的软件公司现状。CMM是印度人总结出来的被国际公认并普遍使用的软件工程规范,最高等级应该是CMM5。但十分遗憾的是中国的真正意义上的CMM5等级的这种软件企业并不多,为什么?要搞一个CMM5的认证来,与我们社会中想搞一个学位证书的概念差不多。可想这种卑劣的文化!残害着自己的民族。在这个社会里一切都不会超过人情世故。

我对这种标准化的工程流程十分关注,国内在这方面做的比较好的是大连。但大连是中国最大的软件外包产业,几乎全在为日本工作。所以这种CMM5的高层(设计层)都是由日本人来完成的,中国的“打字员”只需要按照日本人设计的详细文档,把代码敲到电脑里并测试通过就可以了。我们知道编码只是软件开发中的一小部分而已,非常惭愧!

不在其位莫思其事!

老徐说给我们提供UML的课程是为了让大家在以后的工作中能看懂UML图。UML的画图工具很简单,难在你用丰富的经验画出优美的软件框架和详细设计来。

一、软件工程

简要学习一下软件工程,软件工程是由软件危机引起的。软件危机就引起了瀑布模型,从瀑布模型又升级出来RUP来。

一幅美丽的用来形容软件工程问题的漫画:

clip_image002[4]

1.瀑布模型

clip_image003[4]

模型的特点是:

1). 各阶段间具有顺序性和依赖性: 后一阶段工作必须在前一阶段工作完成后才能进行。

2). 质量保证机制的依赖性。即每一步都必须循序渐进,及早消除故障隐患,保证本阶段的工作的质量,从而达到保证整体软件质量的目的。

3). 推迟实现原则。前一阶段工作做的越细, 越扎实,后一阶段工作进行的就越顺利,强调”宁慢求好”。因此,各阶段工作总是一拖再拖,致使整个工期推迟实现。显然瀑布模型不能满足呈爆炸状增长的社会应用需求。

2. 统一软件开发过程:RUP(Rational Unified ProcessRUP)

一个通用的软件流程框架, 以架构为中心, 用例驱动的迭代化开发流程。 RUP 是从几千个软件项目的实践经验中总结出来的, 对于实际的项目具有很强的指导意义。RUP 用二维坐标来描述。 横轴通过时间来组织, 是过程展开的生命周期特征, 体现开发过程的动态结构;纵轴以内容来组织, 体现开发过程的静态结构。

clip_image004[4]

有关瀑布模型和RUP的资料网上有很多,在次就不多做总结了。

三、UML

UML(United Modeling Language,统一建模语言):是一种基于面向对象的可视化建模语言。

UML采用了一组形象化的图形(如类图)符号作为建模语言,使用这些符号可以形象地描述系统的各个方面。

UML通过建立图形之间的各种关系(如类与类之间的关系)来描述模型。

UML中有二类图(共10种):

1).静态模型图:描述系统的静态结构

类图、对象图、包图、组件图、部署图

2).动态模型图:描述系统行为的各个方面

用例图、时序图、协作图、状态图、活动图。

其中蓝色为重点图例,其他的图例比较少用。

在画图之前我们有必要复习一下类的四种关系:

u 关联关系(association)

u 依赖关系(dependency)

u 泛化关系(generalization)

u 实现关系(realization)

我们在hibernate中有学习到这四种关系,原本我以为那只是在hibernate中使用。没想到在UML中也有,其实这四种关系应该是软件工程中的规范了。那hiberante也是使用了这种规范进行相关开发的,这样可以促进hibernate路线的正确性,这太好了!

我们使用的是IBM的RationalRoseUML设计工具,使用工具具体图画的操作就不说明了。

1.用例图

用例图(Use Case Diagram): 也称为用户模型图, 是从软件需求分析到最终实现的第一步, 它是从客户的角度来描述系统功能。

用例图包含 3 个基本组件:

1) 参与者(Actor): 与系统打交道的人或其他系统即使用该系统的人或事物。在UML中参与者用人形图标表示。

2) 用例(Use Case): 代表系统的某项完整的功能。在UML中使用一个椭圆来表示。

3) 关系: 定义用例之间的关系:

a) 泛化关系:表示同一业务目的(父用例)的不同技术实现(各个子用例)。 在UML中,用例泛化用一个三角箭头从子用例指向父用例。以下是某购物网站为用户提供不同的支付方式。

b) 包含关系:一个用例可以包含其他用例具有的行为, 并把它包含的用例行为作为自身行为的一部分。 在 UML 中包含关系用虚线箭头加 “<<include>>”, 箭头指向被包含的用例。

c) 扩展关系:如果在完成某个功能的时候偶尔会执行另外一个功能, 则用扩展关系表示。在 UML 中扩展关系用虚线箭头加 “<<extend>>”, 箭头指向被扩展的用例。

clip_image006[4]

蓝线部分为:泛化关系。红线部分为:包含关系。绿线部分为:泛化关系。

2.类图

类图是面向对象系统建模中最常用的图,是定义其他图的基础。

类图主要是用来显示系统中的类, 接口以及它们之间的关系。

类图包含的主要元素有类, 接口和关系。 其中关系有关联关系, 泛化关系, 依赖关系和实现关系。 在类图中也可以包含注释和约束。

这里的关系十分重要,我们来一一看一下。

1). 泛化关系(继承关系):用来表示类与类, 接口与接口之间的继承关系. 泛化关系有时也称为”is a kind of”关系。

clip_image008[4]

2). 实现关系:用来表示类与接口之间的实现关系。

clip_image010[4]

3).依赖关系:比如我们上班需要交通工具,交通工具可以是公交车、私家车、电动车或自行车,步行也可以。这就是一依赖关系,使用某一个对象或对象的方法来完成一种功能。但与它不存在固定对应关系。

clip_image012[4]

4).关联关系:对于两个相对独立的系统,当一个系统的实例与另一个系统的一些特定实例存在固定的对应关系时,这两个系统之间为关联关系。

多对多双向关联,可以自动生成代码哦:

clip_image014[4]

关联关系中有一个难点,上面的图是多对多双向关联。我也可以映射出一对多和多对一的意向关联。但一对多关系中还有聚合关系和组成关系。

聚合关系:是更强形式的关联。强调部分和整体逻辑结构,但不强调生命周期。对应的属性具有get/set方法。例如计算机包含键盘和鼠标,但如果计算机不在了键盘和鼠标可以存。我们也可以为计算机换键盘和鼠标:

clip_image016[4]

UML中组成关系:是更强形式的聚合,不仅强调部分和整体,而且还强调生命周期。仅有get方法。比如人有头和手,如果主体不在了,那么部分肯定也不存在了。也不能更换。

clip_image018[4]

5).导航性:

导航性表示可从源类的任何对象到目标类的一个或多个对象遍历。 即:给定源类的一个对象, 可以得到目标类的所有对象。 可以在关联关系上加上箭头表示导航方向。

只在一个方向上可以导航的关联称为单向关联,用一个带箭头的方向表示; 在两个方向上都可以导航的关联称为双向关联, 用一条没有箭头的实线表示。

clip_image020[4]

3. 时序图

时序图用于描述对象之间的传递消息的时间顺序, 即用例中的行为顺序。

当执行一个用例时, 时序图中的每条消息对应了一个类操作或者引起转换的触发事件。

在 UML 中, 时序图表示为一个二维的关系图, 其中, 纵轴是时间轴, 时间延竖线向下延伸。 横轴代表在协作中各个独立的对象。 当对象存在时, 生命线用一条虚线表示, 消息用从一个对象的生命线到另一个对象的生命线的箭头表示。 箭头以时间的顺序在图中上下排列。

clip_image022[5]

时序图中的基本概念:

对象:时序图中对象使用矩形表示,并且对象名称下有下划线。将对象置于时序图的顶部说明在交互开始时对象就已经存在了。如果对象的位置不在顶部,表示对象是在交互的过程中被创建的。

生命线:生命线是一条垂直的虚线。表示时序图中的对象在一段生命周期内的存在。每个对象底部中心的位置都带有生命线。

消息:两个对象之间的单路通信。从发送方指向接收方。在时序图中很少使用返回消息。

激活:时序图可以描述对象的激活和钝化。激活表示该对象被占用以完成某个任务。钝化指对象处于空闲状态,等待消息。在 UML 中,对象的激活时将对象的生命线拓宽为矩形来表示的。矩形称为计划条或控制期。对象就是在激活条的顶部被激活的。对象在完成自己的工作后被钝化。

对象的创建和销毁:在时序图中, 对象的默认位置是在图的顶部。这说明对象在交互开始之前就已经存在了。如果对象是在交互过程中创建的,那么就应该将对象放到中间部分。如果要撤销一个对象,在其生命线终止点处放置“ X”符号。

5.活动图

活动图就是流程图,但在UML工具中可以加入泳道:

clip_image024[4]

6.状态图

通过建立对象的生存周期模型来描述对象随时间变化的动态行为。比如hibernate中持久化对象的三种状态:临时状态、持久化状态、游离状态。

clip_image026[4]

状态图的基本概念:

状态:用圆角矩形表示。状态名称表示状态的名字,通常用字符串表示。一个状态的名称在状态图所在的上下文中应该是唯一的。

转换:用带箭头的直线表示。一端连着源状态,一端连着目标状态。

初始状态:每个状态图都有一个初始状态。此状态代表状态图的起始位置。初始状态只能作为转换的源,不能作为转换的目标,并且在状态图中只能有一个。初始状态用一个实心圆表示。

终止状态:模型元素的最后状态,是一个状态图的终止点。终止状态在一个状态图中可以有多个。

7.协作图、对象图、包图

不画了,用处不大且非常简单。

8.组件图

组件图用来建立系统中各组件之间的关系,各组件通过功能组织在一起。

Javabean,ejb,jsp都是组件。在UML中,组件使用在左侧有两个小矩形的大矩形来表示。

组件图可以用来设计系统的整体构架:

clip_image028[4]

9.部署图

部署图用来帮助开发者了解软件中的各个组件驻留在什么硬件位置,以及这些硬件之间的交互关系。

节点:用来表示一种硬件,可以是打印机,计算机等。节点的标记符号是一个三维框,在框的左上方包含了节点的名称。

通信关联:节点通过通信关联建立彼此的关系,采用从节点到节点绘制实线来表示关联。

clip_image030[4]

一下子搞出来这么多东西,这么一看UML贯穿软件设计的各个阶段。让人感觉很好!

一定要学好软件工程,努力在工作中总结经验!

posted @ 2010-01-19 00:24 長城 阅读(1037) | 评论 (0)编辑 收藏

     摘要:          前两天我们已经完成了流程定义的管理和表单的定义的管理。今天们将整合这两大模块,使他们形成一个标准的工作流程。            在学习OA项目时,就像学习其他知识一样跟着老师的思路走。有的时候东西讲...  阅读全文

posted @ 2010-01-17 14:03 長城 阅读(733) | 评论 (1)编辑 收藏

     摘要: 来到北京,今天的天气似乎是最好的,希望不要再有降温天气了。今日继续我们的审批流程,今天的内容似乎有点多,同学们需要努力学习哦!   我个人认为今天的内容多,是为因今天加入了测试部分。使用JBPM开发OA系统,说简单些就是将自定义表单数据放到JBPM工作流中流转。我们所需要实现的功能就是,使用户可以向系统中部署自定义工作流,用户可以自己添加自定义表单。我们通过编写通用表单实体,让任何自定义...  阅读全文

posted @ 2010-01-15 23:29 長城 阅读(730) | 评论 (0)编辑 收藏

     摘要: 今日的北京气温回升,昨天是降温。天气的变暖,让大家感觉十分温暖,课上睡意连绵。汤兄弟有发现大家的状况,所以今天拿出了一点时间与大家交流学习方法或技术上的一些问题。授课进度完全在掌握之中。 未来三天的内容,学习使用JBMP解决审批流转这一大模块的需求。今日的课程内容比较简单,但在实际项目中的应用却十分重要。把WEB基础搞的差不多了,这些框架并没什么难的。更多的是应该多使用,多熟悉他们。两大重点内容...  阅读全文

posted @ 2010-01-14 23:58 長城 阅读(624) | 评论 (0)编辑 收藏

     摘要: 今日完成部门(department)和员工(employee)管理,由于昨天已经对增、删、改、查摸了遍,所以今日的内容相对就比较简单了。虽然简单,仍然有需要注意的地方。经验丰富的程序员,编写的代码十分优雅,这也是新人们严重不足的地方,当然我也应该加强这方面的能力。   不过说来也十分无聊,手动编写OA项目已二天了。这两天除了项目的架构与优雅的接口设计让我感觉好些外,其他没有什么让我感觉愉...  阅读全文

posted @ 2010-01-13 15:32 長城 阅读(400) | 评论 (0)编辑 收藏

     摘要: 上一节课我们已经完成了OA项目的基础部分,对DAO和BEAN的基本操作。今日开始学习OA项目中“组织管理”这一部分。在学习的过程中,整体上难度相对比较简单,更多的是项目经验上的学习。但在配置hibernate的映射文件时,大家有些应付不来。我也不例外,一对一映射关系我掌握的不好。但汤兄弟为人正直、善良,他在晚上下课后给我们被了    。   这个项目虽然未详...  阅读全文

posted @ 2010-01-11 23:45 長城 阅读(413) | 评论 (0)编辑 收藏

     摘要: 今日开始进行OA项目了,OA是一个大型的办公自动化管理系统。汤老师使用6天的时间带领我们做这个项目,显然是不可能全部完成的,我们要做其中重点的几个模块。这个项目将对我们之前学习的struts1、hibernate3、jbpm3、jstl1.1、junit4进行综合性的系统练习。   在跟着老师学习新技术时,课堂上我们能很好的理解各知识点。但放到一起,在实际项目中应用时还时感觉有点陌生。不...  阅读全文

posted @ 2010-01-10 10:34 長城 阅读(785) | 评论 (0)编辑 收藏

     摘要: 今日继续讲解jbpm框架,早上汤老师领着大家把昨天的内容复习了一下,然后做了总结。总结之后十分清晰。   一、昨日回顾   1.          部署流程定义:“deployProcessDefinition”向“jbpm_processdefinition” 表中添加新的流程定义记录...  阅读全文

posted @ 2010-01-09 00:03 長城 阅读(1494) | 评论 (0)编辑 收藏

     摘要: OA早就流行应用于办公自动化管理,软件行业的前辈们相比做过很多OA系统的开发。他们积累了非富的OA开发经验,以至于JBOSS开发出了一套专门针对OA系统开发的框架——jbpm。   OA使得办公自动化,那么jbpm就是为了使编写OA自动化(jbpm需要手动添加的代码比较少)。同时jbpm可以灵活定制办公流程与组件。功能十分强大,真是为了解放程序员的双手(去除那些不必要的重复性工作)。 &...  阅读全文

posted @ 2010-01-07 23:54 長城 阅读(1653) | 评论 (0)编辑 收藏

     摘要: 北京好奇怪,昼夜温差很大,有点像月球。早起时窗上的冰霜很厚实,但到了白天阳光很足,风力很小,气温很好。大连现在确在降温,零下十几度,比较罕见。可能是我离开她一会,她却变冷了。呵呵~~   今日上午把lucene的高级部分给结束了。下午搞了一下Compass,Compass是对lucene的封闭。因为lucene使用起来有些麻烦。   一、lucene高级 1.分词器 一般的分词...  阅读全文

posted @ 2010-01-06 16:51 長城 阅读(1490) | 评论 (0)编辑 收藏

     摘要:          我们这些网民,见得多了检索应用了。Google、百度、论坛内部搜索、网站内部搜索…,这些应用使用的就是检索技术。今天我们学习的主要是针对WEB应用的内部文本检索,比如论坛。我们使用的框架是lucene。授课老师是汤阳光,年轻有为!       &nbs...  阅读全文

posted @ 2010-01-04 21:26 長城 阅读(699) | 评论 (0)编辑 收藏

     摘要:          从昨晚后半夜开始下午,现在外面的雪还没停,这是来北京后最大的一场雪。早上6:30起床,然后去吃早餐。今天是元旦假期的最后一天,幸好乘车的人不多,很快就坐上了车。如果是平时可能得在大雪里走几站,甚至走到学校。气温还可以,在外面等车时,雪好美!   今日继续讲解hibernate,也是hiber...  阅读全文

posted @ 2010-01-03 23:17 長城 阅读(512) | 评论 (0)编辑 收藏

     摘要:          最近学习有些疲惫,明天就是元旦了,好快!学习幸福,今天放松一下看看电影,明天再写学习日志吧!                   新年快乐!...  阅读全文

posted @ 2010-01-02 11:13 長城 阅读(1720) | 评论 (0)编辑 收藏

     摘要: Hibernate是由徐培成老师授课的,传智播客的老师正是我要寻找的那种老师。有丰富的工作经验和项目架构经验。而且他们的教学经验也很丰富!老徐讲课十分精细,他编写的熟练程度也很让人吃惊!           Hibernate,以前老方在讲解JAVAWEB的时候有给我们编写过hibernate的简易实现原理...  阅读全文

posted @ 2009-12-30 23:02 長城 阅读(303) | 评论 (0)编辑 收藏

     摘要: 今天早上老佟将昨天的练习进行了讲解。今天的主要内容是对AJAX的汇总练习,做了两个练习都是比较常使用的应用。   一、              下拉框的级联,比如,选择下拉框一中的内容(城市名称),在下拉框二中显示在这个城市中的部门。在下拉框二中选择部门名称...  阅读全文

posted @ 2009-12-29 18:01 長城 阅读(382) | 评论 (0)编辑 收藏

     摘要: AJAX当我在前两年第一次看到这个名字的时候,我有些感觉头大。因为又出了一门新语言,自从WEB应用流行起来时,就层出不穷的新技术。那时在网上看到《Ajax实战》,很郁闷,又是500多页的新技术…。但自从接触WEB以来,很多看似复杂而艰难的东西就像窗户纸一样。AJAX也不例外,不是就对当前页面数据的更新吗!(说大话了,虽然我还没用熟它。但它确实没有相像中的那么难。)   开始整理! &nb...  阅读全文

posted @ 2009-12-28 01:03 長城 阅读(441) | 评论 (0)编辑 收藏

     摘要:   使用过AJAX技术的人都知道大名鼎鼎的JQuery。虽然我来学习之前有看过AJAX的视频,但那时对WEB应用这个东西还比较模糊,不清楚HTML、JSP与Servlet是怎么工作的,甚至不知道JQuery包装的是什么东西。今日的学习再结合昨天的JavaScriptDOM的内容,让我对此十分清晰。JQuery原则:“write less, do more.”,这句话已充分说明它对简化使用...  阅读全文

posted @ 2009-12-26 15:30 長城 阅读(909) | 评论 (0)编辑 收藏

     摘要:          今天学习JavaScriptDOM加强,javascript灵活性大家都知道。但我们学习的只是使用JavaScript 对页面的操作,为学习AJAX打下基础。            JavaScriptDOM对页...  阅读全文

posted @ 2009-12-25 00:40 長城 阅读(451) | 评论 (0)编辑 收藏

练习:实现一个简单顾客管理应用,可以添加顾客、修改顾客、查询顾客和删除顾客。

        数据库:MySQL

        连接池:c3p0

        DAODBUtils

        显示层:Sturts1

 

流程:

clip_image001

 

 

要源代码的请联系:jiachangcheng@gmail.com

posted @ 2009-12-25 00:33 長城 阅读(213) | 评论 (0)编辑 收藏

     摘要:          今天是Sturts1的最后一天,老佟下午做了一个综合性练习,十分经典!通过这个练习也让我感觉到了老佟的功力深厚。这个练习明天我再做。            今天的重点内容有:MappingDispatchActi...  阅读全文

posted @ 2009-12-22 23:55 長城 阅读(264) | 评论 (0)编辑 收藏

     摘要:          今天是Struts1的第二天,明天是最后一天。看我这么说,多少感觉Struts1有点烦。因为总是使用配置文件,不用怎么写代码,一个强大的表单校验功能就完成了。其实我们一直专注于代码的重用,减少重复工作所带来的枯燥与麻烦,从这个角度上想,Struts是相当好的!    &...  阅读全文

posted @ 2009-12-22 20:24 長城 阅读(465) | 评论 (0)编辑 收藏

     摘要:          Today is first day of J2E高级部分。今天开始讲解struts1,为什么要讲1不讲2呢?因为自struts1以来,就应用广泛。即使Struts2已经发布了,但使用struts1开发的WEB应用比较多见,因为Struts2与Struts1有很大的差别,所以将以前使用Struts1开...  阅读全文

posted @ 2009-12-21 00:19 長城 阅读(424) | 评论 (0)编辑 收藏

     摘要:          今日是JAVAWEB最后一课,JAVAMAIL。E-mail在当今的日常生活中已经成为人们重要的通信方式之一,在WEB应用中E -mail被做为与用户通信的最重要方式。如今各大综合性网站都有提供自己的mail服务,企业或各其他专业性网站也有自己的内部mail服务器,天于为工作交流与合作。所以,学习E-...  阅读全文

posted @ 2009-12-18 23:36 長城 阅读(981) | 评论 (0)编辑 收藏

今天早上去公司把订单处理模块完成了,然后自己在看一些关于Android、JDO、GWT方面的资料。很早以前就关注google推出的这些开源项目,对Google的这种胸怀十分认可,。由于学完了JAVAWEB(还差JAVAMAIL)部分,再加上以前的桌面开发经验,看这些东西感觉好多了,不再恐怖了。

Android开发被做为开发课程的最后一部分,那是十分诱人的。早在1.1的时候,我就下载AndroidSDK,想在上面写点东西,但由于能力有限,所以只跑了他的HelloWord!例子。如今即使自己慢慢去看Android的UI、数据存储、网络…没多大的问题。

同学们的学习劲头十分好,都在相互的问问题,老方没怎么闲着。能把这个小练习搞定,那以前学的知识就没多大问题了,而且十分有成就感(相对WEB新手而言)!老方说这个练习搞定了,以后学习struts框架就没多大问题了,他的意思不是学会怎么去使用struts框架,而是struts框架的实现原理。当然还包括其他的框架。

十分期待后边的大项目,一定要认真学好!

呵呵,休息了哈!~~

posted @ 2009-12-16 22:47 長城 阅读(992) | 评论 (0)编辑 收藏

         今天一大早去到学校,便开始编写网上商城。写到下午3点多,完成了!感觉十分的好,因为这是自己第一次将所学的WEB知识规整到一起了。做出来的成品,虽然不能拿出来展示(只是个练习,很多校验没加),但已经让我十分开心了。以前为网上商城这个东西还是十分的恐惧,工程显得比较庞大。其实加上了论坛和评论等功能,还是十分庞大的。

         今天写些什么好呢?把工程中的一个难点写出来吧!

         我们在添加书籍的时候可以添加一张书籍的照片,照片是存在硬盘目录里的。而数据库中保存的是照片在硬盘目录中的路径。

1.        如何获取浏览器向服务器端发送过来的图片文件?使用request输入流吗?太麻烦了!Apache组织为我们提供了一个方便的工具——commons-fileupload,它可以很好的解决这一问题。

2.        如何确保,图片的名称不一样?当然是大名鼎鼎的UUID了,生成了一个不重复的随机串就OK了!

我把代码粘贴出来:

private String uploadFields(HttpServletRequest request,

           Map<String, String> map) {

       // 获取request中的请求参数

       DiskFileItemFactory dfif = new DiskFileItemFactory();

       ServletFileUpload sfu = new ServletFileUpload(dfif);

       sfu.setHeaderEncoding("UTF-8");

       String file = null;

       try {

           List<FileItem> list = sfu.parseRequest(request);

           // 遍历所有参数

           for (Iterator<FileItem> its = list.iterator(); its.hasNext();) {

               FileItem fi = its.next();

              // 是否为表单字段,如果不是则为文件上传输入流。

              if (!fi.isFormField()) {

                  InputStream is = fi.getInputStream();

                  // 获取图片目录

                  String dir = this.getServletContext().getRealPath("/")

                         + "/images/";

                  File dirF = new File(dir);

                  if (!dirF.exists())

                     dirF.mkdirs();

                  // 使用UUID创建文件名称

                  file = UUID.randomUUID().toString()

                         + fi.getName().substring(

                                fi.getName().lastIndexOf("."));

                  // 写出文件

                  byte[] buf = new byte[1024];

                  int len = 0;

                  FileOutputStream fos = new FileOutputStream(new File(dir

                         + file));

                  while ((len = is.read(buf)) != -1) {

                     fos.write(buf, 0, len);

                  }

                  // 关闭流

                  fos.close();

                  is.close();

                  fi.delete();

              } else {

                  // 如果为表单字段,则将这些信息添加到map中返回给调用函数

                  // filter无法对文件上传进行过滤,所以需要手动对编码转换。

                  map.put(fi.getFieldName(), new String(fi.getString()

                         .getBytes("iso8859-1"), "UTF-8"));

              }

           }

       } catch (Exception e) {

           e.printStackTrace();

       }

       // 返回在服务器保存后的文件路径。

       return "images/" + file;

    }

        

然后老方在下午4点钟时,给大家讲解了订单的提交。订单提交是唯一涉及到多表操作的模块,这也是练习的重点。一个多对多的设计方式。如下模块流程图。

clip_image001

看到里边的orderitemorders表了吧,这就是一个多对多的关系。Orderitem就是中间表,记录订单的的id和书的id,还包含数量和总计字段。这样,添加订单或是查询订单这样操作起来更直观方便些,这就是面向对象的有点。

         订单处理模块中也是首次使用到MVC,以前我认为Servlet就是业务逻辑层,其实不是。Servlet只是个Web层(V)。通过今天老方的讲解,我发现自己并未完全融入面向对象的设计模式,还有些面向过程的东西在影响着我。不过我想,这一点很快就会改变!

         今天的练习确实达到的预期效果,虽然有些同学还未完成。不过,有的同学昨天晚上已经完成了,有的上午已经完成了。卧虎藏龙!我需要向他们好好学习。

         今晚回来时我把老方的工程复制到工作空间里了,结果我的工程名与他相同。晕!幸好我的包名与他不同,只有几个JSP页面的名称与他相同,吓我一跳。我今天尝试着将数据库字段、requestresponse中的属性名称封装到静态类中,但操作起来十分不方便,比如编写一个SQL语句。在大工程中,这肯定非常有用!

         继续整理工程去

         加油!

posted @ 2009-12-15 21:04 長城 阅读(857) | 评论 (0)编辑 收藏

         这个经典的练习项目,已经揭晓——在线商城(图书)!如果能将这个项目搞定,那就没什么问题了。对自己有信心。今天不知写些什么好了,晚上回来本想去写这个项目的。但日志是要坚持完成的,那就把项目框架和流程写出来吧!订单处理这个功能,老方留着明天下午或后天再讲。

 

一、后台产品录入模块:

clip_image001

 

 

二、产品展示模块:

clip_image002

 

 

三、产品购买模块:

clip_image003

 

 

四、用户模块:

clip_image004

 

 

         上画面的图仅代表个人水平,时间问题。老方没有完全按照企业标准化开发流程来进行,因这个练习时间是挤出来的。但标准化开发一直是我认为十分重要的东西,所以今天自己试着画图出来。

 

         虽然对WEB各方面技术掌握还不熟练,但已经很有感觉了。其实就是叠代码,重要的是要有框架的叠。今天突然的一堆东西压过来,看着老师在一边讲模块,一边写代码,JSP工农与Servlet等,跳来跳去多少感觉有些不适。不过都是以前学过的东西,自己写上来问题不大。今天看着老方写的东西,我个人认为有些东西可以优化出来,比如数据库字段等可以定义为常量。当然老方也不可能讲的太优化了,这样我想那些没多少经验的同学肯定晕了。因为今天的文件十分多!

 

         好了,我要开始写代码了!

 

         加油!

posted @ 2009-12-14 20:50 長城 阅读(725) | 评论 (0)编辑 收藏

     摘要:          除了JavaMail今日是JavaWeb部分的最后一天了,还有三天的时间是做个小项目。将之前学习的所有知识串起来,准备迎接高级部分。嘿嘿!终于到了高级部分!          今日主要内容是JSP自定义标签与JSTL,之...  阅读全文

posted @ 2009-12-14 00:03 長城 阅读(422) | 评论 (0)编辑 收藏

(转自:http://user.qzone.qq.com/252796718

从远古时期至今,铺天盖地全球各地似乎都有“上天的使者”降临人间——神、巫妖、仙,今天统称为占卜。

中华文明五千年,占卜具体源自何时我也不去查资料了。根据以往的阅读,只知道在远古时期就已经有了,就从伏羲开始说起吧!那时伏羲便开始总结大自然的规律,比如春夏秋冬,二十四节气,一天当中的各时辰,何时耕种、何时收割,还制作了一些测时、测气的工具。这些科学技术是不会被普遍大众掌握的,所以掌握这些技术的人一般都是天子级人物。在诸子百家争鸣之前,这些技术也一直被皇宫高院内的“囚徒”们掌握着,他们以此告诉人们我是上天下派的“天子”。我可以告诉你们何时该做什么,何时应该怎么做,这也被当时的人们所接受了。他们个人的意图,也被理解为是天意。

在诸子百家争鸣之后,“天子”的烙印依然深深的印在人们的心中。虽然起始的那些科学技术已经变成了常识,但人们似乎并不愿意从科学的角度去理解。儒、墨、道、法等这些百家,依然去使用这些知识,去发挥这些知识。力量切实很大,要不哪来的中华文明。在此就给他们一个统称——易经。我看的易经里,有这意思,一切都是源自易经。我只是简单看看,不去深入研究,在此就把易经做为一个统称吧!这样方便。

本篇主要说占卜。我们知道,易经中有占卜技术。比如,八卦、龟壳、推背图、抽签、星相、面相。国外的有,塔罗牌、星座。如此种种,可以测天、测地、测人测以住、测未来。

我出生并在农村长大,听了多的“大仙”。人们遇事迷惑时,便愿意去“求仙”,也有的正常家庭也愿意去“求仙”。希望这些仙能帮助他们,求个心理上的安慰或幸福吧!我来到城里读书和工作,也遇到大街上,也有自己“开店”的。有穷人去求,也有富人去求。越准的,人越多。这些“仙者”,在咱们这片大地上非常的多。

其实世界各的占卜应该都一样,咱们统分一下。一种是求学求出的仙,一种是自成仙。我在这也不叫他们仙了,给个统称——卜者。

首先来分析一下自成卜者,这些人有什么特点?你会发现,年龄都比较大。当然也有年轻一些的,我见过的至少24岁以上。为什么没有小娃娃成仙的?仙还没长大?哈哈,不是!这些人都比较成熟,有一定的生活经历。你有点茅塞顿开了吗?

首先卜者善细观,要比平常人细致的多。我们知道,表象磁场是原始磁场和核心磁场的表象,所以一个人经历什么,或一个人从什么环境成长,受原始磁场的影响多大?都会影响自身的核心磁场,以表象磁场表现出来。这些卜者正是通过观察人身的表象磁场来判断一个人的以住和未来。因为,一、表象磁场表现出来的肯定有你的过去。二、因为你的过去影响了你的磁场。而你的这些影响,也会驱使你未来是什么样子的。所以,卜者可以通过这些来判断。

唉?即使他们可以细观入微,为什么他们能说的那么准?这就是他们的生活经历了,有些人喜欢细观很多东西,比如大自然中的各种现象,动物,人。他们观到了你的表象磁场,就拿这些经历和心得往你身上套。因为你身上的表象磁场,与他们见过的十分相近,甚至完全相同。

这正如我们平凡人看人一样,你第一次看到某人。就愿意观察他身上的特质,通过他身上外在的表象,来确定他一个个什么样的人!这下你明白了吧!再举一例,医生可以根据你的神情或者你身体的表象特征,就知道一个人是不是健康的或者生了什么病!

再次从人身具有的特殊能量来分析一下。你见过或听的卜者,是不是女性居多?我是!其一、因为,女性比较心细。其二、因为,女性是个感性的动物。感性?第六感?我把这种特殊能量理解为人身磁场的一种特殊感应能量。人身上所散发出的磁场能量相比普通人,卜者们可以感应的更深一些。他们为什么具有这此感应能量?不应该说他们为什么具有这种能量,而应该为他们身上的这种能量被开发出来了,普通人没有被开发出来。他们为什么会开发出来?他们生活以来就观至入微,喜欢思索,可能是这些习惯导致的吧!还有就是受过某种刺激的人,这些能量也被激发出来了。在此,就不深入研究了。

       然后说一下求学求出的卜者,这个比较多见,也广为被接受。因为这种力量是比较强大的。OK,我们来分析一下。易经中的占卜,它是经历了千年的考验和验证的。前面我们提到过伏羲总结的时令和气象,易经中还有对面相、手相、生辰八字、姓名、风水、星相等这些总结。面相、手相是表象,生辰八字、姓名也代表一种能量场。而且,易经面面具到,哲学思想、科学技术等,这些都提升着它的“身价”!

我们首先从面相、手相分析一下,有听说过面相和手相会变的人吗?一个人生下来是多么漂亮他长大后就一定很漂亮吗?我见过相能变,我见过有些人小时候漂亮,长大就不那么理想了,有些人小时候长相平平,长大却很理想。如果你看过我前些写的文章,你就知道一个真正漂亮人的是什么?面相和手相,只不过是表象磁场,是原始磁场和核心磁场的表象。眼睛是心灵的窗户,那你的面相、手相、表情就是你磁场的表象。历史的人们去总结这种表象,然后把他们分类。哪些是好的,哪些是不好的?那些表象,是在经历什么情况下产生的,这些表象会在将来发生什么?OK,明白了吗?

再从生辰八字、姓名来分析一下。生辰八字是什么?是时令!我从开篇中便提到,我只是想分析一下人身的磁场。在这里我不得不提到其他磁场来解释时令这个东西。我把宇宙的所有物质都认为是以能量的形式存在的。时令,它代表的能量就多了,比如各星球的轨迹、气温的变化这些在某个时令下通常发生的能量。正是这些磁场对人出生时的影响,才让人们之间的磁场大不相同。在易经中,人们总结各时令出生的人磁场是什么样子的,未来的走势是什么样子的,现在广为流形的星座占卜也与此相同。一个人出生时,具有原始磁场和核心磁场。这是他们的原型。这些磁场将影响着一个人的未来。所以,我们觉得他怎么算的那么准,呵呵,确实很准,但那都是经验总结。看过星座占卜的人便知,星座讲解的每个是星座的性格与我们差不多,但使用星座具体测算到哪一天,比如今天的运势等,就十分差劲了!

姓名测算,汉字具备的最大特点是什么?是寓意!从象形汉字到现在的简化汉字,每一个字都代表一种意。汉字是最能反应大自然事物的文字。当一个人起了一个名字,这种象意便伴随着他。我们知道,大自然一切事物皆能量。从心理这个角度说,这种象意能量(象意能量指,汉字代表的那个事物的能量。)也影响着一个人的核心磁场。名字伴随着他的时间越长,影响越深!如果说一个人在娘胎里,命运就已经定下来了。那为什么现在还有那些改名字的?为什么易经大师还要给人改名字,而且还让你要深入体会这个好的名字。让他的意深深的印在你的心中,这正是影响你的核心磁场,当这种好的象意深入你的核心磁场后,你的核心磁场发生了变化。核心磁场的变化,引起你的表象磁场也发生了变化。此时,那卜者和易经大师看到你,都说你好!

易经学说,整个世界都在研究。他是咱们伟大的国学!

唉,长城。那应该如何却改变那所谓的“命运”?

OK,我们已经知道。占卜学是从表象磁场分析一个人,那我们就应该去改变表象磁场,只有改变了核心磁场,才会引起表象磁场的改变。比如,前边的改名字就是一种方法。发达国与中国一样,很早就分析这些东西了。最近在国际上兴起的学说,得到了大家的认可——吸引力法则!《秘密》、《神奇的二十四堂课》《心灵的鸡烫》这些心理学。都是在建设人的核心磁场,中国的儒家思想也是在建设人的核心磁场。去用心多读读这些书吧!

因为,人是脆弱的!某些情况下也是无知的。通过上边的解释,我想你已经明白了。这所谓的“命运”是多么的科学!我希望大家不在迷信,而是从科学的角度去理解。这个课题比较庞大,不能一下子从各个方面分析出来,只能一点一点来!

     咱们共同建设核心磁场吧!勇敢面对人的本性、面对自己的缺点,建立自信等…。这些品质,从古至今一直被提倡和称赞。好了不多说了,还需要学习、工作。

posted @ 2009-12-12 12:38 長城 阅读(531) | 评论 (0)编辑 收藏

     摘要:          今日是JDBC的最后一天了,继续JDBC的高级应用。说是高级应用,只是针对JDBC的再次封装,使得使用JDBC变得更加简单。DBUtil就是这样的库!今日上午首先讲解JDBC操作多个实体之多对多关系,Hibnate正是使用了这样的手法,这一功能让人感觉很好。然后方老师将以前使用的JDBC操作中,有重复...  阅读全文

posted @ 2009-12-11 23:12 長城 阅读(801) | 评论 (0)编辑 收藏

     摘要:          Oracle数据库部分终于在昨天结束了,整理学习日志到很晚。今天继续讲解JDBC,是方老师授课的。方老师在我们班还有六堂的课程,多少有些舍不得,他是个好老师。学完这六堂课,JAVAWEB基础到此也就结束了(09-12-18)。十分渴望快些学习到项目那,把这些技术混合运用,做出个像模像样的东西来! &n...  阅读全文

posted @ 2009-12-11 00:18 長城 阅读(345) | 评论 (0)编辑 收藏

     摘要:                 从张老师的基础增强课上,我就想深入了解一下类加载器。然后听懂了张老师的课,知道了JAVA类加载的方式,以及实现自己的类加载器的应用。但一直没有自己去编写类加载器,也对class文件的具体处理方式不了解。今日休息,有时间...  阅读全文

posted @ 2009-12-10 01:09 長城 阅读(247) | 评论 (0)编辑 收藏

     摘要:                 今日的内容比较多,有些吃不消。不多说了,赶紧复习!   一、Merge语句 根据条件在表中执行修改或插入数据的功能,如果插入的数据行在目的表中存在就执行UPDATE,如果是不存在则执行INSERT: -避免了...  阅读全文

posted @ 2009-12-10 00:59 長城 阅读(815) | 评论 (0)编辑 收藏

     摘要:       数据库比较枯燥,我说的是使用数据库不是做数据库。总是用SQL语句那么跑来跑去,想把数据库讲解的十分有趣,着实不是一件容易的事。只是在PLSQL里编写SQL语句,然后调用、查看结果。虽然数据库很枯燥,但它在项目中的功用却是十分重要的。我原未如此的深入使用过数据库,近两天一见,其功能也让我十分兴奋,以前自己写的小东西,走了些弯路! &nbs...  阅读全文

posted @ 2009-12-08 00:01 長城 阅读(948) | 评论 (2)编辑 收藏

     摘要: (转自:http://hi.baidu.com/%C9%AE_%CC%C6/blog/item/9e2a8b0887008a8ad0581b3d.html) 这是转载自一个兄弟的,写的比较细致,受益颇多!我只是针对图片进行了修改,使它看起来逻辑清晰一些。 十分感谢这位兄弟!        Java平台提供了一个全新的集合框架。...  阅读全文

posted @ 2009-12-06 21:48 長城 阅读(422) | 评论 (0)编辑 收藏

         今日学习的是在Oracle中使用简单的查询语句,与“2009-11-29传智播客 数据库——数据库入门[mysql]”学习的内容差不多,不知写些什么好了。现在学习的都是单表查询,后天应该就开始学习多表操作了。

 

         Oracle中有个虚拟表“DUAL”,说是虚拟,只是这个表不需要用户创建。在数据库里默认就有的,它有什么用途?用一句话概括一下:只是不是针对某表记录的操作,就需要这个表来完成!比如,打印当前系统时间就需要:“select sysdate from dual”,但在MySQL等数据库中确不需要这样,在MySQL中直接使用“select now();”即可。

 

         今日老冯讲解的Oracle函数比较简单,但也让我感觉到Oracle的强大。比如说有一个“decode”函数,说是函数更像是“switch catch”语句。老冯有个例子,要按照职位给员工涨工资:

SELECT   last_name,salary,

      decode(job_id,

          '总经理',1.15*salary,

          '副总经理',1.10*salary,

          salary)  工资

FROM employees;

 

         可见它的强大了吧!下面列一下日期时间与文本互转的格式和数字与文本互转的格式:

期日格式:

格式控制符

描述

YYYY  YYY YY

以数字表示全年(分别代表4位、三位、两位)的数字年

YEAR

年的拼写

MM

两位数字月

MONTH

月的全拼

MON

月名称的缩写

DD

数字日

DAY

星期的全拼

D

星期中的第几天 

DY

表示三位缩写的星期

 

         注意:调用TO_DATE函数时,比如TO_DATE(“2009-12-05”,”yyyy-mm-dd”),其中第二个日期格式字符串必须与第一个参数的时间格式相同。

 

数字格式控制符:

数字格式控制符

描述

9

代表一位数字,如果当前位有数字,显示数字,否则不显示(小数部分仍然会强制显示)

0

强制显示该位,如果当前位有数字,显示数字,否则显示0

$

增加美元符号显示

L

增加本地货币符号显示(RMB)

.

小数点符号

,

千分位符号  3,000,000,000.00

 

         其他操作函数,就去下载了个Oracle函数大全吧!操作数据库这些语句,更多的就是练习了,练习的让自己很容易记下来。

 

         来传智播客学习的这段时间,让我感觉很好,充实了很多。真是物有所值,也搞不懂那些教一些基础知识加点高级内容的培训机构却要1万多。而且还是远程视频授课!真是越垃圾的学校越贵,广告做的真好!课间时,大家有与老冯谈论起大连的软件产业。只要做这行的都知道,大连的软件产业外包是重点,而且这个城市是出了名的收入低消费高。这些到也罢。要命的是,给日本人干活,那真叫苦力!似乎一点动脑子的东西都不愿意让你来做,做这种工作的人应该都不叫程序员吧。应该叫“打字”员,专门按照日本人写的文档来打代码。如果这种工作在中国过多,还到那里去发展什么自己的核心竞争力啊!不过没办法,人家愿意出钱。也有听说,日本人出的一个人月是2-3万人民币,但到程员手中却只有3000-5000元。呵呵!

 

         无论如何,学习结束后我还是想回到大连。我喜欢那里!

posted @ 2009-12-05 21:20 長城 阅读(350) | 评论 (0)编辑 收藏

     摘要:          从今日起连结四天Oracle,由冯威老师授课。由于以前没有接触过Oracle数据库,所以上午讲解的Oraclae数据库的一些专业名词,让我有点措手不及。不过没关系,回家看一下就可以了。上午的内容比较枯燥,下午还好。下午讲解在Oracle数据库中使用SQL语句,这相对轻松些。SQL语句与前两天学习的在M...  阅读全文

posted @ 2009-12-04 22:46 長城 阅读(315) | 评论 (0)编辑 收藏

         我对IO流的理解上并没什么问题,但前一片段上课时有经常使用到IO流。发现自己对JAVAIO流没有系统的概念,JAVAIO流的要类是InputStreamOutputStream,这两个类的子类较多,而且还有一部分的包装类。SO,我要对JAVAIO流有一个系统的学习。

JAVA IO 全视图:

JAVAIO 

InputStream部分:

         InputStream,它是一个抽象类,所示所有输入流的的超类。它包含了输入流的基本操作。

         AudioIntpuStream,音频输入流对应的输出。结合AudioSystem可以实现:

1.        从外部音频文件、流或 URL 获得音频输入流

2.        从音频输入流写入外部文件

3.        将音频输入流转换为不同的音频格式

ByteArrayInputStream,字节数据输入流。字面的翻译。它包含了一个缓冲区,该缓冲区从输入游戏中读取字节。因为数据已经读入到缓冲区中,所以关闭流对它无效,仍然可以调用它的方法而不会抛出异常。

FileInputStream,文件输入流。从文件中获取输入字节,包含对文件流的特殊方法。如果要读取字符流,可以使用FileReader

PipedInputStream,管道输入流。用于线程间的通讯,但不要在同一个线程中使用管道输入流和输出流,这样可能造成线程死锁。

SequenceInputStream,输入流的逻辑串联。它将多个输入流串联到一起读取。比如它串联了输入流AB,当读取到A的结尾时,便从B流中接着读取。

StringBufferInputStream,与ByteArrayInputSteam类同,ByteArrayInputStream用于处理字节,而StringBufferInputStream用于处理字符。

ObjectInputStreamJava对象输入流。实现将对象从输入流中读取。比如将ObjectOutputStreamFileOutputStream结合使用,将JAVA对象序列化后保存到文件。然后再使用FileInputStreamObjectInputStream将文件中被序列化的JAVA对象反序列化回来到程序中。也可以在远程通讯中使用对象流传输JAVA对象,这个比较高级。

FilterInputStreamJDK帮助文档中说它只是简单的重写将所有对输入流的操作传递给它所包含的InputStream输入流。嗯,其实它是一个Decorate模式的超类。从它继承了一些子类,用于提供一些额外的功能,向下看。

         BufferedInputStream,对InputStream增加了缓存功能。以更好的支持markreset方法。

CheckedInputStream,校验输入流。可用于验证输入数据的完整性。与Checksum配合使用。

CipherInputStream,解密输入流。与Cipher配合使用。CipherOutputStream是加密输出流。对数据进行加解密使用。

DigestInputStream,摘要输入流。这个比较少见,棱一看JDK手册,不太了解。不过数据摘要是用于安全通讯或数据完整证验证的。哦,它与MessageDigest配合使用,可见JAVA IO设计者的用心!

LineNumberInputStream,行号输入流。此类已过时。它假定输入流是字符流,它调用InputStream的方法并将\n\r统一转换成一个\n。每读到一个换行时,便将行号加1,初始行号为0。此类不深入研究了!

ProgressMonitor,进度监视输入流。用于监视用户读取的进度,如果这个流很大。它会自动弹出进度提示窗口,用户可以点击“Cancel”按钮,取消读取。这个也实JAVAIO给实现了,比较人性化!

PushBackInputStream,推回输入流。就是可以将从输入流中读取的数据,调用unread方法将数据推回到输入流中,也可以将其他数据推进去。JDK手册中举了一个例子说,将标识符字符读取后,可以推回到输入然,然后重复读取,在哪里需要这样的应用呢?

DataInputStream,数据输入流。可以以与机器无关方式从底层输入流中读取基本JAVA数据类型。

InflaterInputStream 解压缩输入流。解压缩以“deflate”压缩格式的流过滤器。它与Inflater配合使用,Inflater使用流行的ZLIB压缩库。

         GZipInputStreamGZip解压缩输入流。解压缩以“GZip”压缩格式的流过滤器。

         ZipInputStreamZip解压缩输入流。解压缩以“Zip”压缩格式的流过滤器。

         JarInputStreamJar解压缩输入流。可以读取Jar文件中的内容。其实Jar的压缩格式就是Zip格式。但它比Zip多了一个Manifest条目。Manifest 可用于存储有关 JAR 文件及其条目的元信息。关于Manifest,可以查看JDK手册。

         OKOutputStream在此就不一一列出了。因为OutpuStream中子类与InputStream中的子类相对应。但OutpuStream不完全具有与InputStream中的子类对应的类。因为没必要,比如AudioInputStream,没有与之对应的AudioOutputStream,我们需要读取指定格式的音频即可。如果想写出音频数据直接用FileOutputStream即可!        

         Java中还有WriterReader两个超类,主要用于处理字符流,这个比较简单就不在此做介绍了。OK

posted @ 2009-12-03 22:48 長城 阅读(393) | 评论 (0)编辑 收藏

JAVAIO

posted @ 2009-12-03 16:22 長城 阅读(270) | 评论 (0)编辑 收藏

Today is JDBC高级部分,课程的主要内容有连接池与事务。这都是在应用开发中比较常用,比较重要的。

一、使用配置文件优化JDBCUtil,使用工厂模式隔离DAO层:

昨天有说过将对数据库获取连接和释放的操作单封装到一个类中,如:

import java.sql.*;
import cn.itcast.cc.exception.JDBCUtilException;

/**
 * JDBC工具类
 * 
 * @author Administrator
 * 
 */
public class JDBCUtil {
	// 连接数据库时所需要的参数
	private static String url = "jdbc:mysql://localhost:3306/jdbc";
	private static String username = "root";
	private static String password = "root";
	// 类被加载时就加载驱动
	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	// 获取连接
	public static Connection getConnection() throws JDBCUtilException {
		try {
			return DriverManager.getConnection(url, username, password);
		} catch (SQLException e) {
			throw new JDBCUtilException(e);
		}
	}

	// 释放连接等资源,下面是一种健康的释放方式
	public static void release(ResultSet rs, Statement sta, Connection conn)
			throws JDBCUtilException {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				throw new JDBCUtilException(e);
			}
			rs = null;
		}

		if (sta != null) {
			try {
				sta.close();
			} catch (SQLException e) {
				throw new JDBCUtilException(e);
			}
			sta = null;
		}

		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				throw new JDBCUtilException(e);
			}
			conn = null;
		}
	}
}

从上面我们看到其中装载数据库驱动和获取数据库连接的代码:

Class.forName("com.mysql.jdbc.Driver");

DriverManager.getConnection(url, username, password);

我们使用了固定的url,它是一个成员。在以后的开发中,如果要使用其他的数据库或者数据库的用户名密码被改变了,我们还需要手动的修改上边的代码,重新编译。这是一种不良的设计方法,为了使我们的代码与数据库分离,我们可以将这些参数配置到配置文件中。这样在需要使用时去读取配置文件中的对应值即可。以后换数据库或更改了用户名,直接修改一下配置文件即可。

昨天有提到过DAO层,DAO层专门用于处理对数据库的CURD操作等,比如,添加用户、查找用户、修改用户、删除用户,我们可以把这些操作封装到一个类中(UserDao.java),它所处位置就是DAO层。比如,用于处理用户注册的Servlet,在这个Servlet中直接实例化一个UserDao对象。然后调用userDaoObj.add(userbean);方法即可实现用户的注册。

如果我想换一种数据存储方式,比如配置文件,我只将用户信息保存在配置文件中。这样我就需要修改UserDao.java,但有时又需要UserDao.java这个功能类怎么办?我只能重新创建一个专门处理配置文件数据的类(UserDaoPro.java)。这样我又需要修改Servlet中的代码,将实例化UserDao的代码修改为实例化UserDaoPro对象。那UserDaoPro与UserDao的接口是不是相同的呢?如果不相同麻烦就大了,JAVA是提倡使用接口编程的,就是为了实现接口的统一化。

可见,上面的这种实现方式是存在问题的。即使接口统一,我们还需要修改Servlet中的代码。此时工厂模式派上了用场,还记得工厂模式吧!是这样的:

1.定义一个UserDao接口,统一对用户操作的接口。

2.定义一个UserDaoFactory的工厂类,专门生产UserDao对象。

3. UserDaoFactory工厂从配置文件中读取实现了UserDao接口的类名称。使用此类生产产品——UserDao对象。

4.在Servlet中使用UserDaoFactory工厂来创建需要的UserDao对象。

这样就实现了DAO层与Servlet的完全分离!完美!

二、数据库连接池:

每当有一个新的连接发生时,数据库就需要创建一个Connection对象来处理连接。访问结束后,Connection对象被释放。数据库创建一个Connection对象,是十分耗时且消耗较大的服务器资源。试想,如果有500个用户同时访问数据库,数据库同时创建500个Connection将会是什么样子!因此,连接池这一技术诞生了。

连接池,在服务器加载WEB应用后。WEB应用会自动创建一个连接池,池中包含多个Connection对象。每当有新的连接请求时,便从这个池中拿出一个Connection对象用于处理连接,使用完成后,便还回给这个池子。下面代码为连接池的实现原理:

import java.io.*;
import java.lang.reflect.*;
import java.sql.*;
import java.util.*;
import javax.sql.DataSource;

/**
 * 自己编写的简单连接池类,单例模式实现。
 * 
 * @author Administrator
 * 
 */
public class JDBCUtil implements DataSource {
	private static LinkedList<Connection> conns = new LinkedList<Connection>();
	private static JDBCUtil myjdbcutil = new JDBCUtil();

	private JDBCUtil() {
		// 取配置文件
		InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream(
				"cn/itcast/cc/db/myjdbc.properties");
		// 装载配置文件
		Properties pro = new Properties();
		try {
			pro.load(in);
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 取出配置项
		String driver = pro.getProperty("driverClassName");
		String url = pro.getProperty("url");
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		int initialSize = Integer.parseInt(pro.getProperty("initialSize"));
		// 加载驱动,填充连接池
		try {
			// 常用的数据库,驱动类被加载时,都会自已加载驱动。
			Class.forName(driver);
			for (int i = 0; i < initialSize; i++) {
				conns.add(DriverManager.getConnection(url, username, password));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 返回单例的实例
	public static JDBCUtil getInstance() {
		return myjdbcutil;
	}

	public Connection getConnection() throws SQLException {
		if (conns.size() > 0) {
			final Connection conn = conns.pop();
			// 此处需要使用动态代理技术,因为返回的Connection对象在关闭时需要被收回到LinkedList中。
			// 动态代理,增强Connection.colse()方法,将它回收到LinkedList中。但不销毁!
			return (Connection) Proxy.newProxyInstance(JDBCUtil.class
					.getClassLoader(), conn.getClass().getInterfaces(),
					new InvocationHandler() {

						public Object invoke(Object proxy, Method method,
								Object[] args) throws Throwable {
							// 如果是close方法,则将conn回收到List中。
							if (method.getName().equals("close")) {
								conns.push(conn);
								return null;
							}
							return method.invoke(conn, args);
						}
					});
		}
		throw new RuntimeException("服务器忙,请稍后连接!");
	}
}

有很多服务器为用户提供了DataSource(数据源)的实现。DataSource中包含了连接池的实现。也有一些第三方组织单独提供了连接池的实现:DBCP、C3P0。所以,在以后的开发中,我们可以直接使用这些资源。

著名的DBCP比较常用,使用DBCP必须引入Commons-dbcp.jar和Commons-pool.jar。Tomcat中的连接池也是使用DBCP实现的。DBCP的使用非常简单:

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtil {
	private static DataSource ds = null;
	static {
		try {
			// 取配置文件
			InputStream in = JDBCUtil.class.getClassLoader()
					.getResourceAsStream(
							"cn/itcast/cc/db/dbcpconfig.properties");
			// 装载配置文件
			Properties pro = new Properties();
			pro.load(in);
			// 创建数据源
			ds = BasicDataSourceFactory.createDataSource(pro);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 获取连接
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();
	}
}

 

其中的配置文件“dbcpconfig.properties”:

#连接设置

#驱动器

driverClassName=com.mysql.jdbc.Driver

#数据库连接URL

url=jdbc:mysql://localhost:3306/jdbc

#数据库用户名

username=root

#数据库密码

password=root

#初始连接池数量

initialSize=10

#最大连接数量

maxActive=50

#最大空闲连接

maxIdle=20

#最小空闲连接

minIdle=5

#超时等待时间以毫秒为单位 6000毫秒/1000等于60秒

maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]

#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。

connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。

defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。

#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)

defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。

#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

defaultTransactionIsolation=READ_UNCOMMITTED

上面是直接使用Apache提供的DBCP实现的连接池,接下来看一下使用JNDI技术在Tomcat中配置连接池,在Tomcat服务的conf\context.xml文件中添加:

<Context>

<Resource name="jdbc/datasource" auth="Container"

type="javax.sql.DataSource" username="root" password="root"

driverClassName="com.mysql.jdbc.Driver"

url="jdbc:mysql://localhost:3306/jdbc"

maxActive="8" maxIdle="4"/>

</Context>

Name: 对象在JNDI容器中的名称。

Auth:所使用的容器。

Type:对象类型。

Username:数据库用户名。

Password:数据库密码。

driverClassName:数据库驱动类。

url:连接数据库的URL。

maxActive:最大连接数。

maxIdle:最大空闲连接数。

注意其中的数据库驱动,对应的jar包必须放置到Tomcat目录下的lib目录中。这样服务器才能找得到。

在WEB应用中获取数据库连接的代码:

// 初始化JNDI环境

Context initCtx = new InitialContext();

// 获取JNDI容器

Context envCtx = (Context) initCtx.lookup("java:comp/env");

// 获取数据源

DataSource dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

// 获取数据库连接

dataSource.getConnection();

JNDI是一个对象容器,服务器根据配置文件提供的信息。创建这些对象,并按照指定的名称保存在容器中。WEB应用,无论在何处都可以根据名称获取在JNDI容器中的对象。

三、数据库事务管理:

什么是事务?老方有这样的面试题。事务指逻辑上的一组操作,这组操作要不全部生效,要不全部失效。在控制台中操作事务的命令:

start transaction 开启事务

Rollback 回滚事务

Commit 提交事务

set transction isolation level 设置事务隔离级别

select @@tx_isolation 查询当前事务隔离级别

事务的特性(ACID),这在面试中是比较常见的。老方一再强调,一定要记下来!OK,让我们看一看。

事务的原子性(Automicity),它更像是事务的定义。就是逻辑上的一组操作,不可分割,要么全部生效,要么全部失效。

事务的一致性(Consistency),老方的PPT有中说:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如,银行转账,A-B。A账户中减少100元,B帐户中增加一百元。这看起来比较好理解,但让我有点疑问的是,如果从数据库中删除一个用户呢?难道不用事务处理吗?所以我对这个一致性的理解除了老方说的,还有只要事务处理符合正确的逻辑,就是一致性。

隔离性(Isolation),如果多个用户同时访问数据库,同时访问一张表。这样会造成一些访问错误,所以有了隔离性这一定义。将多个并发事务之间要相互隔离。

持久性(Durability),事务一旦被提交,它对数据库中数据的改变是永久性的,无论其他操作或数据库故障不会对它有任何影响。

在JDBC中使用事务的语句:

// 开启事务

conn.setAutoCommit(false);

// 回滚事务

conn.rollback();

// 提交事务

conn.commit();

// ...

// 设置保存点

sp = conn.setSavepoint();

// 回滚到指定保存点

conn.rollback(sp);

方老师使用了一个经典的案例,来讲解事务处理——银行转账系统!

例,用户A转账10000元给用户B。应该是A账户中减少10000元,B账户中增加10000元。那么在A提交了10000元后,数据库发生问题(比如断电),那B帐户增加10000元的语句还没有执行。使用事务可以很好解决这一问题:

1. 开启事务

2. A帐户减少10000元

3. 中间发生错误,回滚事务

4. B帐户增加10000元

5. 提交事务

OK,在上同这一过程中,如果没有执行到第5步。数据库的内容就不会发生改变。在此有必要解释一下回滚事务,回滚事务在提交事务后执行没有什么效果,回滚事务在提交事务之前执行,会擦除在开启事务之后执行的SQL语句。

上面是针对单一事务进行的处理,在并发事务中会遇到一些问题。设置事务的隔离级别可以很好的解决这一问题。

首先我们来看一下并发事务容易产生的问题:

脏读:

例,用户A账户减少10000元,用户B账户增加了10000元,但A还没有提交事务。此时,B去查询它的账户发现A已经给自己转账了10000元。然后,A回滚了事务。B被A给骗了,这就是脏读,B读到的是未提交的数据。我虽对数据库事务的实现原理不了解(事务是通过日志处理的),我打个比方就更好理解这一原因了。数据库对所有用户维护了一个虚表,在开启事务中,提交事务前对数据的修改,都是修改的虚表,用户查询的也是虚表的内容,当执行了提交事务操作后,将虚表中被修改的内容保存到数据库。实际技术细节就不深入了!

不可重复读:

例,用户A原账户内容为100万元,此时银行将数据显示到电脑屏幕和保存到文件中。银行工作人员在电脑屏幕上看到的是100万元,但此时,用户A向账户里又存了100万元。结果保存到文件的是200万元。到是100万元还是200万元?工作人员有些迷惑。与脏读相反的是,脏读是读取了前一事务未提交的数据,不可重复读读取的是前一事务提交了的事务。注意,不可重复读针对的是某一记录!

虚读:

例,银行要统计A的报表。A的账户中有200万元,屏幕上报表显示的总额是200万元,此时,用户A向账户中又存入了100万元。报表打印出来的总额就是300万元。工作人员一对比,到底哪个是正确的?注意,虚读针对的是整个表。

不可重复读和虚读,有点难理解。这看起来不是什么问题,如果发生这一问题,工作人员就刷新一下表呗!如果工作人员处理的是1万个用户的报表,同时不幸运的是这1万个用户都发生了虚读的问题。那工作人员能受了吗?你可能还会说那就以打印的报表为准呗!问题是,可能屏幕上的那个才是正确的,这样就要重新打印报表。所以为了使问题得以简单的解决,事务的隔离性发挥了它的作用!

处理上边的三种并发事务产生的问题,数据库定义了四种隔离级别:

Serializable:可避免脏读、不可重复读、虚读情况的发生。

Repeatable read:可避免脏读、不可重复读情况的发生。

Read committed:可避免脏读情况发生。

Read uncommitted:最低级别,以上情况均无法保证。

Serializable,最高安全级别。设置了此级别,当一个事务访问了某一表时,此表就会被封死。其他事务对此表的访问就会被挂起,直到上一事务提交后才执行一个事务。OK,这看起来十分容易理解。

Repeatable read,让我再小深入一下,当每个事务线程访问同一表时,数据库针对每个线程维护了一张虚拟表。此时各线程看到的都是原始的数据内容,对表数据的修改相互不发生影响,即使事务被提交了。数据库可能为每个线程维护了一张虚拟表吗?当然不可以,我想这只是为了便于理解。技术细节不深入研究!

Read committed,数据库对每个用户的查询显示的都是原始内容(真实内容)。如果某些用户对此表的事务没有提交就不会影响原始内容。所以其他用户查看到的都是原始内容或提交了的数据内容。

Read uncommitted,这个就不多说了。

今天的内容也就事务的隔离性有些难度吧!一般也不会去用那最高安全级别,这一级别在银行中比较常用。

正如老方所说,是不是感觉越学越简单了!确实如此,我想大家应该也对此有感觉。不知不觉明天又休息了!

加油!

posted @ 2009-12-02 23:20 長城 阅读(752) | 评论 (1)编辑 收藏