2008年9月22日 星期一

JavaEE HttpSession 用法

先建立一個儲存使用者資訊用的POJO物件,如:

使用WebApp的Servlet或Spring Controller,建立Login及Logout的動作,

Login:


Logout:

2008年9月19日 星期五

Hibernate 自定 generator

Hibernate的generator tag 是用來定義如何Hibernate物件的主鍵
如:


使用increment可以使主鍵每次自動加一。
然而class也可以是自己設計的 java CustGenerator class
要設計一個generator class 必須 implement兩個interface:
public class GreenBookGroupGenerator implements IdentifierGenerator, Configurable

IdentifierGenerator interface 提供 的方法
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException
會在每次需要主鍵時被呼叫,obj即是要被指定id的Hibernate entity POJO
要return Serializable id回去。

Configurable interface 提供 的方法
public void configure(Type type, Properties props, Dialect dialect) throws MappingException
只會在SessionFactory建立時呼叫一次,如果generator有提供param會以 key-value pair把參數
放在Properties裡傳進來:

自從Hibernate 3.3 後複合主鍵才可以使用generator tag

2008年9月4日 星期四

hibernate 關連

在hbm.xml使用many-to-one進行多對一關連
當被關連的對象是複合主鍵時,不可在many-to-one tag使用column attribute
只要在many-to-one tag下建立多個子column tag並一一指定name=主鍵欄位名稱即可
如圖:

2008年8月21日 星期四

Eclipse UML2 工具

在預設的Site Ganymede下的Models and Model Development下的UML2*
選擇 UML2 Tools 、 UML2 Tools SDK 、UML2 End-User Features 、UML2 Extender SDK四項,
安裝即可。

使用時New -> Others -> UML 2.1 Diagrams 就可以建立UseCase 等UML圖,
建立時會產生一個.uml的model xml檔案,及另一個.umlxxx的圖形render定義檔,
使用model可以產生各種的render圖,但如果多個圖共用同一個model要小心資料共用的問題。

2008年8月20日 星期三

apache ftpserver-1.0-M2

apache ftpserver 可以加入自定的Ftplet來處理Ftp Event。
只要實作Ftplet interface 或 直接繼承DefaultFtplet。
再加入Ftplet到ftpserver,當Ftp command到來後就會自動呼叫對應的方法。

FtpServer ftpserver = new FtpServer();
ftpserver.setFtplets(getFtpletsMap());
ftpserver.start();

想使用DefaultFtplet來處理Ftp命令,可以override DefaultFtplet的onXXXStart方法。
卻找不到onListStart方法,來顯示檔案列表。
看了一下source code 發現DefaultFtplet的實作只是把beforeCommand根據,
request.getCommand()取得的命令來分支到其他方法,如下,

public FtpletResult beforeCommand(FtpSession session, FtpRequest request)
throws FtpException, IOException {
String command = request.getCommand().toUpperCase();

if ("DELE".equals(command)) {
return onDeleteStart(session, request);
} else if ("STOR".equals(command)) {
return onUploadStart(session, request);
} else if ("RETR".equals(command)) {
return onDownloadStart(session, request);
} else if ("RMD".equals(command)) {
return onRmdirStart(session, request);
} else if ("MKD".equals(command)) {
return onMkdirStart(session, request);
} else if ("APPE".equals(command)) {
return onAppendStart(session, request);
} else if ("STOU".equals(command)) {
return onUploadUniqueStart(session, request);
} else if ("RNTO".equals(command)) {
return onRenameStart(session, request);
} else {
// TODO should we call a catch all?
return null;
}
}

於是就可以自己重新override beforeCommand方法再增加LIST分支即可,
@Override
public FtpletResult beforeCommand(FtpSession session, FtpRequest request) throws FtpException, IOException {
String command = request.getCommand().toUpperCase();
if ("LIST".equals(command)) {
return this.onListStart(session, request);
} else {
return super.beforeCommand(session, request);
}
}

2008年8月11日 星期一

Spring 整合 Hibernate

classpath所需要的jar
===== postgresql ==========
pg74.216.jdbc3.jar
======= spring ===========
spring.jar
commons-logging.jar
======= hibernate =========
antlr-2.7.6.jar
asm.jar
c3p0-0.9.1.jar
cglib-2.1.3.jar
commons-collections-2.1.1.jar
dom4j-1.6.1.jar
ehcache-1.2.3.jar
hibernate3.jar
jta.jar
log4j-1.2.13.jar
=======================

