Wicket 1.4 开发手记(二)
一个通用的范例 (另带Filter)
作者:Steel.Ma
Mail:
steel.ma@139.com steel.ma@tom.com
MSN: Blog:
Motorola_8088@hotmail.com http://blog.sina.com.cn/steelma http://hi.csdn.net/iamsteelma
1
Steel.Ma技术笔记 wicket 1.4开发手记(二)
1 概述
很久没有写wicket的笔记了,本次写一个比较长的,通过一个通用的范例来展示如何快速开发wicket应用程序。
主要构思是,写一个最常见的典型应用,上部是查询条件区,下部是列表区,自动分页,然后带多选框,可以让用户自行选定记录,同时每条记录配一个连接,标示用户的操作。
以上为应用的构想,为了让这个应用更贴近现实,本人将引入filter机制,如果操作者没有登录过,则强制将页面指向login。
2 环境准备与基本配置
环境选型:
Tomcat 6.0.18 Wicket 1.4.6 Mysql 5 MyEclipse
我们选择做一个用户查询/列表应用。
Tomcat、 MyEclipse的配置方法,本文就不再赘述了,请参阅本人之前的各
个开发笔记。这次将借用我一个朋友的系统,制作一个名为phonefee的project。
然后在MySQL中制作一个Database(本处名字为mao),再创建一个tuser
表,并录入几条数据,内容如下:
2
Steel.Ma技术笔记 wicket 1.4开发手记(二)
说明:若usertype=9 则为超级用户,0为普通用户 配置连接池:
在WebRoot/META-IMF下,建立一个context.xml,如下图所示:
内容如下:
this to disable session persistence across Tomcat restarts type=\"javax.sql.DataSource\" driverClassName=\"com.mysql.jdbc.Driver\" url=\"jdbc:mysql://localhost:3306/mao\" username=\"root\" password=\"abcd1234\" maxActive=\"50\" maxIdle=\"10\" maxWait=\"-1\"/>
需要记得把MySQL的JDBC驱动引入project,过程略。
3 代码制作
3.1 概述
我们分析下,现在需要2个页面:一个登录页面,这里命名为Login;一个查询/列表页面,这里命名为List3,此外,还需要一个过滤器。
3.2 包结构配置
建立com.steelma.wicket、com.steelma.filter、com.steelma.sdo和com.steelma.object一共4个包。
com.steelma.wicket包用于存放wicket应用程序。 com.steelma.filter包用于存放过滤器
com.steelma.sdo包用于存放简单数据对象(simple data object),所谓的简单数据对象是我提出的一个概念,wicket中的表单程序在提交时,需要有一个model数据对象来存放提交的数据,因此需要做一些与页面表单的数据匹配的
4
Steel.Ma技术笔记 wicket 1.4开发手记(二)
简单的数据类,这些类我就定义为“简单数据对象”。简单数据对象,顾名思义,其实就是一些get和set方法了,与vo很像,但vo主要是针对数据实体或数据对象的,而简单数据对象主要是为了匹配表单,是的表单处理程序与页面解耦。
com.steelma.object包用于存放数据对象(data object),基本相当于vo。
3.3 数据对象制作
首先制作一个针对tuser表的数据对象 obj_user:
package com.steelma.object;
import java.io.*; import java.util.*; import java.sql.*;
import javax.naming.Context; //必须import
import javax.naming.InitialContext; //必须import import javax.sql.*; //DataSource 所在的包,必须import
public class obj_user {
private String UserID ; private String Password ; private String UserType ; private boolean IsVIP ; private boolean IsSelected ;
public void setPassword(String Password) {
public void setIsVIP(boolean IsVIP) {
public void setIsSelected(boolean IsSelected) {
5
this.UserID = UserID ;
public void setUserID(String UserID) {
}
this.Password = Password ;
}
this.IsVIP = IsVIP ;
}
this.IsSelected = IsSelected ;
}
Steel.Ma技术笔记 wicket 1.4开发手记(二)
public void setUserType(int UserType) {
switch(UserType) {
case 0 : this.UserType = \"普通用户\" ; break ; case 9 : this.UserType = \"超级用户\" ; break ; default : this.UserType = \"普通用户\" ; }
}
public String getUserID() {
public String getPassword() {
public boolean getIsVIP() {
public String getUserType() {
return this.UserType ; return this.IsVIP ; return this.Password ; return this.UserID ;
}
}
}
}
public boolean getIsSelected() {
return this.IsSelected ;
}
public boolean getUserByUserID(String UserID, String PSWD) {
boolean ret = false ;
String sSQL = \"select * from tuser where userid='\" + UserID + \"' And pswd = '\" + PSWD + \"'\" ;
try {
Context ctx = new InitialContext(); //获得数据源 DataSource ds = (DataSource) ctx.lookup(\"java:comp/env/jdbc/mysql\");
//获取连接
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement() ; ResultSet rs = stmt.executeQuery(sSQL) ; if (rs.next()){
ret = true ;
setUserID(rs.getString(\"userid\")) ;
6
Steel.Ma技术笔记 wicket 1.4开发手记(二)
setPassword(rs.getString(\"pswd\")) ; setUserType(rs.getInt(\"usertype\")) ; setIsVIP(rs.getBoolean(\"isvip\")) ;
} else { }
ret = false ; rs.close() ; stmt.close() ; conn.close() ; }
}
catch (Exception e) { }
return ret ;
System.out.print(e.getMessage()) ;
}
从上述代码可以看到,除了get和set方法之外,我还做一个方法:getUserByUserID,传入用户账号和密码,检测是否存在该用户。
此外还有2个sdo:
1、 login画面用的,传入用户名和密码
package com.steelma.sdo;
public class loginsdo { private String un ; private String pw ;
public void setun(String un) { }
public String getun() { }
public void setpw(String pw) { }
public String getpw() {
return this.pw ;
7
this.un = un ;
return this.un ;
this.pw = pw ;
}
Steel.Ma技术笔记 wicket 1.4开发手记(二)
}
2、 list3画面用的,传入用户名中含有的字符,以及用户类型
package com.steelma.sdo;
public class listsdo { }
private String UserType ; private String UserName ;
public String getUserType() {
public String getUserName() {
public void setUserType(String UserType) {
public void setUserName(String UserName) {
this.UserName = UserName ; this.UserType = UserType ; return this.UserName ; return this.UserType ;
}
}
}
}
3.4 Login制作
Login画面本来是很简单的,但为了测试带参数的wicket,因此这里将做2个构造器,一个是不带参数的默认构造器,另一个是带参数的构造器。
首先在com.steelma.wicket下创建一个html的页面模板,名字按规则,必须为login.html
8
Steel.Ma技术笔记 wicket 1.4开发手记(二)
然后制作login.java:
package com.steelma.wicket;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
import org.apache.wicket.PageParameters; import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel; import org.apache.wicket.util.string.Strings;
import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.markup.html.form.PasswordTextField; import org.apache.wicket.markup.html.form.RadioChoice; import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.upload.FileUploadField; import org.apache.wicket.markup.html.form.validation.*; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.util.lang.Bytes;
import org.apache.wicket.validation.validator.StringValidator; import com.steelma.sdo.loginsdo;
9
Steel.Ma技术笔记 wicket 1.4开发手记(二)
import com.steelma.object.*;
public class login extends WebPage { private String pw ; private String un ; @SuppressWarnings(\"unchecked\") //默认构造器 public login() { super() ; final loginsdo user = new loginsdo() ; this.add(new FeedbackPanel(\"feedback\")); Form form = new Form(\"form\ new CompoundPropertyModel(user)) { protected void onSubmit() { 提交按钮按下后的事件处理函数 //System.out.println(\"执行了!用户名为:\" + user.getun().toString() + \" 密码为:\" + user.getpw().toString()); //这里输出一个onSubmit是让开发人员得知这个方法确实被调用了 obj_user tuser = new obj_user() ; if (tuser.getUserByUserID(user.getun().toString(), user.getpw().toString())){ System.out.println(\"登录成功!!!\") ; HttpServletRequest req =
getWebRequestCycle().getWebRequest().getHttpServletRequest() ; HttpSession ses = req.getSession(true); //ses.putValue(\"username\ ses.setAttribute(\"username\ ; HttpServletResponse res =
getWebRequestCycle().getWebResponse().getHttpServletResponse(); try { res.sendRedirect(\"http://\"+req.getHeader(\"Host\")+\"/phonefee/mainframe.html\") ; } catch (IOException e) { // TODO Auto‐generated catch block e.printStackTrace(); } } else { System.out.println(\"登录失败...\") ; } } }; this.add(form);
10
Steel.Ma技术笔记 wicket 1.4开发手记(二)
TextField unTextField = new TextField(\"un\"); unTextField.setRequired(true); unTextField.add(StringValidator.lengthBetween(2,20)); TextField pwTextField = new TextField(\"pw\"); pwTextField.setRequired(true); form.add(unTextField) ; form.add(pwTextField) ; } //带参数的构造器 public login(PageParameters parameters) { super() ; final loginsdo user = new loginsdo() ; String yy = parameters.getString(\"un\") ; user.setun(yy) ; //用参数中的用户帐号,给sdo中的用户帐号赋值,这样就能将其写入页面 this.add(new FeedbackPanel(\"feedback\")); Form form = new Form(\"form\ new CompoundPropertyModel(user)) { protected void onSubmit() { obj_user tuser = new obj_user() ; if (tuser.getUserByUserID(user.getun().toString(), user.getpw().toString())){ System.out.println(\"登录成功!!!\") ; HttpServletRequest req =
getWebRequestCycle().getWebRequest().getHttpServletRequest() ; //获取HttpServletRequest HttpSession ses = req.getSession(true); //ses.putValue(\"username\ ses.setAttribute(\"username\ ; 在session中写值 HttpServletResponse res =
getWebRequestCycle().getWebResponse().getHttpServletResponse();//获取HttpServletResponse try { res.sendRedirect(\"../test\") ; //执行传统的页面跳转 } catch (IOException e) { // TODO Auto‐generated catch block e.printStackTrace(); } } else { System.out.println(\"登录失败...\") ; }
11
Steel.Ma技术笔记 wicket 1.4开发手记(二)
}
} };
this.add(form);
TextField unTextField = new TextField(\"un\"); unTextField.setRequired(true);
unTextField.add(StringValidator.lengthBetween(2,20));
TextField pwTextField = new TextField(\"pw\"); pwTextField.setRequired(true);
form.add(unTextField) ; form.add(pwTextField) ; }
最后记得按照wicket的规则,做一个loginapplication类,将其引出来:
package com.steelma.wicket;
import org.apache.wicket.protocol.http.WebApplication;
import com.steelma.wicket.login;
public class loginApplication extends WebApplication { }
public Class getHomePage() {
return login.class;
}
3.5 List3制作
List3应用,是一个最常见的应用,我们这么设计
1、 画面分为上下2部分,分为2个for
2、 上半部分是2个参数:用户账号中含有的字符串以及用户类别 3、 提交后,自动更新下部的用户列表
4、 下半部分,默认是全部用户列表,自动分页,每页3条记录 5、 每条记录前加一个select选择框(checkbox),以便标示操作者选定的记录
12
Steel.Ma技术笔记 wicket 1.4开发手记(二)
6、 每条记录后部加一个链接,直接表示哪条记录被点击了
7、 提交后,检测有哪些记录被选中了,然后调用login,传递一个参数过去
还是老规矩,先做一个html
然后,做list3的wicket:
package com.steelma.wicket;
13
Steel.Ma技术笔记 wicket 1.4开发手记(二)
import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.io.*; import java.util.*; import java.sql.*;
import javax.naming.Context; //必须import
import javax.naming.InitialContext; //必须import import javax.sql.*; //DataSource 所在的包,必须import
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
import org.apache.wicket.PageParameters; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel; import org.apache.wicket.util.string.Strings; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice; import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.markup.html.form.PasswordTextField; import org.apache.wicket.markup.html.form.RadioChoice; import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.upload.FileUploadField; import org.apache.wicket.markup.html.form.validation.*; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.list.PageableListView; import
org.apache.wicket.markup.html.navigation.paging.PagingNavigator; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.model.CompoundPropertyModel;
14
Steel.Ma技术笔记 wicket 1.4开发手记(二)
import org.apache.wicket.util.lang.Bytes;
import org.apache.wicket.validation.validator.StringValidator;
import com.steelma.sdo.listsdo; import com.steelma.sdo.loginsdo; import com.steelma.object.*; import com.steelma.wicket.login;
public class list3 extends WebPage{
Form one = new Form(\"one\", new CompoundPropertyModel(ttt)) {
protected void onSubmit() {
//info(\"好了!\") ; //拼SQL文的条件子句 TJ = \"\" ;
private Context ctx ; private DataSource ds ; private Connection conn ; private Statement stmt ; private ResultSet rs ;
private String pw ; private String un ;
private static List UserList = new ArrayList(); private static List UT = new ArrayList() ; private String TJ = \"\" ;
PageableListView ListView ;
@SuppressWarnings(\"unchecked\") public list3() {
super();
UT.clear() ; UT.add(\"超级用户\") ; UT.add(\"普通用户\") ;
final listsdo ttt = new listsdo() ; this.add(new FeedbackPanel(\"feedback\"));
System.out.println(\"ok !!!\");
System.out.println(\"用户账号含有:\" + ttt.getUserName()); System.out.println(\"用户类型为:\" + ttt.getUserType()); if (ttt.getUserName() != null) {
TJ += \" Where userid like '%\" + ttt.getUserName() + \"%'\" ;
15
Steel.Ma技术笔记 wicket 1.4开发手记(二)
}
if (!ttt.getUserType().equals(\"请选择\")) { }
if (ttt.getUserType().equals(\"超级用户\")) { TJ += \" where usertype = 9\" ; } else { }
TJ += \" where usertype = 0\" ;
if (ttt.getUserType().equals(\"超级用户\")) { TJ += \" And usertype = 9\" ; } else { }
TJ += \" And usertype = 0\" ;
} else if (!ttt.getUserType().equals(\"请选择\")) {
String sSQL = \"select * from tuser\" + TJ; System.out.println(sSQL) ;
UserList.clear() ; try {
//列表清除,以便重新刷新
ctx = new InitialContext(); //获得数据源
ds = (DataSource)
//获取连接
conn = ds.getConnection(); stmt = conn.createStatement() ; rs = stmt.executeQuery(sSQL) ; while (rs.next()){
//i++ ;
ctx.lookup(\"java:comp/env/jdbc/mysql\");
obj_user tuser = new obj_user() ;
tuser.setUserID(rs.getString(\"userid\")) ; tuser.setPassword(rs.getString(\"pswd\")) ; tuser.setUserType(rs.getInt(\"UserType\")) ;
}
catch (Exception e) { }
ListView.setModelObject(UserList) ;// 对应的列表model,实
16
}
UserList.add(tuser) ;
rs.close() ; stmt.close() ; conn.close() ;
System.out.print(e.getMessage()) ; System.out.println(\"ok, xxxx\") ;
Steel.Ma技术笔记 wicket 1.4开发手记(二)
现刷新
}
} ;
TextField un = new TextField(\"UserName\");
DropDownChoice pw = new DropDownChoice(\"UserType\", UT);
this.add(one) ;
one.add(un) ; one.add(pw) ;
//==我是分割线=以下为下半部分的处理程序
=======================================
UserList.clear() ; int i = 0 ;
//先查询出列表清单,然后循环赋值 String sSQL = \"select * from tuser\" + TJ; System.out.println(sSQL) ;
try {
ctx = new InitialContext();
//获得数据源
ds = (DataSource) ctx.lookup(\"java:comp/env/jdbc/mysql\"); //获取连接
conn = ds.getConnection(); stmt = conn.createStatement() ; rs = stmt.executeQuery(sSQL) ; UserList.clear() ; while (rs.next()){
i++ ;
obj_user tuser = new obj_user() ;
tuser.setUserID(rs.getString(\"userid\")) ; tuser.setPassword(rs.getString(\"pswd\")) ; tuser.setUserType(rs.getInt(\"UserType\")) ;
}
catch (Exception e) { }
17
}
UserList.add(tuser) ;
rs.close() ; stmt.close() ; conn.close() ;
System.out.print(e.getMessage()) ;
Steel.Ma技术笔记 wicket 1.4开发手记(二)
System.out.println(Integer.toString(i)) ;
ListView = new PageableListView(\"user\", UserList, 3) { //做一
个3条记录分页的表格
protected void populateItem(ListItem item) {
final obj_user tuser1 = (obj_user) item.getModelObject();
item.add(new CheckBox(\"selected\", new PropertyModel(tuser1, \"IsSelected\"))); //是否选中
item.add(new Label(\"id\", tuser1.getUserID()));
//用户账号
item.add(new Label(\"pw\",tuser1.getPassword()));
//密码
item.add(new Label(\"type\",tuser1.getUserType()));
//类型
item.add(new Link(\"link\") {
public void onClick() { //转向编辑页面
System.out.println(tuser1.getUserID() + \" 被点击了!\") ;
Form form = new Form(\"form\") {
public void onSubmit() {
// 执行删除操作 String l = \"xxx\" ;
int j ;
System.out.println(\"列表:\" + Integer.toString(UserList.size())) ;
for(j=0; j obj_user tmp = (obj_user) UserList.get(j) ; l += tmp.getUserID() + \" 被选中!\\n \" ; } } System.out.println(l) ; 18 } } }); }; Steel.Ma技术笔记 wicket 1.4开发手记(二) //login lg = new login() ; PageParameters pre = new PageParameters(); pre.put(\"un\", \"Administrator\"); this.add(form) ; //分页 } this.setResponsePage(login.class, pre) ; }; form.add(ListView); form.add(new PagingNavigator(\"navigator\", ListView)); 组件 } } 以上完成后,记得再做一个list2application将其引出。 3.6 Filter制作 在前面的login画面中,我们向session中写入了一个名为“username”的值,本filer就是检测session中是否存在这个值,如果不存在,就自动将页面跳转到Login画面上。 Filter在之前的开发笔记中已经有介绍,本次再专门拉出来说,是因为这里要配置成对多种资源经过过滤,之前是只对jsp文件一种资源,具体的配置方法见第四部分。 本应用的Filter的内容与之前几乎没有区别: package com.steelma.filter; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; 19 Steel.Ma技术笔记 wicket 1.4开发手记(二) import javax.servlet.FilterChain; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpServletResponse; public class rightfilter implements Filter { public void destroy() { } //从session里取的用户名信息 String username = (String) session.getAttribute(\"username\"); //判断如果没有取到用户信息,就跳转到登陆页面 if (username == null || \"\".equals(username)) { //跳转到登陆页面 //System.out.print(\"OK ! 过滤器生效!\") ; } else { //已经登陆,继续此次请求 chain.doFilter(request,response); } } public void doFilter(ServletRequest request, ServletResponse FilterChain chain) throws IOException, HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; HttpSession session = req.getSession(true); response, ServletException { public void init(FilterConfig filterConfig) throws } ServletException { res.sendRedirect(\"http://\"+req.getHeader(\"Host\")+\"/phonefee/login\"); } 20 Steel.Ma技术笔记 wicket 1.4开发手记(二) 4 部署、配置 Wicket的部署与配置非常简单,本质上与Servlet几乎没有区别, 而且在开发手记(一)中已经有详细的描述了,这里主要要提一下的是Filer的多资源过滤配置。 Filter多资源过滤配置起始也很简单,定义还是一样定义,但在filter-mapping时,将每种需要过滤得资料都filter-mapping即可,以下即是web.xml文件的内容: 21 Steel.Ma技术笔记 wicket 1.4开发手记(二) 22 Steel.Ma技术笔记 wicket 1.4开发手记(二) 23 Steel.Ma技术笔记 wicket 1.4开发手记(二) 5 测试 用MyEclipse的工具发布到tomcat 6,并启动tomcat后,直接访问: http://localhost:8080/phonefee/list3,由于没有登陆过,因此过滤器会自动引导页 面到http://localhost:8080/phonefee/login 24 Steel.Ma技术笔记 wicket 1.4开发手记(二) 用户登录后,再访问http://localhost:8080/phonefee/list3 : 我们在上半部分的用户账号中输入“t”,然后用户类型选择“普通用户”,提交后,下半部分的列表自动刷新,可以见到,现在只有1页了: 25 Steel.Ma技术笔记 wicket 1.4开发手记(二) 我们在账号“steel”的“编辑”链接上点击了一下,控制台可以看到相应的处理: 然后,我们选择“scott”和“test”2个帐号: 26 Steel.Ma技术笔记 wicket 1.4开发手记(二) 提交后,我们看到console中,系统准备地识别出了使用者钩选的记录: 而系统也会自动调转到login画面,并穿过去一个值为“Administrator”的参数,login的那个带参数的构造器将自动识别,然后将这个值写入画面: 27 因篇幅问题不能全部显示,请点此查看更多更全内容