一、卸載jdk1.4
由于Redhat Enterprise Linux 5.6 中自帶安裝了jdk1.4.2的,所以在安裝jdk1.6前我把jdk1.4.2的卸了,步驟如下:
1、打開終端輸入 yum remove java
終端顯示 Is this ok [y/N]:
輸入y ,按回車。
終端顯示 Complete! 此時jdk1.4已被卸了。
二、安裝jdk1.6
1.下載:jdk-1_5_0_06-linux-i586-rpm.bin
地址:http://java.sun.com/j2se/1.5.0/download.jsp
2.給文件加上可執行權限
[root@esprit java]# chmod +x jdk-1_5_0_06-linux-i586-rpm.bin
chmod +x jdk-6u31-linux-i586-rpm.bin
3.執行jdk-1_5_0_06-linux-i586-rpm.bin
[root@esprit java]# ./jdk-1_5_0_06-linux-i586-rpm.bin
./jdk-6u31-linux-i586-rpm.bin
執行后生成jdk-6u31-linux-i586.rpm
4.安裝jdk-6u31-linux-i586.rpm
rpm -ivh jdk-6u31-linux-i586.rpm
########################################### [100%]
package jdk-1.6.0_31-fcs is already installed
這里我jdk安裝在/usr/java目錄下
三、配置java環境變量
環境變量配置有三種方法(分別是:修改/etc/profile文件,修改用戶目錄下的.bashrc文件,直接在shell下修改)
這里我只講我用到的修改/etc/profile文件
[root@esprit java]# vi /etc/profile
打開文件后,按 I 鍵,在文件后添加:
JAVA_HOME =/ usr / java / jdk1.6.0_31
PATH = $JAVA_HOME / bin:$PATH
CLASSPATH = .:$JAVA_HOME / lib / tools.jar:$JAVA_HOME / lib / dt.jar:$JAVA_HOME/lib
export JAVA_HOME PATH CLASSPATH
按esc 鍵
輸入:wq 保存退出。
重新登入
四、檢查jdk是否裝好
在命令行輸入: java -version
如果顯示版本信息,表示已經安裝配置成功
五、卸載jdk1.6
輸入 rpm -qa|grep jdk
顯示 jdk-1.6.0_24-fcs
卸載 rpm -e –nodeps jdk-1.6.0_24-fcs
package com.ky.ui.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
Email:
上午11:18:19
*/
public final class ImgRead{
// public final static String getPressImgPath(){
// return ApplicationContext.getRealPath("/template/data/util/shuiyin.gif");
// }
/** *//**
* 把圖片印刷到圖片上
* @param pressImg -- 水印文件
* @param targetImg -- 目標文件
* @param x
* @param y
*/
public final static void pressImage(String pressImg, String targetImg, int x, int y){
try {
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// 水印文件
File _filebiao = new File(pressImg);
Image src_biao = ImageIO.read(_filebiao);
int wideth_biao = src_biao.getWidth(null);
int height_biao = src_biao.getHeight(null);
g.drawImage(src_biao, wideth - wideth_biao - x, height - height_biao -y, wideth_biao,
height_biao, null);
// /
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
e.printStackTrace();
}
}
/** *//**
* 打印文字水印圖片
* @param pressText --文字
* @param targetImg -- 目標圖片
* @param fontName -- 字體名
* @param fontStyle -- 字體樣式
* @param color -- 字體顏色
* @param fontSize -- 字體大小
* @param x -- 偏移量
* @param y
*/
public static void pressText(String pressText, String targetImg, String fontName,int fontStyle, int color, int fontSize, int x, int y){
try{
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// String s=" g.setColor(Color.RED);
g.setFont(new Font(fontName, fontStyle, fontSize));
g.drawString(pressText, wideth - fontSize - x, height - fontSize/2 - y);
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
System.out.println(e);
}
}
public static void main(String[] args){
pressImage("C:/foot_05.gif", "c:/Chart.jpg", 20 ,20);
}
}
// 獲取屏幕的邊界
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
// 獲取底部任務欄高度
int taskBarHeight = screenInsets.bottom;
1、 下載vsftpd
# wget ftp://vsftpd.beasts.org/users/cevans/vsftpd-2.3.2.tar.gz
2、 解壓、安裝vsftpd
# tar xvfz vsftpd-2.3.2.tar.gz
# cd vsftpd-2.3.2
# make
make命令成功執行后,您將看到vsftpd文件獲得當前目錄中創建。
# ls -l vsftpd
3、 安裝 vsftpd d到 Linux
# make install
在make install,確保vsftpd文件復制到/ usr / local / sbin目錄。
# ls -l /usr/local/sbin/vsftpd
4、 復制vsftpd手冊頁到/usr/share/man/man8,man5
# cp vsftpd.8 /usr/share/man/man8/
# cp vsftpd.conf.5 /usr/share/man/man5/
5、 拷貝vsftpd.cond配置文件
# cp vsftpd.conf /etc
6、 設置Anonymouse FTP訪問vsftpd
# mkdir /var/ftp/
# chown root.root /var/ftp
# chmod og-w /var/ftp
ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
在這個階段,如果你試圖登錄與任何其他賬戶(除了匿名,和ftp),它就會失敗,如下所示
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
530 This FTP server is anonymous only.
Login failed.
ftp>
7、 允許LINIX登錄使用vsftp
# cp RedHat/vsftpd.pam /etc/pam.d/ftp
#local_enable=YES
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
切記再每次修改完vsftpd.conf文件之后要重啟一下vsftpd
# ps -ef | grep vsftpd
# kill -9 {vsftpd-pid}
# /usr/local/sbin/vsftpd &
如果還不能登錄成功,那么要關閉系統其他的ftp服務和防火墻
Service xinetd stop
Service iptables stop
摘要: 各種排序算法:冒擇路(入)兮(稀)快歸堆,桶式排序,基數排序 冒泡排序,選擇排序,插入排序,稀爾排序,快速排序,歸并排序,堆排序,桶式排序,基數排序 一、冒泡排序(BubbleSort) 1. 基本思想: 兩兩比較待排序數據元素的大小,發現兩個數據元素的次序相反時即進行交換,直到沒有反序的數據元素為止。 2. 排序過程: 設想被排序的數組R[1..N]垂直豎立,將每個數據元素看作有重量的氣...
閱讀全文
摘要: Java反射機制是Java語言被視為準動態語言的關鍵性質。Java反射機制的核心就是允許在運行時通過Java Reflection APIs來取得已知名字的class類的相關信息,動態地生成此類,并調用其方法或修改其域(甚至是本身聲明為private的域或方法)。
也許你使用Java已經很長時間了,可是幾乎不會用到Java反射機制。你會嗤之以鼻地告訴我,Java反射機制沒啥用...
閱讀全文
1.使用mysqladmin修改mysql密碼
C:\>mysqladmin -udbuser -p password newpassEnter password: oldpass當然用此命令的前提是你把mysql加入了環境變量,如果沒有加入環境變量的話那只能在命令行下cd到mysqladmin所在的目錄下與此那個次命令了!
-----------------------------------------
2.重置root密碼
方法一:
在my.ini的[mysqld]字段加入:
skip-grant-tables
重啟mysql服務,這時的mysql不需要密碼即可登錄數據庫
然后進入mysql
mysql>use mysql;mysql>update user set password=password('新密碼') WHERE User='root'; mysql>flush privileges;運行之后最后去掉my.ini中的skip-grant-tables,重啟mysqld即可。
修改mysql密碼方法二:
不使用修改my.ini重啟服務的方法,通過非服務方式加skip-grant-tables運行mysql來修改mysql密碼
停止mysql服務
打開命令行窗口,在bin目錄下使用mysqld-nt.exe啟動,即在命令行窗口執行: mysqld-nt --skip-grant-tables
然后另外打開一個命令行窗口,登錄mysql,此時無需輸入mysql密碼即可進入。
按以上方法修改好密碼后,關閉命令行運行mysql的那個窗口,此時即關閉了mysql,如果發現mysql仍在運行的話可以結束掉對應進程來關閉。
啟動mysql服務
-----------------------------------------
記住此方法,走遍天下無mysql密碼
先假設一個ftp地址 用戶名 密碼
FTP Server: home4u.at.china.com
User: yepanghuang
Password: abc123
打開windows的開始菜單,執行“運行”命令,在對話框中輸入ftp,按下“確定”按鈕將會切換至DOS窗口,出現命令提示符
ftp>鍵入命令連接FTP服務器
:
ftp> open home4u.at.china.com (回車)
稍等片刻,屏幕提示連接成功:
ftp> connected to home4u.china.com
接下來服務器詢問用戶名和口令,分別輸入yepanghuang和abc123,待認證通過即可。
windows下ftp上傳文件:
比如要把 D:\index.html上傳至服務器的根目錄中,可以鍵入:
ftp> put D:\index.html (回車)
當屏幕提示你已經傳輸完畢,可以鍵入相關命令查看:
ftp> dir (回車)
windows下ftp上傳下載:
假設要把服務器\images目錄中的所有.jpg文件下載至本機中,可以輸入指令:
ftp> cd images(回車) [注:進入\images目錄]
ftp> mget *.jpg
windows下ftp上傳與下載工作完畢,鍵入bye中斷連接。
ftp> bye(回車)
下面是一些常用的FTP命令:
1. open:與服務器相連接;
2. send(put):上傳文件;
3. get:下載文件;
4. mget:下載多個文件;
5. cd:切換目錄;
6. dir:查看當前目錄下的文件;
7. del:刪除文件;
8. bye:中斷與服務器的連接。
如果想了解更多,可以鍵入
ftp> help (回車)
查看命令集:
ascii: 設定以ASCII方式傳送文件(缺省值)
bell: 每完成一次文件傳送,報警提示
binary: 設定以二進制方式傳送文件
bye: 終止主機FTP進程,并退出FTP管理方式
case: 當為ON時,用MGET命令拷貝的文件名到本地機器中,全部轉換為小寫字母
cd: 同UNIX的CD命令
cdup: 返回上一級目錄
chmod: 改變遠端主機的文件權限
close: 終止遠端的FTP進程,返回到FTP命令狀態,所有的宏定義都被刪除
delete: 刪除遠端主機中的文件
dir [remote-directory] [local-file]: 列出當前遠端主機目錄中的文件.如果有本地文件,就將結果寫至本地文件
get [remote-file] [local-file]: 從遠端主機中傳送至本地主機中
help [command]: 輸出命令的解釋
lcd: 改變當前本地主機的工作目錄,如果缺省,就轉到當前用戶的HOME目錄
ls [remote-directory] [local-file]: 同DIR
其實在網上也看到過一些文章,介紹如何讓java程序以window服務的方式啟動。
今天有空,就想用c寫一個window服務,在服務啟動時來啟動一個java程序。
因為在c方面,我十足菜鳥,先到網上搜索了一下關于如何用c寫出windows服務,找到一篇介紹的相當詳細,參照介紹寫了一個window服務。
測試的過程中遇到一個問題,由于我的java程序啟動時會在系統托盤顯示一個小圖標,但通過c寫的window服務啟運這個java程序后,系統托盤里沒有顯示小圖標。
再搜索,原來:
windows服務程序默認是工作于WinLogon桌面的,服務啟動時不會顯示GUI界面.可以打開控制面板->服務,查看服務的屬性->[登錄]-[允許服務與桌面交互],打上鉤后,系統托盤就能顯示在任務欄。
用C寫一個windows服務:
來源:http://www.vckbase.com/document/viewdoc/?id=1474
摘要
Windows 服務被設計用于需要在后臺運行的應用程序以及實現沒有用戶交互的任務。為了學習這種控制臺應用程序的基礎知識,C(不是C++)是最佳選擇。本文將建立并實現一個簡單的服務程序,其功能是查詢系統中可用物理內存數量,然后將結果寫入一個文本文件。最后,你可以用所學知識編寫自己的 Windows 服務。
當初我寫第一個 NT 服務時,我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 寫的文章:“Creating a Simple Win32 Service in C++”,這篇文章附帶一個 C++ 例子。雖然這篇文章很好地解釋了服務的開發過程,但是,我仍然感覺缺少我需要的重要信息。我想理解通過什么框架,調用什么函數,以及何時調用,但 C++ 在這方面沒有讓我輕松多少。面向對象的方法固然方便,但由于用類對底層 Win32 函數調用進行了封裝,它不利于學習服務程序的基本知識。這就是為什么我覺得 C 更加適合于編寫初級服務程序或者實現簡單后臺任務的服務。在你對服務程序有了充分透徹的理解之后,用 C++ 編寫才能游刃有余。當我離開原來的工作崗位,不得不向另一個人轉移我的知識的時候,利用我用 C 所寫的例子就非常容易解釋 NT 服務之所以然。
服務是一個運行在后臺并實現勿需用戶交互的任務的控制臺程序。Windows NT/2000/XP 操作系統提供為服務程序提供專門的支持。人們可以用服務控制面板來配置安裝好的服務程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服務”(或在“開始”|“運行”對話框中輸入 services.msc /s——譯者注)。可以將服務配置成操作系統啟動時自動啟動,這樣你就不必每次再重啟系統后還要手動啟動服務。
本文將首先解釋如何創建一個定期查詢可用物理內存并將結果寫入某個文本文件的服務。然后指導你完成生成,安裝和實現服務的整個過程。
第一步:主函數和全局定義
首先,包含所需的頭文件。例子要調用 Win32 函數(windows.h)和磁盤文件寫入(stdio.h):
#include <windows.h>
#include <stdio.h>
接著,定義兩個常量:
#define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"
SLEEP_TIME 指定兩次連續查詢可用內存之間的毫秒間隔。在第二步中編寫服務工作循環的時候要使用該常量。
LOGFILE 定義日志文件的路徑,你將會用 WriteToLog 函數將內存查詢的結果輸出到該文件,WriteToLog 函數定義如下:
int WriteToLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
聲明幾個全局變量,以便在程序的多個函數之間共享它們值。此外,做一個函數的前向定義:
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
現在,準備工作已經就緒,你可以開始編碼了。服務程序控制臺程序的一個子集。因此,開始你可以定義一個 main 函數,它是程序的入口點。對于服務程序來說,main 的代碼令人驚訝地簡短,因為它只創建分派表并啟動控制分派機。
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// 啟動服務的控制分派機線程
StartServiceCtrlDispatcher(ServiceTable);
}
一個程序可能包含若干個服務。每一個服務都必須列于專門的分派表中(為此該程序定義了一個 ServiceTable 結構數組)。這個表中的每一項都要在 SERVICE_TABLE_ENTRY 結構之中。它有兩個域:
- lpServiceName: 指向表示服務名稱字符串的指針;當定義了多個服務時,那么這個域必須指定;
- lpServiceProc: 指向服務主函數的指針(服務入口點);
分派表的最后一項必須是服務名和服務主函數域的 NULL 指針,文本例子程序中只宿主一個服務,所以服務名的定義是可選的。
服務控制管理器(SCM:Services Control Manager)是一個管理系統所有服務的進程。當 SCM 啟動某個服務時,它等待某個進程的主線程來調用 StartServiceCtrlDispatcher 函數。將分派表傳遞給 StartServiceCtrlDispatcher。這將把調用進程的主線程轉換為控制分派器。該分派器啟動一個新線程,該線程運行分派表中每個服務的 ServiceMain 函數(本文例子中只有一個服務)分派器還監視程序中所有服務的執行情況。然后分派器將控制請求從 SCM 傳給服務。
注意:如果 StartServiceCtrlDispatcher 函數30秒沒有被調用,便會報錯,為了避免這種情況,我們必須在 ServiceMain 函數中(參見本文例子)或在非主函數的單獨線程中初始化服務分派表。本文所描述的服務不需要防范這樣的情況。
分派表中所有的服務執行完之后(例如,用戶通過“服務”控制面板程序停止它們),或者發生錯誤時。StartServiceCtrlDispatcher 調用返回。然后主進程終止。
第二步:ServiceMain 函數
Listing 1 展示了 ServiceMain 的代碼。該函數是服務的入口點。它運行在一個單獨的線程當中,這個線程是由控制分派器創建的。ServiceMain 應該盡可能早早為服務注冊控制處理器。這要通過調用 RegisterServiceCtrlHadler 函數來實現。你要將兩個參數傳遞給此函數:服務名和指向 ControlHandlerfunction 的指針。
它指示控制分派器調用 ControlHandler 函數處理 SCM 控制請求。注冊完控制處理器之后,獲得狀態句柄(hStatus)。通過調用 SetServiceStatus 函數,用 hStatus 向 SCM 報告服務的狀態。
Listing 1 展示了如何指定服務特征和其當前狀態來初始化 ServiceStatus 結構,ServiceStatus 結構的每個域都有其用途:
- dwServiceType:指示服務類型,創建 Win32 服務。賦值 SERVICE_WIN32;
- dwCurrentState:指定服務的當前狀態。因為服務的初始化在這里沒有完成,所以這里的狀態為 SERVICE_START_PENDING;
- dwControlsAccepted:這個域通知 SCM 服務接受哪個域。本文例子是允許 STOP 和 SHUTDOWN 請求。處理控制請求將在第三步討論;
- dwWin32ExitCode 和 dwServiceSpecificExitCode:這兩個域在你終止服務并報告退出細節時很有用。初始化服務時并不退出,因此,它們的值為 0;
- dwCheckPoint 和 dwWaitHint:這兩個域表示初始化某個服務進程時要30秒以上。本文例子服務的初始化過程很短,所以這兩個域的值都為 0。
調用 SetServiceStatus 函數向 SCM 報告服務的狀態時。要提供 hStatus 句柄和 ServiceStatus 結構。注意 ServiceStatus 一個全局變量,所以你可以跨多個函數使用它。ServiceMain 函數中,你給結構的幾個域賦值,它們在服務運行的整個過程中都保持不變,比如:dwServiceType。
在報告了服務狀態之后,你可以調用 InitService 函數來完成初始化。這個函數只是添加一個說明性字符串到日志文件。如下面代碼所示:
// 服務初始化
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
在 ServiceMain 中,檢查 InitService 函數的返回值。如果初始化有錯(因為有可能寫日志文件失?。?,則將服務狀態置為終止并退出 ServiceMain:
error = InitService();
if (error)
{
// 初始化失敗,終止服務
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
// 退出 ServiceMain
return;
}
如果初始化成功,則向 SCM 報告狀態:
// 向 SCM 報告運行狀態
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
接著,啟動工作循環。每五秒鐘查詢一個可用物理內存并將結果寫入日志文件。
如 Listing 1 所示,循環一直到服務的狀態為 SERVICE_RUNNING 或日志文件寫入出錯為止。狀態可能在 ControlHandler 函數響應 SCM 控制請求時修改。
第三步:處理控制請求
在第二步中,你用 ServiceMain 函數注冊了控制處理器函數??刂铺幚砥髋c處理各種 Windows 消息的窗口回調函數非常類似。它檢查 SCM 發送了什么請求并采取相應行動。
每次你調用 SetServiceStatus 函數的時候,必須指定服務接收 STOP 和 SHUTDOWN 請求。Listing 2 示范了如何在 ControlHandler 函數中處理它們。
STOP 請求是 SCM 終止服務的時候發送的。例如,如果用戶在“服務”控制面板中手動終止服務。SHUTDOWN 請求是關閉機器時,由 SCM 發送給所有運行中服務的請求。兩種情況的處理方式相同:
- 寫日志文件,監視停止;
- 向 SCM 報告 SERVICE_STOPPED 狀態;
由于 ServiceStatus 結構對于整個程序而言為全局量,ServiceStatus 中的工作循環在當前狀態改變或服務終止后停止。其它的控制請求如:PAUSE 和 CONTINUE 在本文的例子沒有處理。
控制處理器函數必須報告服務狀態,即便 SCM 每次發送控制請求的時候狀態保持相同。因此,不管響應什么請求,都要調用 SetServiceStatus。

圖一 顯示 MemoryStatus 服務的服務控制面板
第四步:安裝和配置服務
程序編好了,將之編譯成 exe 文件。本文例子創建的文件叫 MemoryStatus.exe,將它拷貝到 C:\MyServices 文件夾。為了在機器上安裝這個服務,需要用 SC.EXE 可執行文件,它是 Win32 Platform SDK 中附帶的一個工具。(譯者注:Visaul Studio .NET 2003 IDE 環境中也有這個工具,具體存放位置在:C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt)。使用這個實用工具可以安裝和移除服務。其它控制操作將通過服務控制面板來完成。以下是用命令行安裝 MemoryStatus 服務的方法:
sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe
發出此創建命令。指定服務名和二進制文件的路徑(注意 binpath= 和路徑之間的那個空格)。安裝成功后,便可以用服務控制面板來控制這個服務(參見圖一)。用控制面板的工具欄啟動和終止這個服務。

圖二 MemoryStatus 服務的屬性窗口
MemoryStatus 的啟動類型是手動,也就是說根據需要來啟動這個服務。右鍵單擊該服務,然后選擇上下文菜單中的“屬性”菜單項,此時顯示該服務的屬性窗口。在這里可以修改啟動類型以及其它設置。你還可以從“常規”標簽中啟動/停止服務。以下是從系統中移除服務的方法:
sc delete MemoryStatus
指定 “delete” 選項和服務名。此服務將被標記為刪除,下次西通重啟后,該服務將被完全移除。
第五步:測試服務
從服務控制面板啟動 MemoryStatus 服務。如果初始化不出錯,表示啟動成功。過一會兒將服務停止。檢查一下 C:\MyServices 文件夾中 memstatus.txt 文件的服務輸出。在我的機器上輸出是這樣的:
Monitoring started.
273469440
273379328
273133568
273084416
Monitoring stopped.
為了測試 MemoryStatus 服務在出錯情況下的行為,可以將 memstatus.txt 文件設置成只讀。這樣一來,服務應該無法啟動。
去掉只讀屬性,啟動服務,在將文件設成只讀。服務將停止執行,因為此時日志文件寫入失敗。如果你更新服務控制面板的內容,會發現服務狀態是已經停止。
開發更大更好的服務程序
理解 Win32 服務的基本概念,使你能更好地用 C++ 來設計包裝類。包裝類隱藏了對底層 Win32 函數的調用并提供了一種舒適的通用接口。修改 MemoryStatus 程序代碼,創建滿足自己需要的服務!為了實現比本文例子所示范的更復雜的任務,你可以創建多線程的服務,將作業劃分成幾個工作者線程并從 ServiceMain 函數中監視它們的執行。
最近的機器內存又爆滿了,除了新增機器內存外,還應該好好review一下我們的代碼,有很多代碼編寫過于隨意化,這些不好的習慣或對程序語言的不了解是應該好好打壓打壓了。
下面是參考網絡資源總結的一些在Java編程中盡可能要做到的一些地方。
1. 盡量在合適的場合使用單例
使用單例可以減輕加載的負擔,縮短加載的時間,提高加載的效率,但并不是所有地方都適用于單例,簡單來說,單例主要適用于以下三個方面:
第一,控制資源的使用,通過線程同步來控制資源的并發訪問;
第二,控制實例的產生,以達到節約資源的目的;
第三,控制數據共享,在不建立直接關聯的條件下,讓多個不相關的進程或線程之間實現通信。
2. 盡量避免隨意使用靜態變量
要知道,當某個對象被定義為stataic變量所引用,那么gc通常是不會回收這個對象所占有的內存,如
- public class A{
- static B b = new B();
- }
public class A{ static B b = new B(); }
此時靜態變量b的生命周期與A類同步,如果A類不會卸載,那么b對象會常駐內存,直到程序終止。
3. 盡量避免過多過常的創建Java對象
盡量避免在經常調用的方法,循環中new對象,由于系統不僅要花費時間來創建對象,而且還要花時間對這些對象進行垃圾回收和處理,在我們可以控制的范圍內,最大限度的重用對象,最好能用基本的數據類型或數組來替代對象。
4. 盡量使用final修飾符
帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String。為String類指定final防止了使用者覆蓋length()方法。另外,如果一個類是final的,則該類所有方法都是final的。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使性能平均提高50%。
5. 盡量使用局部變量
調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。
6. 盡量處理好包裝類型和基本類型兩者的使用場所
雖然包裝類型和基本類型在使用過程中是可以相互轉換,但它們兩者所產生的內存區域是完全不同的,基本類型數據產生和處理都在棧中處理,包裝類型是對象,是在堆中產生實例。
在集合類對象,有對象方面需要的處理適用包裝類型,其他的處理提倡使用基本類型。
7. 慎用synchronized,盡量減小synchronize的方法
都知道,實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。synchronize方法被調用時,直接會把當前對象鎖 了,在方法執行完之前其他線程無法調用當前對象的其他方法。所以synchronize的方法盡量小,并且應盡量使用方法同步代替代碼塊同步。
8. 盡量使用StringBuilder和StringBuffer進行字符串連接
這個就不多講了。
9. 盡量不要使用finalize方法
實際上,將資源清理放在finalize方法中完成是非常不好的選擇,由于GC的工作量很大,尤其是回收Young代內存時,大都會引起應用程序暫停,所以再選擇使用finalize方法進行資源清理,會導致GC負擔更大,程序運行效率更差。
10. 盡量使用基本數據類型代替對象
String str = "hello";
上面這種方式會創建一個“hello”字符串,而且JVM的字符緩存池還會緩存這個字符串;
String str = new String("hello");
此時程序除創建字符串外,str所引用的String對象底層還包含一個char[]數組,這個char[]數組依次存放了h,e,l,l,o
11. 單線程應盡量使用HashMap、ArrayList
HashTable、Vector等使用了同步機制,降低了性能。
12. 盡量合理的創建HashMap
當你要創建一個比較大的hashMap時,充分利用另一個構造函數
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次進行了hash重構,擴容是一件很耗費性能的事,在默認中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能準確的估計你所需要的最佳大小,同樣的Hashtable,Vectors也是一樣的道理。
13. 盡量減少對變量的重復計算
如
for(int i=0;i<list.size();i++)
應該改為
for(int i=0,len=list.size();i<len;i++)
并且在循環中應該避免使用復雜的表達式,在循環中,循環條件會被反復計算,如果不使用復雜表達式,而使循環條件值不變的話,程序將會運行的更快。
14. 盡量避免不必要的創建
如
A a = new A();
if(i==1){list.add(a);}
應該改為
if(i==1){
A a = new A();
15. 盡量在finally塊中釋放資源
程序中使用到的資源應當被釋放,以避免資源泄漏。這最好在finally塊中去做。不管程序執行的結果如何,finally塊總是會執行的,以確保資源的正確關閉。
16. 盡量使用移位來代替'a/b'的操作
"/"是一個代價很高的操作,使用移位的操作將會更快和更有效
如
int num = a / 4;
int num = a / 8;
應該改為
int num = a >> 2;
int num = a >> 3;
但注意的是使用移位應添加注釋,因為移位操作不直觀,比較難理解
17.盡量使用移位來代替'a*b'的操作
同樣的,對于'*'操作,使用移位的操作將會更快和更有效
如
int num = a * 4;
int num = a * 8;
應該改為
int num = a << 2;
18. 盡量確定StringBuffer的容量
StringBuffer 的構造器會創建一個默認大小(通常是16)的字符數組。在使用中,如果超出這個大小,就會重新分配內存,創建一個更大的數組,并將原先的數組復制過來,再 丟棄舊的數組。在大多數情況下,你可以在創建 StringBuffer的時候指定大小,這樣就避免了在容量不夠的時候自動增長,以提高性能。
如:StringBuffer buffer = new StringBuffer(1000);
19. 盡量早釋放無用對象的引用
大部分時,方法局部引用變量所引用的對象 會隨著方法結束而變成垃圾,因此,大部分時候程序無需將局部,引用變量顯式設為null。
例如:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- }
Public void test(){ Object obj = new Object(); …… Obj=null; }
上面這個就沒必要了,隨著方法test()的執行完成,程序中obj引用變量的作用域就結束了。但是如果是改成下面:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- //執行耗時,耗內存操作;或調用耗時,耗內存的方法
- ……
- }
Public void test(){ Object obj = new Object(); …… Obj=null; //執行耗時,耗內存操作;或調用耗時,耗內存的方法 …… }
這時候就有必要將obj賦值為null,可以盡早的釋放對Object對象的引用。
20. 盡量避免使用二維數組
二維數據占用的內存空間比一維數組多得多,大概10倍以上。
21. 盡量避免使用split
除非是必須的,否則應該避免使用split,split由于支持正則表達式,所以效率比較低,如果是頻繁的幾十,幾百萬的調用將會耗費大量資源,如果確實需 要頻繁的調用split,可以考慮使用apache的StringUtils.split(string,char),頻繁split的可以緩存結果。
22. ArrayList & LinkedList
一 個是線性表,一個是鏈表,一句話,隨機查詢盡量使用ArrayList,ArrayList優于LinkedList,LinkedList還要移動指 針,添加刪除的操作LinkedList優于ArrayList,ArrayList還要移動數據,不過這是理論性分析,事實未必如此,重要的是理解好2 者得數據結構,對癥下藥。
23. 盡量使用System.arraycopy ()代替通過來循環復制數組
System.arraycopy() 要比通過循環來復制數組快的多
24. 盡量緩存經常使用的對象
盡可能將經常使用的對象進行緩存,可以使用數組,或HashMap的容器來進行緩存,但這種方式可能導致系統占用過多的緩存,性能下降,推薦可以使用一些第三方的開源工具,如EhCache,Oscache進行緩存,他們基本都實現了FIFO/FLU等緩存算法。
25. 盡量避免非常大的內存分配
有時候問題不是由當時的堆狀態造成的,而是因為分配失敗造成的。分配的內存塊都必須是連續的,而隨著堆越來越滿,找到較大的連續塊越來越困難。
26. 慎用異常
當創建一個異常時,需要收集一個棧跟蹤(stack track),這個棧跟蹤用于描述異常是在何處創建的。構建這些棧跟蹤時需要為運行時棧做一份快照,正是這一部分開銷很大。當需要創建一個 Exception 時,JVM 不得不說:先別動,我想就您現在的樣子存一份快照,所以暫時停止入棧和出棧操作。棧跟蹤不只包含運行時棧中的一兩個元素,而是包含這個棧中的每一個元素。
如 果您創建一個 Exception ,就得付出代價。好在捕獲異常開銷不大,因此可以使用 try-catch 將核心內容包起來。從技術上講,您甚至可以隨意地拋出異常,而不用花費很大的代價。招致性能損失的并不是 throw 操作——盡管在沒有預先創建異常的情況下就拋出異常是有點不尋常。真正要花代價的是創建異常。幸運的是,好的編程習慣已教會我們,不應該不管三七二十一就 拋出異常。異常是為異常的情況而設計的,使用時也應該牢記這一原則。
相關回復:
xuanyuan 寫道
7.慎用synchronized,盡量減小synchronize的方法
re:同意,不過文中有個地方說錯了,使用synchronized關鍵字并不一定都是鎖定當前對象的,要看具體的鎖是什么。如果是在方法上加的synchronized,則是以對象本身為鎖的,如果是靜態方法則鎖的粒度是類。
---------------
9.盡量不要使用finalize方法
re:同意,其實不推薦用finalize方法的根本原因在于,JVM的規范并不保證何時執行該方法,所以用這個方法來釋放資源很不合適,有可能造成長時間資源得不到釋放。
---------------
16.盡量使用移位來代替'a/b'的操作;17.盡量使用移位來代替'a*b'的操作
re:個人不太同意這兩條。這樣做確實有更好的性能,但是卻犧牲了可讀性。這兩個操作符對很多程序員來說并不直觀。我認為在如今硬件價格不那么昂貴的情況下,略微犧牲一些性能,換來更好的可讀性和可維護性是好的選擇。
wuzhengju 寫道
19.盡量早釋放無用對象的引用
大部分時,方法局部引用變量所引用的對象 會隨著方法結束而變成垃圾,因此,大部分時候程序無需將局部,引用變量顯式設為null。
例如:
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面這個就沒必要了,隨著方法test()的執行完成,程序中obj引用變量的作用域就結束了。但是如果是改成下面:
Public void test(){
Object obj = new Object();
……
Obj=null;
//執行耗時,耗內存操作;或調用耗時,耗內存的方法
……
}
如果Object obj = new Object(); 如果這對象并不是大對象,這有必要嗎?Obj=null;只是告訴jvm這個對象已經成為垃圾,至于什么時候回收,還不能確定! 這可讀性也不好!
下面的代碼片段是由經過驗證的程序修改而來。觀察這些代碼片段你會發現,跟以前的版本相比,在Java7里,文件相關的操作變得簡單的多了。通過使用新的Files類里提供的各種方法,你可以只用一行代碼就能完成下列的文件操作:
這篇文件是以你對Java7里提供的新的Path類很熟悉為前提,如果你不熟悉這個類,這里就簡單說一句,Path是文件系統里對位置的一個邏輯概念,例如c:\ 和../foobar.txt都是Path。
創建和刪除文件
下面的代碼片段向你展示的是用 Files.createFile (Path target) 方法創建文件的基本用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Path file = Files.createFile (target);
很多時候,出于安全的原因,你可能希望在創建的文件上設置一下屬性,例如:是否可讀/可寫/寫執行。這些屬性依賴于文件系統的種類,你需要使用跟文件系統相應的權限輔助類來完成這種操作。例如,PosixFilePermission和PosixFilePermissions為POSIX文件系統設計的。下面的是在POSIX文件系統上的文件設置讀寫權限的用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Set<PosixFilePermission> perms = PosixFilePermissions.fromString ("rw-rw-rw-");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute (perms);
Files.createFile (target, attr);
這個java.nio.file.attribute包里提供了很多關于FilePermission的類。
警告當創建一個帶有權限屬性的文件時,請注意包含這個文件的文件夾是否有權限的強制約束。例如,你會發現,由于這些限制,盡管你給創建的文件指定了rw-rw-rw權限,實際創建的結果卻是rw-r–r–。
刪除文件更簡單,使用Files.delete (Path)這個方法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.delete (target);
拷貝和移動文件
下面的代碼向你展示的是使用Files.copy (Path source, Path target)方法做文件拷貝的基本用法。
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.copy (source, target);
經常的,在拷貝文件的過程中你可能希望指定一些操作設置。在Java7里,你可以通過使用StandardCopyOption enum來設置這些屬性。下面看一個例子。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
- Files.copy (source, target, REPLACE_EXISTING);
拷貝操作時可以使用的屬性還包括COPY_ATTRIBUTES (保留文件屬性) 和ATOMIC_MOVE (確保移動事務操作的成功,否則進行回滾)。
移動文件的操作跟拷貝很相似,使用Files.move (Path source, Path target)方法。
同樣,你也可以指定移動操作的屬性,使用Files.move (Path source, Path target, CopyOptions...) 方法里的參數來設置。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.move (source, target, REPLACE_EXISTING,COPY_ATTRIBUTES);
可以看出,新的用于文件操作的NIO.2 API 非常便于使用。
眾所周知,隨機數是任何一種編程語言最基本的特征之一。而生成隨機數的基本方式也是相同的:產生一個0到1之間的隨機數??此坪唵?,但有時我們也會忽略了一些有趣的功能。
我們從書本上學到什么?
最明顯的,也是直觀的方式,在Java中生成隨機數只要簡單的調用:
- java.lang.Math.random()
在所有其他語言中,生成隨機數就像是使用Math工具類,如abs, pow, floor, sqrt和其他數學函數。大多數人通過書籍、教程和課程來了解這個類。一個簡單的例子:從0.0到1.0之間可以生成一個雙精度浮點數。那么通過上面的信息,開發人員要產生0.0和10.0之間的雙精度浮點數會這樣來寫:
- Math.random() * 10
而產生0和10之間的整數,則會寫成:
- Math.round(Math.random() * 10)
進階
通過閱讀Math.random()的源碼,或者干脆利用IDE的自動完成功能,開發人員可以很容易發現,java.lang.Math.random()使用一個內部的隨機生成對象 - 一個很強大的對象可以靈活的隨機產生:布爾值、所有數字類型,甚至是高斯分布。例如:
- new java.util.Random().nextInt(10)
它有一個缺點,就是它是一個對象。它的方法必須是通過一個實例來調用,這意味著必須先調用它的構造函數。如果在內存充足的情況下,像上面的表達式是可以接受的;但內存不足時,就會帶來問題。
一個簡單的解決方案,可以避免每次需要生成一個隨機數時創建一個新實例,那就是使用一個靜態類。猜你可能想到了java.lang.Math,很好,我們就是改良java.lang.Math的初始化。雖然這個工程量低,但你也要做一些簡單的單元測試來確保其不會出錯。
假設程序需要生成一個隨機數來存儲,問題就又來了。比如有時需要操作或保護種子(seed),一個內部數用來存儲狀態和計算下一個隨機數。在這些特殊情況下,共用隨機生成對象是不合適的。
并發
在Java EE多線程應用程序的環境中,隨機生成實例對象仍然可以被存儲在類或其他實現類,作為一個靜態屬性。幸運的是,java.util.Random是線程安全的,所以不存在多個線程調用會破壞種子(seed)的風險。
另一個值得考慮的是多線程java.lang.ThreadLocal的實例。偷懶的做法是通過Java本身API實現單一實例,當然你也可以確保每一個線程都有自己的一個實例對象。
雖然Java沒有提供一個很好的方法來管理java.util.Random的單一實例。但是,期待已久的Java 7提供了一種新的方式來產生隨機數:
- java.util.concurrent.ThreadLocalRandom.current().nextInt(10)
這個新的API綜合了其他兩種方法的優點:單一實例/靜態訪問,就像Math.random()一樣靈活。ThreadLocalRandom也比其他任何處理高并發的方法要更快。
經驗
Chris Marasti-Georg 指出:
- Math.round(Math.random() * 10)
使分布不平衡,例如:0.0 - 0.499999將四舍五入為0,而0.5至1.499999將四舍五入為1。那么如何使用舊式語法來實現正確的均衡分布,如下:
- Math.floor(Math.random() * 11)
幸運的是,如果我們使用java.util.Random或java.util.concurrent.ThreadLocalRandom就不用擔心上述問題了。
Java實戰項目里面介紹了一些不正確使用java.util.Random API的危害。這個教訓告訴我們不要使用:
- Math.abs(rnd.nextInt())%n
而使用:
- rnd.nextInt(n)
package com.wss;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class GPS_GNSS_XML_Color {
//刪除節點時傳入的參數
private static String deleteNumber;
//修改節點時傳入的參數
private static String updateNumber;
//讀取傳入的路徑,返回一個document對象
public static Document loadInit(String filePath){
Document document = null;
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(new File(filePath));
document.normalize();
return document;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
/**
* 刪除制定的xml
* @param filePath
* @return
*/
public static boolean deleteXML(String filePath){
deleteNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
Document document = loadInit(filePath);
try{
NodeList nodeList = document.getElementsByTagName("color");
for(int i=0; i<nodeList.getLength(); i++){
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
//刪除節點時傳入的參數
if(number_.equals(deleteNumber)){
Node node = nodeList.item(i);
node.getParentNode().removeChild(node);
saveXML(document, filePath);
}
}
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 修改制定的xml
* @param filePath
* @return
*/
public static boolean updateXML(String filePath){
updateNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
//讀取傳入的路徑,返回一個document對象
Document document = loadInit(filePath);
try{
//獲取葉節點
NodeList nodeList = document.getElementsByTagName("color");
//遍歷葉節點
for(int i=0; i<nodeList.getLength(); i++){
String number = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
//修改節點時傳入的參數
if(number.equals(updateNumber)){
document.getElementsByTagName("colorValue").item(i).getFirstChild().setNodeValue("black");
document.getElementsByTagName("minValue").item(i).getFirstChild().setNodeValue("2222");
document.getElementsByTagName("maxValue").item(i).getFirstChild().setNodeValue("22222");
System.out.println();
}
}
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 添加節點
* @param filePath
* @return
*/
public static boolean addXML(String filePath){
try{
//讀取傳入的路徑,返回一個document對象
Document document = loadInit(filePath);
//創建葉節點
Element eltColor = document.createElement("color");
Element eltNumber = document.createElement("number");//創建葉節點的第一個元素
Element eltColorValue = document.createElement("colorValue");//創建葉節點的第二個元素
Element eltMinValue = document.createElement("minValue");//創建葉節點的第三個元素
Element eltMaxValue = document.createElement("maxValue");//創建葉節點的第四個元素
Text number_ = document.createTextNode(UUID.randomUUID().toString());//創建葉節點的第一個元素下的文本節點
eltNumber.appendChild(number_);//把該文本節點加入到葉節點的第一個元素里面
Text colorValue_ = document.createTextNode("colorValue");//創建葉節點的第二個元素下的文本節點
eltColorValue.appendChild(colorValue_);//把該文本節點加入到葉節點的第二個元素里面
Text minValue_ = document.createTextNode("100");//創建葉節點的第三個元素下的文本節點
eltMinValue.appendChild(minValue_);//把該文本節點加入到葉節點的第三個元素里面
Text maxValue_ = document.createTextNode("200");//創建葉節點的第四個元素下的文本節點
eltMaxValue.appendChild(maxValue_);//把該文本節點加入到葉節點的第四個元素里面
//把葉節點下的元素加入到葉節點下
eltColor.appendChild(eltNumber);
eltColor.appendChild(eltColorValue);
eltColor.appendChild(eltMinValue);
eltColor.appendChild(eltMaxValue);
//獲取根節點
Element eltRoot = document.getDocumentElement();
//把葉節點加入到根節點下
eltRoot.appendChild(eltColor);
//更新修改后的源文件
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 把修改后的document寫進源文件(更新源文件)
* @param document
* @param filePath
* @return
*/
public static boolean saveXML(Document document, String filePath){
try{
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 獲取xml文件的所有記錄
* @param filePath
* @return
*/
public static List<ColorValue> selectXML(String filePath){
List<ColorValue> colorValueList = new ArrayList<ColorValue>();
try{
//讀取傳入的路徑,返回一個document對象
Document document = loadInit(filePath);
//獲取葉節點
NodeList nodeList = document.getElementsByTagName("color");
//遍歷葉節點
for(int i=0; i<nodeList.getLength(); i++){
ColorValue colorValue = new ColorValue();
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue_ = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue_ = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue_ = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
colorValue.setNumber(number_);
colorValue.setColorValue(colorValue_);
colorValue.setMinValue(minValue_);
colorValue.setMaxValue(maxValue_);
colorValueList.add(colorValue);
}
return colorValueList;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
}
package com.wss;
public class ColorValue {
private String number;
private String colorValue;
private Double minValue;
private Double maxValue;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getColorValue() {
return colorValue;
}
public void setColorValue(String colorValue) {
this.colorValue = colorValue;
}
public Double getMinValue() {
return minValue;
}
public void setMinValue(Double minValue) {
this.minValue = minValue;
}
public Double getMaxValue() {
return maxValue;
}
public void setMaxValue(Double maxValue) {
this.maxValue = maxValue;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Colors>
<color>
<number>7007b384-fab3-4779-9171-229d0664b6b5</number>
<colorValue>black</colorValue>
<minValue>2222</minValue>
<maxValue>22222</maxValue>
</color>
<color>
<number>421f481e-790c-41be-91e3-27d215b73ce2</number>
<colorValue>colorValue</colorValue>
<minValue>100</minValue>
<maxValue>200</maxValue>
</color>
</Colors>
// 寫文件UTF-8格式 寫一行
public static void writerTxtFile(String filePath, String text) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
fs.write(text + "\n");
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 寫文件UTF-8格式 寫一行
public static void writerStringBuffer(String filePath, StringBuffer text) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
fs.write(text + "\n");
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 寫文件
public static void writerTxtFile(String filePath, List<String> list) {
OutputStreamWriter fs;
try {
fs = new OutputStreamWriter(new FileOutputStream(filePath, true), "UTF-8");
for(int i=0; i<list.size(); i++){
fs.write(list.get(i) + "\n");
}
fs.flush();
fs.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
package dateapp;
import java.util.Date;
import java.util.Calendar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.JSpinner.NumberEditor;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.swing.border.LineBorder;
public class DateChooseJButton extends JButton {
private DateChooser dateChooser = null;
private String preLabel = "";
public DateChooseJButton() {
this(getNowDate());
}
public DateChooseJButton(SimpleDateFormat df, String dateString) {
this();
setText(df, dateString);
}
public DateChooseJButton(Date date) {
this("", date);
}
public DateChooseJButton(String preLabel, Date date) {
if (preLabel != null)
this.preLabel = preLabel;
setDate(date);
setBorder(null);
setCursor(new Cursor(Cursor.HAND_CURSOR));
super.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (dateChooser == null)
dateChooser = new DateChooser();
Point p = getLocationOnScreen();
p.y = p.y + 30;
dateChooser.showDateChooser(p);
}
});
}
private static Date getNowDate() {
return Calendar.getInstance().getTime();
}
private static SimpleDateFormat getDefaultDateFormat() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
// 覆蓋父類的方法
public void setText(String s) {
Date date;
try {
date = getDefaultDateFormat().parse(s);
} catch (ParseException e) {
date = getNowDate();
}
setDate(date);
}
public void setText(SimpleDateFormat df, String s) {
Date date;
try {
date = df.parse(s);
} catch (ParseException e) {
date = getNowDate();
}
setDate(date);
}
public void setDate(Date date) {
super.setText(preLabel + getDefaultDateFormat().format(date));
}
public Date getDate() {
String dateString = getText().substring(preLabel.length());
try {
return getDefaultDateFormat().parse(dateString);
} catch (ParseException e) {
return getNowDate();
}
}
// 覆蓋父類的方法使之無效
public void addActionListener(ActionListener listener) {
}
private class DateChooser extends JPanel implements ActionListener,
ChangeListener {
int startYear = 1980; // 默認【最小】顯示年份
int lastYear = 2050; // 默認【最大】顯示年份
int width = 400; // 界面寬度
int height = 200; // 界面高度
Color backGroundColor = Color.gray; // 底色
// 月歷表格配色----------------//
Color palletTableColor = Color.white; // 日歷表底色
Color todayBackColor = Color.orange; // 今天背景色
Color weekFontColor = Color.blue; // 星期文字色
Color dateFontColor = Color.black; // 日期文字色
Color weekendFontColor = Color.red; // 周末文字色
// 控制條配色------------------//
Color controlLineColor = Color.pink; // 控制條底色
Color controlTextColor = Color.white; // 控制條標簽文字色
Color rbFontColor = Color.white; // RoundBox文字色
Color rbBorderColor = Color.red; // RoundBox邊框色
Color rbButtonColor = Color.pink; // RoundBox按鈕色
Color rbBtFontColor = Color.red; // RoundBox按鈕文字色
JDialog dialog;
JSpinner yearSpin;
JSpinner monthSpin;
JSpinner hourSpin;
JComboBox minSpin;
JComboBox secondBox;
JButton[][] daysButton = new JButton[6][7];
DateChooser() {
setLayout(new BorderLayout());
setBorder(new LineBorder(backGroundColor, 2));
setBackground(backGroundColor);
JPanel topYearAndMonth = createYearAndMonthPanal();
add(topYearAndMonth, BorderLayout.NORTH);
JPanel centerWeekAndDay = createWeekAndDayPanal();
add(centerWeekAndDay, BorderLayout.CENTER);
}
private JPanel createYearAndMonthPanal() {
Calendar c = getCalendar();
int currentYear = c.get(Calendar.YEAR);
int currentMonth = c.get(Calendar.MONTH) + 1;
int currentHour = c.get(Calendar.HOUR_OF_DAY);
int currentMin = c.get(Calendar.MINUTE);
int currentSecond = c.get(Calendar.SECOND);
JPanel result = new JPanel();
result.setLayout(new FlowLayout());
result.setBackground(controlLineColor);
yearSpin = new JSpinner(new SpinnerNumberModel(currentYear,
startYear, lastYear, 1));
yearSpin.setPreferredSize(new Dimension(48, 20));
yearSpin.setName("Year");
yearSpin.setEditor(new JSpinner.NumberEditor(yearSpin, "####"));
yearSpin.addChangeListener(this);
result.add(yearSpin);
JLabel yearLabel = new JLabel("年");
yearLabel.setForeground(controlTextColor);
result.add(yearLabel);
monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth, 1,
12, 1));
monthSpin.setPreferredSize(new Dimension(35, 20));
monthSpin.setName("Month");
monthSpin.addChangeListener(this);
result.add(monthSpin);
JLabel monthLabel = new JLabel("月");
monthLabel.setForeground(controlTextColor);
result.add(monthLabel);
hourSpin = new JSpinner(new SpinnerNumberModel(currentHour, 0, 23,
1));
hourSpin.setPreferredSize(new Dimension(35, 20));
hourSpin.setName("Hour");
hourSpin.addChangeListener(this);
result.add(hourSpin);
JLabel hourLabel = new JLabel("時");
hourLabel.setForeground(controlTextColor);
result.add(hourLabel);
minSpin = new JComboBox();
;
addComboBoxItem(minSpin);
minSpin.setPreferredSize(new Dimension(45, 20));
minSpin.setName("Min");
minSpin.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent e) {
JComboBox source = (JComboBox) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Min")) {
c.set(Calendar.MINUTE, getSelectedMin());
setDate(c.getTime());
return;
}
}
});
result.add(minSpin);
JLabel minLabel = new JLabel("分");
hourLabel.setForeground(controlTextColor);
result.add(minLabel);
secondBox = new JComboBox();
addComboBoxItem(secondBox);
secondBox.setPreferredSize(new Dimension(45, 20));
secondBox.setName("Second");
// secondBox.addActionListener(this) ;
secondBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent e) {
JComboBox source = (JComboBox) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Second")) {
c.set(Calendar.SECOND, getSelectedSecond());
setDate(c.getTime());
return;
}
}
});
result.add(secondBox);
JLabel secondLabel = new JLabel("秒");
hourLabel.setForeground(controlTextColor);
result.add(secondLabel);
return result;
}
private void addComboBoxItem(JComboBox comboBox) {
for (int i = 0; i < 60; i++) {
comboBox.addItem(i);
}
}
private JPanel createWeekAndDayPanal() {
String colname[] = { "日", "一", "二", "三", "四", "五", "六" };
JPanel result = new JPanel();
// 設置固定字體,以免調用環境改變影響界面美觀
result.setFont(new Font("宋體", Font.PLAIN, 12));
result.setLayout(new GridLayout(7, 7));
result.setBackground(Color.white);
JLabel cell;
for (int i = 0; i < 7; i++) {
cell = new JLabel(colname[i]);
cell.setHorizontalAlignment(JLabel.RIGHT);
if (i == 0 || i == 6)
cell.setForeground(weekendFontColor);
else
cell.setForeground(weekFontColor);
result.add(cell);
}
int actionCommandId = 0;
for (int i = 0; i < 6; i++)
for (int j = 0; j < 7; j++) {
JButton numberButton = new JButton();
numberButton.setBorder(null);
numberButton.setHorizontalAlignment(SwingConstants.RIGHT);
numberButton.setActionCommand(String
.valueOf(actionCommandId));
numberButton.addActionListener(this);
numberButton.setBackground(palletTableColor);
numberButton.setForeground(dateFontColor);
if (j == 0 || j == 6)
numberButton.setForeground(weekendFontColor);
else
numberButton.setForeground(dateFontColor);
daysButton[i][j] = numberButton;
result.add(numberButton);
actionCommandId++;
}
return result;
}
private JDialog createDialog(Frame owner) {
JDialog result = new JDialog(owner, "日期時間選擇", true);
result.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
result.getContentPane().add(this, BorderLayout.CENTER);
result.pack();
result.setSize(width, height);
return result;
}
void showDateChooser(Point position) {
Frame owner = (Frame) SwingUtilities
.getWindowAncestor(DateChooseJButton.this);
if (dialog == null || dialog.getOwner() != owner)
dialog = createDialog(owner);
dialog.setLocation(getAppropriateLocation(owner, position));
flushWeekAndDay();
dialog.show();
}
Point getAppropriateLocation(Frame owner, Point position) {
Point result = new Point(position);
Point p = owner.getLocation();
int offsetX = (position.x + width) - (p.x + owner.getWidth());
int offsetY = (position.y + height) - (p.y + owner.getHeight());
if (offsetX > 0) {
result.x -= offsetX;
}
if (offsetY > 0) {
result.y -= offsetY;
}
return result;
}
private Calendar getCalendar() {
Calendar result = Calendar.getInstance();
result.setTime(getDate());
return result;
}
private int getSelectedYear() {
return ((Integer) yearSpin.getValue()).intValue();
}
private int getSelectedMonth() {
return ((Integer) monthSpin.getValue()).intValue();
}
private int getSelectedHour() {
return ((Integer) hourSpin.getValue()).intValue();
}
private int getSelectedMin() {
return (Integer) this.minSpin.getSelectedItem();
}
private int getSelectedSecond() {
return (Integer) this.secondBox.getSelectedItem();
}
private void dayColorUpdate(boolean isOldDay) {
Calendar c = getCalendar();
int day = c.get(Calendar.DAY_OF_MONTH);
c.set(Calendar.DAY_OF_MONTH, 1);
int actionCommandId = day - 2 + c.get(Calendar.DAY_OF_WEEK);
int i = actionCommandId / 7;
int j = actionCommandId % 7;
if (isOldDay)
daysButton[i][j].setForeground(dateFontColor);
else
daysButton[i][j].setForeground(todayBackColor);
}
private void flushWeekAndDay() {
Calendar c = getCalendar();
c.set(Calendar.DAY_OF_MONTH, 1);
int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
String s = "";
if (dayNo >= 1 && dayNo <= maxDayNo)
s = String.valueOf(dayNo);
daysButton[i][j].setText(s);
dayNo++;
}
}
dayColorUpdate(false);
}
public void stateChanged(ChangeEvent e) {
JSpinner source = (JSpinner) e.getSource();
Calendar c = getCalendar();
if (source.getName().equals("Hour")) {
c.set(Calendar.HOUR_OF_DAY, getSelectedHour());
setDate(c.getTime());
return;
}
dayColorUpdate(true);
if (source.getName().equals("Year"))
c.set(Calendar.YEAR, getSelectedYear());
else
// (source.getName().equals("Month"))
c.set(Calendar.MONTH, getSelectedMonth() - 1);
setDate(c.getTime());
flushWeekAndDay();
}
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
if (source.getText().length() == 0)
return;
dayColorUpdate(true);
source.setForeground(todayBackColor);
int newDay = Integer.parseInt(source.getText());
Calendar c = getCalendar();
c.set(Calendar.DAY_OF_MONTH, newDay);
setDate(c.getTime());
}
}
public static void main(String[] args){
new JButton();
}
}
上述日期控件繼承JButton,使用時只要構造出來JButton對象就行了。
package com.wss;
import java.awt.BorderLayout;
public class SearchTest extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField latitude;
private JTextField longitude;
private JTextField max;
private JTextField min;
private JTextField center;
private JComboBox begin;
private JComboBox end;
private JTable table;
private DefaultTableModel dm;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SearchTest frame = new SearchTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public SearchTest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getToolkit();
setSize(Toolkit.getDefaultToolkit().getScreenSize());
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
JLabel label = new JLabel("緯度:");
panel.add(label);
latitude = new JTextField();
panel.add(latitude);
latitude.setColumns(10);
JLabel label_1 = new JLabel("經度:");
panel.add(label_1);
longitude = new JTextField();
panel.add(longitude);
longitude.setColumns(10);
JLabel label_2 = new JLabel("時間:");
panel.add(label_2);
//獲取數據庫里的時間正序輸出
List<GPSBean> list_ = BusinessSelect.selectTime("select distinct to_char(obvdatetime,'YYYY-mm-dd HH24:MI:SS') t from gps order by t asc");
String[] time = new String[list_.size()];
for(int a=0; a<list_.size(); a++){
time[a] = list_.get(a).getTime();
}
begin = new JComboBox(time);
panel.add(begin);
JLabel label_3 = new JLabel("至");
panel.add(label_3);
end = new JComboBox(time);
panel.add(end);
JButton close = new DateChooseJButton();
panel.add(close);
//點擊事件
search.addActionListener(new SearchTest_search_actionAdapter(this));
JPanel panel_1 = new JPanel();
contentPane.add(panel_1, BorderLayout.CENTER);
String name[] = {"ID","時間","緯度","經度","值"};
String sql = "select * from gps order by id desc";
List<GPSBean> list = BusinessSelect.selectGPS(sql);
Object gpsValue[][] = new Object[list.size()][5];
for(int i=0; i<list.size(); i++){
GPSBean gpsBean = list.get(i);
Object value[] =
{
gpsBean.getId(),
gpsBean.getObvdateTime(),
gpsBean.getLongitude(),
gpsBean.getLatitude(),
gpsBean.getTecvalue()
};
for(int j=0; j<value.length; j++){
gpsValue[i][j] = value[j];
}
}
dm = new DefaultTableModel(gpsValue, name);
table = new JTable(dm);
table.setPreferredScrollableViewportSize(new Dimension(800,600));
JScrollPane scrollPane = new JScrollPane(table);
panel_1.add(scrollPane);
JPanel panel_s = new JPanel();
contentPane.add(panel_s, BorderLayout.SOUTH);
JLabel max_ = new JLabel("最大值:");
panel_s.add(max_);
max = new JTextField();
panel_s.add(max);
max.setColumns(10);
JLabel min_ = new JLabel("最小值:");
panel_s.add(min_);
min = new JTextField();
panel_s.add(min);
min.setColumns(10);
JLabel center_ = new JLabel("中值:");
panel_s.add(center_);
center = new JTextField();
panel_s.add(center);
center.setColumns(10);
}
public void search_actionPerformed(ActionEvent e){
dm.setRowCount(0);
String latitude_value = latitude.getText();
String longitude_value = longitude.getText();
String begin_value = begin.getSelectedItem().toString();
String end_value = end.getSelectedItem().toString();
String sql = "";
if(latitude_value.equals("") && longitude_value.equals("")){
sql = "select * from (select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS') as d, latitude, longitude, tecvalue, abs(latitude-0) a, abs(longitude-0) b " +
"from gps where obvdateTime>=TO_DATE('"+begin_value
+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end_value
+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc) where a<3 and b<5 order by d asc, a asc,b asc";
}else{
sql = "select * from (select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS') as d, latitude, longitude, tecvalue, abs(latitude-"
+Double.parseDouble(latitude_value)
+") a, abs(longitude-"+Double.parseDouble(longitude_value)
+") b from gps where obvdateTime>=TO_DATE('"+begin_value
+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end_value
+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc) where a<3 and b<5 order by d asc, a asc,b asc";
}
ResultSet rs = CommontDAO.selectFile(sql);
Vector<Object> v;
String time = "2011-02-28 00:00:00";
List<GPSBean> gpsBeanList = new ArrayList<GPSBean>();
try{
while(rs.next()){
if(time.equals(rs.getString(2)) || time == rs.getString(2)){
}else{
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLatitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLongitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
gpsBeanList.add(gpsBean);
time = rs.getString(2);
v = new Vector<Object>();
v.add(rs.getString(1));
v.add(rs.getString(2));
v.add(rs.getString(3));
v.add(rs.getString(4));
v.add(rs.getString(5));
dm.addRow(v);
}
}
}catch(Exception ex){
ex.printStackTrace();
System.out.println(ex.getMessage());
}finally{
CommontDAO.cloes(rs);
Double tecValue[] = new Double[gpsBeanList.size()];
for(int i=0; i<gpsBeanList.size(); i++){
tecValue[i] = gpsBeanList.get(i).getTecvalue();
}
Double center_value = Sort.center(tecValue);
Double max_value = Sort.max(tecValue);
Double min_value = Sort.min(tecValue);
max.setText(max_value+"");
min.setText(min_value+"");
center.setText(center_value+"");
}
}
}
class SearchTest_search_actionAdapter implements ActionListener {
private SearchTest adaptee;
SearchTest_search_actionAdapter(SearchTest adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.search_actionPerformed(e);
}
}
package com.wss;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.sql.*;
import java.util.*;
public class BusinessSelect {
//根據sql查詢記錄
public static List<GPSBean> selectGPS(String sql){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
rs = CommontDAO.selectFile(sql);
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLongitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLatitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
list.add(gpsBean);
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//搜索(根據經度和緯度查詢最近一點的記錄)
public static List<GPSBean> selectGPS(Double latitude_, Double longitude_){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
//獲取比指定點大的最近的1個值
String sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a from gps order by a desc";
rs = CommontDAO.selectFile(sql);
while(rs.next()){
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6));
}
System.out.println("---------------------------------------------------------------------------");
sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(longitude-"+longitude_+") b from gps order by b desc";
rs = CommontDAO.selectFile(sql);
while(rs.next()){
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6));
}
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps order by a asc, b asc";
//重要
// sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps where obvdateTime>=TO_DATE('2011-03-01 00:00:00','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('2011-03-01 02:00:00','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc";
while(rs.next()){
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7));
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//搜索(根據經度和緯度查詢最近一點的記錄)
public static List<GPSBean> selectGPS(Double latitude_, Double longitude_, String begin, String end){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
String sql = "select id, to_char(obvdateTime,'YYYY-mm-dd HH24:MI:SS'), latitude, longitude, tecvalue, abs(latitude-"+latitude_+") a, abs(longitude-"+longitude_+") b from gps where obvdateTime>=TO_DATE('"+begin+"','YYYY-mm-dd HH24:MI:SS') and obvdateTime<=TO_DATE('"+end+"','YYYY-mm-dd HH24:MI:SS') order by a asc, b asc";
rs = CommontDAO.selectFile(sql);
String test = "";
try{
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setId(Integer.parseInt(rs.getString(1)));
gpsBean.setObvdateTime(rs.getString(2));
gpsBean.setLatitude(Double.parseDouble(rs.getString(3)));
gpsBean.setLongitude(Double.parseDouble(rs.getString(4)));
gpsBean.setTecvalue(Double.parseDouble(rs.getString(5)));
list.add(gpsBean);
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7));
// System.out.println(rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5));
// test += rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4)+","+rs.getString(5)+","+rs.getString(6)+","+rs.getString(7)+"\r\n";
}
// File f = new File("D:/test.txt");
// OutputStream out = new FileOutputStream(f,true);
// out.write(test.getBytes());
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
//獲取時間
public static List<GPSBean> selectTime(String sql){
ResultSet rs = null;
List<GPSBean> list = new ArrayList<GPSBean>();
try{
rs = CommontDAO.selectFile(sql);
while(rs.next()){
GPSBean gpsBean = new GPSBean();
gpsBean.setTime(rs.getString(1));
list.add(gpsBean);
}
return list;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}finally{
CommontDAO.cloes(rs);
}
}
}
package com.wss;
public class GPSBean {
private int id;
private String obvdateTime;
private double longitude;
private double latitude;
private double tecvalue;
private String time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getObvdateTime() {
return obvdateTime;
}
public void setObvdateTime(String obvdateTime) {
this.obvdateTime = obvdateTime;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getTecvalue() {
return tecvalue;
}
public void setTecvalue(double tecvalue) {
this.tecvalue = tecvalue;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
package com.wss;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import com.db.DBConnectionManager;
public class CommontDAO {
private static DBConnectionManager dbcm = DBConnectionManager.getInstance();
//insert語句(支持多條sql)
public static boolean insertFile(String sql){
Connection con = null;
Statement st = null;
try{
con = dbcm.getConnection();
st = con.createStatement();
sql = sql.substring(0, sql.length()-1);
String[] num = sql.split(";");
for(int i=0; i<num.length; i++){
st.addBatch(num[i]);
}
st.executeBatch();
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}finally{
close(con, st);
}
}
//select語句(返回一個ResultSet)
public static ResultSet selectFile(String sql){
Connection con = null;
Statement st = null;
ResultSet rs = null;
try{
con = dbcm.getConnection();
st = con.createStatement();
rs = st.executeQuery(sql);
return rs;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return rs;
}
}
public static void close(Connection con){
try{
if(con != null){
con.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
}
public static void close(Connection con, Statement st){
try{
if(st != null){
st.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
close(con);
}
public static void close(Connection con, Statement st, ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
close(con, st);
}
public static void cloes(ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
package com.wss;
public class Sort {
//求最大值
public static Double max(Double[] value){
//把數組第一個值最為一個標志
Double num1 = value[0];
//中間變量
Double temp = 0.0;
for(int i=1; i<value.length; i++){
if(num1 < value[i]){
temp = num1;
num1 = value[i];
value[i] = temp;
}
}
return num1;
}
//求最小值
public static Double min(Double[] value){
//把數組第一個值最為一個標志
Double num1 = value[0];
//中間變量
Double temp = 0.0;
for(int i=0; i<value.length; i++){
if(num1 > value[i]){
temp = num1;
num1 = value[i];
value[i] = temp;
}
}
return num1;
}
//求中值
public static Double center(Double[] value){
Double temp = 0.0;
//排序
for(int i=0; i<value.length; i++){
for(int j=i+1; j<value.length; j++){
if(value[i] > value[j]){
temp = value[j];
value[j] = value[i];
value[i] = temp;
}
}
}
//求中值所在的下標位置
int num = value.length/2;
return value[num];
}
public static void main(String[] args){
Double value[] = {4.0, 1.0, 2.0, 3.0};
System.out.println(Sort.center(value));
}
}
DWR(Direct Web Remoting)是一個WEB遠程調用框架.利用這個框架可以讓AJAX開發變得很簡單.利用DWR可以在客戶端利用JavaScript直接調用服務端的Java方法并返回值給JavaScript就好像直接本地客戶端調用一樣(DWR根據Java類來動態生成JavaScrip代碼).它的最新版本DWR0.6添加許多特性如:支持Dom Trees的自動配置,支持Spring(JavaScript遠程調用spring bean),更好瀏覽器支持,還支持一個可選的commons-logging日記操作.
以上摘自open-open,它通過反射,將java翻譯成javascript,然后利用回調機制,輕松實現了javascript調用Java代碼。
其大概開發過程如下:
1.編寫業務代碼,該代碼是和dwr無關的。
2.確認業務代碼中哪些類、哪些方法是要由javascript直接訪問的。
3.編寫dwr組件,對步驟2的方法進行封裝。
4.配置dwr組件到dwr.xml文件中,如果有必要,配置convert,進行java和javascript類型互轉。
5.通過反射機制,dwr將步驟4的類轉換成javascript代碼,提供給前臺頁面調用。
5.編寫網頁,調用步驟5的javascript中的相關方法(間接調用服務器端的相關類的方法),執行業務邏輯,將執行結果利用回調函數返回。
6.在回調函數中,得到執行結果后,可以繼續編寫業務邏輯的相關javascript代碼。
下面以用戶注冊的例子,來說明其使用。(注意,本次例子只是用于演示,說明DWR的使用,類設計并不是最優的)。
1.先介紹下相關的Java類
User: 用戶類,
public class User {
//登陸ID,主鍵唯一
private String id;
//姓名
private String name;
//口令
private String password;
//電子郵件
private String email;
//以下包含getXXX和setXXX方法
.......
}
UserDAO:實現User的數據庫訪問,這里作為一個演示,編寫測試代碼
public class UserDAO {
//存放保存的數據
private static Map dataMap = new HashMap();
//持久用戶
public boolean save(User user) {
if (dataMap.containsKey(user.getId()))
return false;
System.out.println("下面開始保存用戶");
System.out.println("id:"+user.getId());
System.out.println("password:"+user.getPassword());
System.out.println("name:"+user.getName());
System.out.println("email:"+user.getEmail());
dataMap.put(user.getId(), user);
System.out.println("用戶保存結束");
return true;
}
//查找用戶
public User find(String id) {
return (User)dataMap.get(id);
}
}
DWRUserAccess:DWR組件,提供給javascript訪問的。
public class DWRUserAccess {
UserDAO userDAO = new UserDAO();
public boolean save(User user) {
return userDAO.save(user);
}
public User find(String id) {
return userDAO.find(id);
}
}
下面說明下程序執行的流程
1.用戶在頁面上輸入相關注冊信息,id、name、password、email,點擊“提交”按鈕
2.javascript代碼開始執行,根據用戶填寫相關信息,通過dwr提供的DWRUserAccess.js里save的方法,調用服務器端的DWRUserAccess類save方法,將注冊信息保存。
3.通過DWRUserAccess.jsp里的find方法,調用服務器端DWRUserAccess類里的find方法,執行用戶信息查找。
注意,在以上的執行過程中,DWRUserAccess是供DWR調用的,是DWR組件,因此需要將DWRUserAccess類配置到dwr中。
接下來講解本次dwr測試環境的配置。
1.新建一個webapp,命名為testApp
2.將dwr.jar拷貝到testApp的WEB-INF的lib目錄下
3.編譯上面的User,UserDAO,DWRUserAccess類,放到classes目錄下
4.在web.xml中配置servlet,適配路徑到dwr目錄下,如下所示
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>scriptCompressed</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
以上的配置可以攔截testApp下所有指向dwr的請求,關于這個攔截器,我們會在后面介紹。
5.WEB-INF下新建一個dwr.xml文件,內容如下:
< xml version="1.0" encoding="UTF-8" >
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="DWRUserAccess">
<param name="class" value="test.DWRUserAccess"/>
</create>
<convert converter="bean" match="test.User"/>
</allow>
</dwr>
這里我們把DWRUserAccess配置到了dwr中,create元素中,creater="new"表示每調用一次DWRUserAccess時,需要new一個這樣的類;javascript="DWRUserAccess",表示提供給前臺頁面調用的javascirpt文件是DWRUserAccess.js。
convert元素用于數據類型轉換,即java類和javascript之間相互轉換,因為和前臺交換的是User對象,因此需要對此使用bean轉換,我們將在后面介紹這個類。
4.編寫測試的HTML頁面 test.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DWR測試</TITLE>
<meta http-equiv=Content-Type content="text/html; charset=gb2312">
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
</HEAD>
<BODY>
<B>用戶注冊</B><br>
------------------------------------------------
<Br>
<form name="regForm">
登陸ID:<input type="text" name="id"><br>
口 令:<input type="password" name="password"><br>
姓 名:<input type="text" name="name"><br>
電子郵件:<input type="text" name="email"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnSave()"><br>
</form>
<br>
<br><B>用戶查詢</B><br>
------------------------------------------------
<Br>
<form name="queryForm">
登陸ID:<input type="text" name="id"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnFind()"><br>
</form>
<br>
</BODY>
</HTML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注冊成功!");
} else {
alert("登陸ID已經存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("無法找到用戶:"+queryForm.id.value);
return;
}
alert("找到用戶,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
以下對頁面的javascript進行解釋
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
這兩個是dwr提供的,用戶可以不必關心,只需要導入即可
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
是我們編寫的DWRUserAccess類,經dwr反射后,生成的javascript代碼,它和DWRUserAccess.java是對應的,供用戶調用,實際上我們就是通過這個js文件去調用服務器端的DWRUserAccess類的。
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注冊成功!");
} else {
alert("用戶名已經存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("無法找到用戶:"+queryForm.id.value);
return;
}
alert("找到用戶,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
這段javascirpt代碼,我們來看下OnSave函數,首先它構造一個map,將表單數據都設置到map中,然后調用DWRUserAccess.save(userMap, saveFun),執行save操作。大家可以注意到,服務器端的DWRUserAccess中的save方法是這樣的:boolean save(User user),其參數是一個User對象,返回一個boolean值;而客戶端的方法是這樣的:save(userMap,saveFun),第一個參數userMap是javascirpt中的map對象,在這里相當于服務器端的User對象(在服務器端執行時,會通過convert轉換成User對象),前面我們提到dwr是利用回調函數來返回執行結果的,第二個參數saveFun即是一個回調函數。在函數function saveFun(data)中,data是執行結果,這里是一個bool值,非常簡單的,我們通過判斷data是否為真,可以知道用戶名是否重復,用戶是否注冊成功。
看一下OnFind查找函數,執行結果在回調函數findFun(data)中,因為服務器端返回的是一個User對象,通過convert,將會轉換成javascript的一個map對象,
于是在findFun中,通過data.id、data.name、data.password、data.email我們可以輕松的訪問到這個User對象。
好了配置完畢,啟動服務器,在目錄中打入localhost/testApp/test.html。
1.在“用戶注冊”表單中,id框中輸入admin,password中輸入123456,name中輸入chenbug,email中輸入chenbug@zj.com,點擊提交按鈕,彈出對話框:“注冊成功”,在服務器后臺可以看到信息如下:
下面開始保存用戶
id:admin
password:123456
name:chenbug
email:chenbug@zj.com
用戶保存結束
再次點擊提交按鈕,彈出對話框“登陸ID已經存在”。
2.在“用戶查詢”對話框中,輸入登陸ID為admin,點擊提交按鈕,提示找到用戶,并顯示相關信息,輸入admin123,點擊提交按鈕,提示無法找到用戶。
至此,測試結束。
后續:
1。攔截器 uk.ltd.getahead.dwr.DWRServlet
該類攔截所有指向dwr目錄下的請求,并調用Processor的handler方法進行處理,在uk.ltd.getahead.dwr.impl.DefaultProcessor下,我們可以看到詳細的處理過程。
if (pathInfo.length() == 0 ||
pathInfo.equals(HtmlConstants.PATH_ROOT) ||
pathInfo.equals(req.getContextPath()))
{
resp.sendRedirect(req.getContextPath() + servletPath + HtmlConstants.FILE_INDEX);
}
else if (pathInfo.startsWith(HtmlConstants.FILE_INDEX))
{
index.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_TEST))
{
test.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_INTERFACE))
{
iface.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_EXEC))
{
exec.handle(req, resp);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_ENGINE))
{
file.doFile(req, resp, HtmlConstants.FILE_ENGINE, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_UTIL))
{
file.doFile(req, resp, HtmlConstants.FILE_UTIL, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_DEPRECATED))
{
file.doFile(req, resp, HtmlConstants.FILE_DEPRECATED, HtmlConstants.MIME_JS);
}
else
{
log.warn("Page not found (" + pathInfo + "). In debug/test mode try viewing /[WEB-APP]/dwr/"); //$NON-NLS-1$ //$NON-NLS-2$
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
通過判斷request請求的servlet路徑,進行處理,大家可以自己去參看,這里不詳細討論。
2.bean轉換器,<convert converter="bean" match="test.User"/>
將dwr.jar解壓縮,在路徑ukltdgetaheaddwr下可以看到dwr.xml,這里配置了系統默認的一些轉換器,
<converter id="bean" class="uk.ltd.getahead.dwr.convert.BeanConverter"/>即是剛才用到User類的轉換器,進入代碼我們來看看它是如何在javascript和java間進行轉換的。
打開BeanConverter代碼,定位到函數
public Object convertInbound(Class paramType, InboundVariable iv, InboundContext inctx) throws ConversionException
即是將javascript對象轉換成java對象的,其中
paramType即Class類型,在上面的例子中是test.User,
InboundVariable iv,是傳入的值,通過iv.getValue可以得到傳入的javascript值串
InboundContext inctx,是入口參數上下文,用于保存轉換的后java對象。
因為前臺傳入的是一個javascript的map類型,而map肯定是以{開始和以}結束的,于是在這個函數一開始進行了判斷
if (!value.startsWith(ConversionConstants.INBOUND_MAP_START))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingOpener", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
if (!value.endsWith(ConversionConstants.INBOUND_MAP_END))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingCloser", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
javascript中,map里各個項是用逗號連接的,如var userMap = {id:'admin',password:'123456',name:'chenbug',email:'chenbug@zj.com'};而每個項的鍵值對是用冒號連接的,
在convertInbound函數的接下來的處理中,即是通過分析map字串,通過paramType構造java實例(即User類),然后通過反射,將這些鍵值對設置到java實例中,并返回。
這樣就完成了javascript到java的轉換。
另一個函數
public String convertOutbound(Object data, String varname, OutboundContext outctx) throws ConversionException
即是將java對象轉換為javascript對象(其實是聲明和賦值語句)。
Object data ,是待轉換的java對象
String varname,是javascript中的該對象的變量名
OutboundContext outctx,傳出參數上下文,用于保存轉換后的javascript值
StringBuffer buffer = new StringBuffer();
buffer.append("var "); //$NON-NLS-1$
buffer.append(varname);
buffer.append("={};"); //$NON-NLS-1$
這里聲明了map類型的變量。
即下來來的代碼即是通過反射進行變量賦值,如下
buffer.append(varname);
buffer.append('.');
buffer.append(name);
buffer.append('=');
buffer.append(nested.getAssignCode());
buffer.append(';');
大家可以自己去參看更多的代碼。
3.dwr本身提供了一個測試環境,大家在配置完后,可以在IE中輸入地址http://localhost/testApp/dwr/index.html,看到配置的各DWR組件,并進行相關測試。
先準備好軟件:
Apache官方下載地址:apache_2.0.55-win32-x86-no_ssl.msi,更多版本在這里;
php官方下載地址:php-5.0.5-Win32.zip,更多鏡像下載地址,更多版本下載;
mysql官方下載地址:mysql-4.1.14-win32.zip,更多鏡像下載地址,更多版本下載。
一、安裝Apache,配置成功一個普通網站服務器
運行下載好的“apache_2.0.55-win32-x86-no_ssl.msi”,出現如下界面:
出現Apache HTTP Server 2.0.55的安裝向導界面,點“Next”繼續
確認同意軟件安裝使用許可條例,選擇“I accept the terms in the license agreement”,點“Next”繼續
將Apache安裝到Windows上的使用須知,請閱讀完畢后,按“Next”繼續
設置系統信息,在Network Domain下填入您的域名(比如:goodwaiter.com),在Server Name下填入您的服務器名稱(比如:www.goodwaiter.com,也就是主機名加上域名),在Administrator's Email Address下填入系統管理員的聯系電子郵件地址(比如:yinpeng@xinhuanet.com),上述三條信息僅供參考,其中聯系電子郵件地址會在當系統故障時提供給訪問者,三條信息均可任意填寫,無效的也行。下面有兩個選擇,圖片上選擇的是為系統所有用戶安裝,使用默認的80端口,并作為系統服務自動啟動;另外一個是僅為當前用戶安裝,使用端口8080,手動啟動。一般選擇如圖所示。按“Next”繼續。]
選擇安裝類型,Typical為默認安裝,Custom為用戶自定義安裝,我們這里選擇Custom,有更多可選項。按“Next”繼續
出現選擇安裝選項界面,如圖所示,左鍵點選“Apache HTTP Server 2.0.55”,選擇“This feature, and all subfeatures, will be installed on local hard drive.”,即“此部分,及下屬子部分內容,全部安裝在本地硬盤上”。點選“Change...”,手動指定安裝目錄。
我這里選擇安裝在“D:\”,各位自行選取了,一般建議不要安裝在操作系統所在盤,免得操作系統壞了之后,還原操作把Apache配置文件也清除了。選“OK”繼續。
返回剛才的界面,選“Next”繼續。
確認安裝選項無誤,如果您認為要再檢查一遍,可以點“Back”一步步返回檢查。點“Install”開始按前面設定的安裝選項安裝。
正在安裝界面,請耐心等待,直到出現下面的畫面。
安裝向導成功完成,這時右下角狀態欄應該出現了下面的這個綠色圖標,表示Apache服務已經開始運行,按“Finish”結束Apache的軟件安裝
我們來熟悉一下這個圖標,很方便的,在圖標上左鍵單擊,出現如下界面,有“Start(啟動)”、“Stop(停止)”、“Restart(重啟動)”三個選項,可以很方便的對安裝的Apache服務器進行上述操作。
好了現在我們來測試一下按默認配置運行的網站界面,在IE地址欄打“http://127.0.0.1”,點“轉到”,就可以看到如下頁面,表示Apache服務器已安裝成功。
現在開始配置Apache服務器,使它更好的替我們服務,事實上,如果不配置,你的安裝目錄下的Apache2\htdocs文件夾就是網站的默認根目錄,在里面放入文件就可以了。這里我們還是要配置一下,有什么問題或修改,配置始終是要會的,如圖所示,“開始”、“所有程序”、“Apache HTTP Server 2.0.55”、“Configure Apache Server”、“Edit the Apache httpd conf Configuration file”,點擊打開。
XP的記事本有了些小變化,很實用的一個功能就是可以看到文件內容的行、列位置,按下圖所示,點“查看”,勾選“狀態欄”,界面右下角就多了個標記,“Ln 78, Col 10”就表示“行 78,列 10”,這樣可以迅速的在文件中定位,方便解說。當然,你也可以通過“編輯”,“查找”輸入關鍵字來快速定位。每次配置文件的改變,保存后,必須在 Apache服務器重啟動后生效,可以用前面講的小圖標方便的控制服務器隨時“重啟動”。
現在正式開始配置Apache服務器,“Ln 228”,或者查找關鍵字“DocumentRoot”(也就是網站根目錄),找到如下圖所示地方,然后將""內的地址改成你的網站根目錄,地址格式請照圖上的寫,主要是一般文件地址的“\”在Apache里要改成“/”。
“Ln 253”,同樣,你也可以通過查找“
“Ln321”,DirectoryIndex(目錄索引,也就是在僅指定目錄的情況下,默認顯示的文件名),可以添加很多,系統會根據從左至右的順序來優先顯示,以單個半角空格隔開,比如有些網站的首頁是index.htm,就在光標那里加上“index.htm ”文件名是任意的,不一定非得“index.html”,比如“test.php”等,都可以。
這里有一個選擇配置選項,以前可能要配置,現在好像修正過來了,不用配置了,就是強制所有輸出文件的語言編碼,html文件里有語言標記(,這個就是設定文檔語言為gb2312)的也會強制轉換。如果打開的網頁出現亂碼,請先檢查網頁內有沒有上述 html語言標記,如果沒有,添加上去就能正常顯示了。把“# DefaultLanguage nl”前面的“# ”去掉,把“nl”改成你要強制輸出的語言,中文是“zh-cn”,保存,關閉。
好了,簡單的Apache配置就到此結束了,現在利用先前的小圖標重啟動,所有的配置就生效了,你的網站就成了一個網站服務器,如果你加載了防火墻,請打開80或8080端口,或者允許Apache程序訪問網絡,否則別人不能訪問。如果你有公網IP(一般ADSL或電話撥號上網的都是),就可以邀請所有能上網的朋友訪問使用http://你的IP地址(IP地址查詢可訪問http://www.goodwaiter.com,查詢內容內即是)你的網站了;如果你沒有公網IP,也可以把內網IP地址告訴局域網內的其它用戶,讓他們通過http://你的內網IP地址,訪問你的網站。
二、php的安裝、以module方式,將php與apache結合使你的網站服務器支持php服務器腳本程序
將下載的php安裝文件php-5.0.5-Win32.zip右鍵解壓縮。
指定解壓縮的位置,我的設定在“D:\php”
查看解壓縮后的文件夾內容,找到“php.ini-dist”文件,將其重命名為“php.ini”,打開編輯,找到下面圖中的地方, Ln385,有一個“register_globals = Off”值,這個值是用來打開全局變量的,比如表單送過來的值,如果這個值設為“Off”,就只能用“$_POST['變量名']、$_GET['變量名 ']”等來取得送過來的值,如果設為“On”,就可以直接使用“$變量名”來獲取送過來的值,當然,設為“Off”就比較安全,不會讓人輕易將網頁間傳送的數據截取。這個值是否改成“On”就看自己感覺了,是安全重要還是方便重要?
這里還有一個地方要編輯,功能就是使php能夠直接調用其它模塊,比如訪問mysql,如下圖所示,Ln563,選擇要加載的模塊,去掉前面的 “;”,就表示要加載此模塊了,加載的越多,占用的資源也就多一點,不過也多不到哪去,比如我要用mysql,就要把“;extension= php_mysql.dll”前的“;”去掉。所有的模塊文件都放在php解壓縮目錄的“ext”之下,我這里的截圖是把所有能加載的模塊都加載上去了,前面的“;”沒去掉的,是因為“ext”目錄下默認沒有此模塊,加載會提示找不到文件而出錯。這里只是參考,一般不需要加載這么多,需要的加載上就可以了,編輯好后保存,關閉。
如果上一步加載了其它模塊,就要指明模塊的位置,否則重啟Apache的時候會提示“找不到指定模塊”的錯誤,這里介紹一種最簡單的方法,直接將php安裝路徑、里面的ext路徑指定到windows系統路徑中——在“我的電腦”上右鍵,“屬性”,選擇“高級”標簽,點選“環境變量”,在“系統變量”下找到“Path”變量,選擇,雙擊或點擊“編輯”,將“;D:\php;D:\php\ext”加到原有值的后面,當然,其中的“D:\php” 是我的安裝目錄,你要將它改為自己的php安裝目錄,如下圖所示,全部確定。系統路徑添加好后要重啟電腦才能生效,可以現在重啟,也可以在所有軟件安裝或配置好后重啟。
現在開始將php以module方式與Apache相結合,使php融入Apache,照先前的方法打開Apache的配置文件,Ln 173,找到這里,添加進如圖所示選中的兩行,第一行“LoadModule php5_module D:/php/php5apache2.dll”是指以module方式加載php,第二行“PHPIniDir "D:/php"”是指明php的配置文件php.ini的位置,是當然,其中的“D:/php”要改成你先前選擇的php解壓縮的目錄。
還是Apache的配置文件,Ln 757,加入“AddType application/x-httpd-php .php”、“AddType application/x-httpd-php .html”兩行,你也可以加入更多,實質就是添加可以執行php的文件類型,比如你再加上一行“AddType application/x-httpd-php .htm”,則.htm文件也可以執行php程序了,你甚至還可以添加上一行“AddType application/x-httpd-php .txt”,讓普通的文本文件格式也能運行php程序。
前面所說的目錄默認索引文件也可以改一下,因為現在加了php,有些文件就直接存為.php了,我們也可以把“index.php”設為默認索引文件,優先順序就自己排了,我的是放在第一位。編輯完成,保存,關閉。
現在,php的安裝,與Apache的結合已經全部完成,用屏幕右下角的小圖標重啟Apache,你的Apache服務器就支持了php。
三、mysql的安裝,與php、Apache相結合
打開下載的mysql安裝文件mysql-4.1.14-win32.zip,雙擊解壓縮,運行“setup.exe”,出現如下界面
mysql安裝向導啟動,按“Next”繼續
選擇安裝類型,有“Typical(默認)”、“Complete(完全)”、“Custom(用戶自定義)”三個選項,我們選擇“Custom”,有更多的選項,也方便熟悉安裝過程
在“Developer Components(開發者部分)”上左鍵單擊,選擇“This feature, and all subfeatures, will be installed on local hard drive.”,即“此部分,及下屬子部分內容,全部安裝在本地硬盤上”。在上面的“MySQL Server(mysql服務器)”、“Client Programs(mysql客戶端程序)”、“Documentation(文檔)”也如此操作,以保證安裝所有文件。點選“Change...”,手動指定安裝目錄。
填上安裝目錄,我的是“D:\mysql”,也建議不要放在與操作系統同一分區,這樣可以防止系統備份還原的時候,數據被清空。按“OK”繼續。
返回剛才的界面,按“Next”繼續。
確認一下先前的設置,如果有誤,按“Back”返回重做。按“Install”開始安裝。
正在安裝中,請稍候,直到出現下面的界面
這里是詢問你是否要注冊一個mysql.com的賬號,或是使用已有的賬號登陸mysql.com,一般不需要了,點選“Skip Sign-Up”,按“Next”略過此步驟。
現在軟件安裝完成了,出現上面的界面,這里有一個很好的功能,mysql配置向導,不用向以前一樣,自己手動亂七八糟的配置my.ini了,將 “Configure the Mysql Server now”前面的勾打上,點“Finish”結束軟件的安裝并啟動mysql配置向導。
mysql配置向導啟動界面,按“Next”繼續。
選擇配置方式,“Detailed Configuration(手動精確配置)”、“Standard Configuration(標準配置)”,我們選擇“Detailed Configuration”,方便熟悉配置過程。
選擇服務器類型,“Developer Machine(開發測試類,mysql占用很少資源)”、“Server Machine(服務器類型,mysql占用較多資源)”、“Dedicated MySQL Server Machine(專門的數據庫服務器,mysql占用所有可用資源)”,大家根據自己的類型選擇了,一般選“Server Machine”,不會太少,也不會占滿。
選擇mysql數據庫的大致用途,“Multifunctional Database(通用多功能型,好)”、“Transactional Database Only(服務器類型,專注于事務處理,一般)”、“Non-Transactional Database Only(非事務處理型,較簡單,主要做一些監控、記數用,對MyISAM數據類型的支持僅限于non-transactional),隨自己的用途而選擇了,我這里選擇“Transactional Database Only”,按“Next”繼續。
對InnoDB Tablespace進行配置,就是為InnoDB 數據庫文件選擇一個存儲空間,如果修改了,要記住位置,重裝的時候要選擇一樣的地方,否則可能會造成數據庫損壞,當然,對數據庫做個備份就沒問題了,這里不詳述。我這里沒有修改,使用用默認位置,直接按“Next”繼續
選擇您的網站的一般mysql訪問量,同時連接的數目,“Decision Support(DSS)/OLAP(20個左右)”、“Online Transaction Processing(OLTP)(500個左右)”、“Manual Setting(手動設置,自己輸一個數)”,我這里選“Online Transaction Processing(OLTP)”,自己的服務器,應該夠用了,按“Next”繼續
是否啟用TCP/IP連接,設定端口,如果不啟用,就只能在自己的機器上訪問mysql數據庫了,我這里啟用,把前面的勾打上,Port Number:3306,按“Next”繼續
這個比較重要,就是對mysql默認數據庫語言編碼進行設置,第一個是西文編碼,第二個是多字節的通用utf8編碼,都不是我們通用的編碼,這里選擇第三個,然后在Character Set那里選擇或填入“gbk”,當然也可以用“gb2312”,區別就是gbk的字庫容量大,包括了gb2312的所有漢字,并且加上了繁體字、和其它亂七八糟的字——使用mysql的時候,在執行數據操作命令之前運行一次“SET NAMES GBK;”(運行一次就行了,GBK可以替換為其它值,視這里的設置而定),就可以正常的使用漢字(或其它文字)了,否則不能正常顯示漢字。按 “Next”繼續。
選擇是否將mysql安裝為windows服務,還可以指定Service Name(服務標識名稱),是否將mysql的bin目錄加入到Windows PATH(加入后,就可以直接使用bin下的文件,而不用指出目錄名,比如連接,“mysql.exe -uusername -ppassword;”就可以了,不用指出mysql.exe的完整地址,很方便),我這里全部打上了勾,Service Name不變。按“Next”繼續。
這一步詢問是否要修改默認root用戶(超級管理)的密碼(默認為空),“New root password”如果要修改,就在此填入新密碼(如果是重裝,并且之前已經設置了密碼,在這里更改密碼可能會出錯,請留空,并將“Modify Security Settings”前面的勾去掉,安裝配置完成后另行修改密碼),“Confirm(再輸一遍)”內再填一次,防止輸錯。“Enable root access from remote machines(是否允許root用戶在其它的機器上登陸,如果要安全,就不要勾上,如果要方便,就勾上它)”。最后“Create An Anonymous Account(新建一個匿名用戶,匿名用戶可以連接數據庫,不能操作數據,包括查詢)”,一般就不用勾了,設置完畢,按“Next”繼續。
確認設置無誤,如果有誤,按“Back”返回檢查。按“Execute”使設置生效。
設置完畢,按“Finish”結束mysql的安裝與配置——這里有一個比較常見的錯誤,就是不能“Start service”,一般出現在以前有安裝mysql的服務器上,解決的辦法,先保證以前安裝的mysql服務器徹底卸載掉了;不行的話,檢查是否按上面一步所說,之前的密碼是否有修改,照上面的操作;如果依然不行,將mysql安裝目錄下的data文件夾備份,然后刪除,在安裝完成后,將安裝生成的 data文件夾刪除,備份的data文件夾移回來,再重啟mysql服務就可以了,這種情況下,可能需要將數據庫檢查一下,然后修復一次,防止數據出錯。
與Apache及php相結合,前面已提過,這里再說一下,在php安裝目錄下,找到先前重命名并編輯過的 php.ini,如下圖所示,Ln563,把“;extension=php_mysql.dll”前的“;”去掉,加載mysql模塊。保存,關閉后,重啟apache就可以了。這里也可以選擇其它要加載的模塊,去掉前面的“;”,就表示要加載此模塊了,加載的越多,占用的資源也就多一點,不過也多不到哪去。所有的模塊文件都放在php解壓縮目錄的“ext”之下,我這里的截圖是把所有能加載的模塊都加載上去了,前面的“;”沒去掉的,是因為“ext” 目錄下默認沒有此模塊,加載會提示找不到文件而出錯。這里只是參考,一般不需要加載這么多,需要的加載上就可以了,編輯好后保存,關閉。
同樣,加載了模塊后,就要指明模塊的位置,否則重啟Apache的時候會提示“找不到指定模塊”的錯誤,這里介紹一種最簡單的方法,直接將 php安裝路徑、里面的ext路徑指定到windows系統路徑中——在“我的電腦”上右鍵,“屬性”,選擇“高級”標簽,點選“環境變量”,在“系統變量”下找到“Path”變量,選擇,雙擊或點擊“編輯”,將“;D:\php;D:\php\ext”加到原有值的后面,當然,其中的“D:\php”是我的安裝目錄,你要將它改為自己的php安裝目錄,如下圖所示,全部確定。系統路徑添加好后要重啟電腦才能生效,可以現在重啟,也可以在所有軟件安裝或配置好后重啟。
系統主要是通過tomcat運行,將tomcat和jre打包后發送給客戶使用,綠色的方式安裝使用,由于客戶也不搞開發,所以就僅僅是jre和tomcat和應用程序
我使用的jre6,免安裝版版的tomcat6;目錄結構是這樣的
[我的應用名字]
|-jre6
|-tomcat6
|-go_tomcat.bat
go_tomcat.bat文件內容
@ECHO OFF
set JRE_HOME=.\jre6
set PATH=%JRE_HOME%\bin;%PATH%
set TOMCAT_HOME=.\tomcat6
cd .\%TOMCAT_HOME%\bin
rem 啟動tomcat服務
.\startup.bat