範例資料表DDL
CREATE TABLE tbl_user
(
id serial NOT NULL,
name character varying(20),
age integer,
CONSTRAINT tbl_user_pkey PRIMARY KEY (id)
)

使用HibernateTools產生TblUser.java POJO物件 及 TblUser.hbm.xml mapping file

建立IUserDAO介面
package idv.muchu.test.spring;

public interface IUserDAO {
public void insert(TblUser user);
public void update(TblUser user);
public void delete(TblUser user);
public TblUser find(Integer id);
}

實作IUserDAO介面(使用HibernateTemplate簡化實作)

package idv.muchu.test.spring;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class UserDAO implements IUserDAO {
private HibernateTemplate hibernateTemplate = null;

public void setSessionFactory(SessionFactory sf) {
this.hibernateTemplate = new HibernateTemplate(sf);
}

public void delete(TblUser user) {
hibernateTemplate.delete(user);
}

public TblUser find(Integer id) {
return (TblUser) hibernateTemplate.get(TblUser.class, id);
}

public void insert(TblUser user) {
hibernateTemplate.save(user);
}

public void update(TblUser user) {
hibernateTemplate.update(user);
}
}

spring bean設定檔透過DataSource設定SessionFactory物件並"注入"到UserDAO物件


Demo程式
package idv.muchu.test.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringHibernateDemo {
/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("dao-config.xml");
IUserDAO userDAO = (IUserDAO)context.getBean("userDAO");
TblUser user = new TblUser();
user.setAge(15);
user.setName("mars");
userDAO.insert(user); //新增
TblUser mark = userDAO.find(1); //查詢
System.out.println("mark's age:" + mark.getAge());
mark.setAge(30);
userDAO.update(mark); //修改
System.out.println("mark's age:" + mark.getAge());
userDAO.delete(mark); //刪除
}
}

2008年7月26日 星期六

hibernate LazyInitializationException

hibernate 3 預設有啟動LazyInitialization
在Session.
load(Class theClass,Serializable id)時
還不會將資料庫中的資料載入到物件中,一直要到物件屬性被改變時才會載入,
但修改物件時Session必須處於open狀態,否則會丟出LazyInitializationException
如果在Session關閉後才要使用物件則可以使用Hibernate.initialize(rec_obj);
來先行載入資料庫的資料到物件中
如:
Session session = HibernateUtil.getSessionFactory().openSession();
User user = (User) session.load(User.class, new Integer(1));
Hibernate.initialize(user);

session.close();

Hibernate的Session物件有兩個:
org.hibernate.Session 及 org.hibernate.classic.Session
classic版是為了相容於Hibernate 2.x的物件,已半棄用,建議新的開發要使用
org.hibernate.Session

使用Hql進行查詢時可以一次查詢多個資料表的物件,只要把資料TO物件extends/implements同一個class/interface即可,如:
Man implements Human ...
Woman implements Human ...
同時查找Man 及 Woman的資料:
Session.find("from Human ...");

透過ThreadLocal讓多個Thread各自管理自己的Session物件範例:
public class HibernateUtil {
public static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
Session s = session.get();
if(s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = session.get();
if(s != null) {
s.close();
}
session.set(null);
}
}

2008年7月22日 星期二

debian下使用zhcon

沒有做任何設定直接執行zhcon會造成畫面錯亂當機的情型
只要在/boot/grub/menu.list檔案的最下面的kernel字串後加上vga=791再重新開機就可以了

title Debian GNU/Linux, kernel 2.6.18-4-k7
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-4-k7 root=/dev/hdd1 ro vga=791
initrd /boot/initrd.img-2.6.18-4-k7
savedefault

vga其他顯示模示代碼如下:
Screen 640x480 800x600 1024x768 1280x1024 1600x1200
Colors --------------------------- -------------------------------------------
256 | 769 771 773 775 796
32,768 | 784 787 790 793 797
65,536 | 785 788 791 794 798
16.8M | 786 789 792 795 799

2008年7月21日 星期一

virtualbox

下載:
http://www.virtualbox.org/wiki/Downloads

安裝:
#dpkg --install virtualbox_1.6.2-31466_Debian_etch_i386.deb

加入群組:
#usermod -G vboxusers -a muchu1983

設定Host key:
檔案 -> 偏好設定 -> 輸入

複製一份.vdi硬體檔:
VBoxManage clonevdi /mnt/hdb1/debian-vbox.vdi /mnt/hdb1/debian-vbox-v2.vdi
複製完成即可再建立一台新的虛擬機來使用新的硬碟檔

虛擬機之間的網路互通:
啟用虛擬機的新網卡eth1並設定為掛附到內部網路及給定相同的network name
再分別設定各別虛擬機的eth1 ip (例:192.168.1.100 & 192.168.1.200)
#ifconfig eth1 192.168.1.100

主端分享資料夾給客端電腦:
需先安裝客端額外功能 -
#sh /media/cdrom0/VboxLinuxAdditions.run
在主端vbox程式的 設定值 -> 分享資料夾 -> 加入新的分享資料夾
啟動客端電腦,mount 分享資料夾
#mount -t vboxsf share /mnt/share

2008年7月12日 星期六

java Thread wait() notify() notifyAll() 運作

.使用wait()、notify()、notifyAll()方法前,執行緒必需先獲得物
件鎖,也就是說,執行緒必需是處理物件的synchronized區段
中,該執行緒是處於Running狀態的。

.當執行緒在物件的synchronized區段中碰到了wait()方法,該執
行緒就必需釋放出該物件的Lock,並進入該物件的wait pool中
等待。

.執行的過程式可能會有多個執行緒因為碰到wait()方法而在wait
pool中等待。

..此時。如果某個使用該物件的執行緒碰到了notify()方法,那麼在
物件的wait pool中第一個碰到了wait()方法的執行緒就會被移到該
物件的lock pool中繼續等待取得物件鎖。

..而如果某個使用該物件的執行緒碰到了notifyAll()方法,那麼在物
件的wait pool中所有的執行緒就會被移到該物件的lock pool中,
而優先權最高的執行緒會先取得物件鎖。

2008年7月8日 星期二

Jaas Login module flag意義

      1) Required     - The LoginModule is required to succeed.
If it succeeds or fails, authentication still continues
to proceed down the LoginModule list.

此LoginModule一定要驗証成功整個Login程序才會通過,無論驗証成敗,均會繼續
進行下一個LoginModule驗証。

2) Requisite - The LoginModule is required to succeed.
If it succeeds, authentication continues down the
LoginModule list. If it fails,
control immediately returns to the application
(authentication does not proceed down the
LoginModule list).

此LoginModule一定要驗証成功整個Login程序才會通過,驗証成功,則繼續進行
下一個LoginModule驗証,若驗証失敗,則不繼續進行下一個LoginModule驗証,
驗証程式完成。
3) Sufficient - The LoginModule is not required to
succeed. If it does succeed, control immediately
returns to the application (authentication does not
proceed down the LoginModule list).
If it fails, authentication continues down the
LoginModule list.
此LoginModule不一定要驗証成功,若驗証成功,則繼續進行則不繼續進行下一個
LoginModule驗証,若驗証失敗,則繼續進行下一個LoginModule驗証,
4) Optional - The LoginModule is not required to
succeed. If it succeeds or fails,
authentication still continues to proceed down the
LoginModule list.
此LoginModule不一定要驗証成功,無論驗証成敗,均會進行下一個LoginModule驗証。

2008年7月6日 星期日

XFce4快捷鍵記錄檔位置

XFce4 的預設快捷鍵位置在
/usr/share/themes/Default/xfwm4/keythemerc

2008年6月30日 星期一

xfce新增圖示主題

先到http://www.xfce-look.org/下載想要的圖示
例如XXX.tar.gz
移到~/icons/並解壓縮開來 (如果沒有icons資料夾就自行mkdir)
~/icons/XXX/
即可在 Xfce設定管理程式 -> 使用者介面 -> 圖示主題 下
看到剛新增的圖示主題

2008年6月20日 星期五

JCR研究:jackrabbit

一。使用 svn checkout出jackrabbit的src code
svn co http://svn.apache.org/repos/asf/jackrabbit/trunk jackrabbit
二。進到checkout出來的根目錄,使用 maven 進行build
mvn install
三。完成建置後 maven 會在家目錄產生jackrabbit的jars:
${home}\.maven\repository\org.apache.jackrabbit\jars\jackrabbit-*-SNAPSHOT.jar

四。在classpath引入必要的jars
jcr的有:
jcr-1.0.jar
jackrabbit的有:
jackrabbit-api-1.5-SNAPSHOT.jar
jackrabbit-core-1.5-SNAPSHOT.jar
jackrabbit-jcr-commons-1.5-SNAPSHOT.jar
jackrabbit-spi-1.5-SNAPSHOT.jar
jackrabbit-spi-commons-1.5-SNAPSHOT.jar
jackrabbit-text-extractors-1.5-SNAPSHOT.jar
slf4j的有:
slf4j-api-1.3.0.jar
slf4j-simple-1.5.2.jar
其他:
commons-collections-3.1.jar
concurrent-1.3.4.jar
derby-10.2.1.6.jar
commons-io-1.4.jar
lucene-core-2.2.0.jar
PDFBox-0.7.3.jar
poi-3.0.2-FINAL-20080204.jar
tm-extractors-0.4.jar
poi-scratchpad-3.0.2-FINAL-20080204.jar
poi-contrib-3.0.2-FINAL-20080204.jar

五。第一個登入程式FirstHop
public static void main(String[] args) throws Exception {
// local repository
// System.setProperty("org.apache.jackrabbit.repository.home", "D:/jackrabbit-repos");
// Repository repository = new TransientRepository();
// http rmi repository
Repository repository = new URLRemoteRepository("http://192.168.1.57:-1/jackrabbit-webapp-1.5-SNAPSHOT/rmi");
// rmi repository
// Repository repository = new RMIRemoteRepository("//localhost/jackrabbit.repository");
Session session = repository.login(new SimpleCredentials("transtep", "".toCharArray()));
try {
String user = session.getUserID();
String name = repository.getDescriptor(Repository.REP_NAME_DESC);
System.out.println("Logged in as " + user + " to a " + name + " repository.");
Workspace workspace = session.getWorkspace();
Node rootNode = session.getRootNode();
// // 儲存資料
workspace.getNamespaceRegistry().registerNamespace("xsignage", "http://www.transtep.com/xsignage/1.0");
Node imageNode = rootNode.addNode("xsignage:image");
imageNode.setProperty("xsignage:type", "圖片");
imageNode.setProperty("xsignage:read", true);
imageNode.setProperty("xsignage:write", true);
Node jpegImage = imageNode.addNode("xsignage:jpeg");
jpegImage.setProperty("xsignage:yuffie", new FileInputStream(new File("./尤菲.jpg")));
session.save();
// 取出資料
Node imageNode2 = rootNode.getNode("xsignage:image");
System.out.println("type: " + imageNode2.getProperty("xsignage:type").getString());
System.out.println("read: " + imageNode2.getProperty("xsignage:read").getString());
System.out.println("write: " + imageNode2.getProperty("xsignage:write").getString());
Node jpegImage2 = imageNode2.getNode("xsignage:jpeg");
InputStream ins = jpegImage2.getProperty("xsignage:yuffie").getStream();
FileOutputStream pos = new FileOutputStream("./yuffie.jpg");
int read = -1;
while ((read = ins.read()) != -1) {
pos.write(read);
}
} finally {
session.logout();
}
}

2008年6月19日 星期四

從servlet上下載檔案的寫法

public void execute(HttpServletRequest req, HttpServletResponse res) {
PrintWriter out = null;
// 取得輸入參數
String did = req.getParameter("did");
String filename = req.getParameter("filename");
if (did == null) {// 無did
out.print("公文文號(did)為空值");
return;
} else if (filename == null) {// 無filename
out.print("檔案名稱(filename)為空值");
return;
}
// Dao
DocAttDao docAttDao = DocAttDao.getInstance();
TblDocattId id = new TblDocattId(Integer.parseInt(did), filename);
TblDocatt tblDocAtt = new TblDocatt(id);
tblDocAtt = (TblDocatt) docAttDao.get(tblDocAtt);
try {
res.setHeader("Pragma", ""); // HTTP 1.0
res.setHeader("Cache-Control", ""); // HTTP 1.1
if (tblDocAtt != null) {
String fileurl = tblDocAtt.getUrl();
String agent = req.getHeader("User-Agent");
if (agent.indexOf("MSIE") > -1) {
// encoding filename for IE
filename = URLEncoder.encode(filename, "utf-8");
} else {
filename = new BCodec().encode(filename);
}
// 下載檔案
res.setContentType("application/octet-stream;charset=utf-8");
res.setHeader("Content-Disposition", "attachment; filename = " + filename);
// 打開指定文件的stream
File file = new File(fileurl);
FileInputStream bis = new FileInputStream(file);
OutputStream bos = res.getOutputStream();
byte[] buff = new byte[1024];
int readCount = 0;
readCount = bis.read(buff);
while (readCount != -1) {
bos.write(buff, 0, readCount);
readCount = bis.read(buff);
}
if (bis != null)
bis.close();
if (bos != null)
bos.close();
} else {
res.getWriter().print("無此檔案");
}
} catch (Exception e) {
e.printStackTrace();
}

}

maven安裝

1.下載maven
2.解壓縮
3.新增M2_HOME環境變數到解壓縮目錄
4.新增M2_HOME\bin 路徑到Path環境變數
5.在console下運行svn --version檢查是否安裝成功

2008年6月18日 星期三

DTO DAO 物件

[轉載]http://www.javaworld.com.tw/jute/post/view?bid=44&id=85388&tpg=1&ppg=1&sty=3&age=0
DTO:Data Transfer Object
DAO:Data Access Object

由名稱來猜,DTO 就是類似用來作資料傳輸的 Java 類別,個人看過的寫法是寫成有 getter/setter 的 JavaBean
透過 DTO 可以很方便地將資料跨 tier 傳遞,且完整封裝

比如:

Servlet 產生 DTO 物件,將 Client 端輸入的資料透過 setter 寫進 DTO,呼叫企業邏輯處理元件時將 DTO 物件當成參數向後端傳遞

而後端的企業邏輯處理元件就可以透過 DTO 的 getter 取出所需要的資料,並進行運算
若後端運算完畢之後必須要將處理結果傳回 Client 端,也是透過 DTO 的 setter 設定新的值,並回傳給 Servlet

這整個過程當中都只需要 DTO 物件一個參數,像坐捷運一樣從前端一路傳到後端
不需要串一堆參數傳來傳去的,若後端須新增參數時也只需要更改 DTO 及用到相關 getter/setter 的程式碼即可,大部分程式都不需要變動


至於 DAO,是跟資料庫存取有關的類別
我看過的做法是將所有操作資料庫的動作都萃取集中起來寫成特定的公用類別
程式中若需要存取資料庫時一律透過 DAO 處理

這樣的好處是,當資料庫更換時,僅需抽換 DAO 即可,其他程式可以繼續使用,可以將應用程式與資料庫的耦合度降低

linux 下使用藍芽傳輸

1.安裝kdebluetooth套件
2.確定相關服務已啟動
sudo /etc/init.d/dbus start
sudo /etc/init.d/bluetooth start
3.啟動kbluetoothd
4.使用kbtobexclient程式傳送資料到手機上

ps.手機 -> pc 尚未試成功

2008年6月13日 星期五

java 的 enum

透過java列舉型別可以很容易的表達一些常數性質的資料
public enum ROLE {
CHANNEL, PLAYLIST, TERMINAL, CONTENT;
};
而使用列舉型別的values()方法可以取出所有的列舉常數陣列
public static void main(String[] args) {
for(ROLE role : ROLE.values()){
System.out.println(role);
}
}
同時列舉型別也可以自定所屬的成員和方法,更可以override toString()方法來自定常數的表示
public enum ROLE {
CHANNEL, PLAYLIST, TERMINAL, CONTENT;
private Integer id;
private String name;

public void setId(Integer id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return name + "(" + id + ")";
}
};

使用列舉型自定的方法:
public static void main(String[] args) {
for(ROLE role : ROLE.values()){
role.setId(4);
role.setName("頻道四號");
System.out.println(role);
}
}

2008年6月2日 星期一

使用URL post XML給server端的servlet

URL urlobj = new URL(servletUrl);
HttpURLConnection urlconn = (HttpURLConnection) urlobj.openConnection();
urlconn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8"); //<--注意編碼設定
urlconn.setDoOutput(true);
urlconn.setDoInput(true);
urlconn.setRequestMethod("POST");
PrintWriter urlpw = new PrintWriter(new OutputStreamWriter(new DataOutputStream(urlconn.getOutputStream()),"UTF-8")); //<--注意編碼設定
JAXBAgent jaxbAgent = new JAXBAgent();
urlpw.print(jaxbAgent.marshal(reqObj));
urlpw.flush();
urlpw.close();
BufferedReader urlbr = new BufferedReader(new InputStreamReader(new DataInputStream(urlconn.getInputStream()),"UTF-8")); //<--注意編碼設定
StringBuffer strbuf = new StringBuffer();
String line = null;
while (null != (line = urlbr.readLine())) {
strbuf.append(line);
}
Object resObj = jaxbAgent.unmarshal(pkgName, strbuf.toString());


//server端的Servlet也要使用
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
//來設定編碼,才不會有中文字亂碼的問題。