大家都知道Struts是一种基于MVC的结构,而这个MVC又怎么样理解呢?书上阐述的一般都很详细,而我的理解很直白,我们可以把业务逻辑放到每个JSP页面中,当你访问一个JSP页面的时候,就可以看到业务逻辑得到的结果,而把这些业务逻辑与HTML代码夹杂到了一起,一定会造成一些不必要的麻烦,可以不可以不让我们的业务逻辑和那些HTML代码夹杂到一起呢?多少得搀杂一些,那干脆,尽量少的吧,于是我们可以尝试着把业务逻辑的运算过程放到一个Action里,我们访问这个Action,之后Action执行业务逻辑,最后把业务逻辑的结果放到request中,并将页面请求转发给一个用于显示结果的jsp页面,这样,这个页面就可以少去很多的业务逻辑,而只是单纯的去显示一些业务逻辑计算结果的页面而已。这时的Action称为控制器,JSP页可以叫做视图了,而控制器操作的业务对象,无非就应该叫模型了!
从上面的话,我们来分析一下当我们要做一个分页时所需要的部分,而在这之前,我们先看看他们的执行过程吧,首先我们第一次请求访问一个页面,它会把所有记录的前N条显示给我们,之后计算是否有下一页,等类似的信息,当我们点下一页的时候,就获取下一页的信息,我们还可以添加一个搜索,比如我们用于显示学生的,可以安学生姓名查找,学号查找,班级查找。而对于显示的对象,我们一般也都会封装为javabean,所以用于放置查询结果的容器是不定的,而这时,我们就需要用泛型来提升我们的代码效率!
首先我们写一个用于分页显示的javabean:
package com.boya.subject.model;
import java.util.Vector;
public class Page<E>
{
private int current = 1; //当前页
private int total = 0; //总记录数
private int pages = 0; //总页数
private int each = 5; //每页显示
private int start = 0; //每页显示的开始记录数
private int end = 0; //每页显示的结束记录数
private boolean next = false; //是否有下一页
private boolean previous = false; //是否有上一页
private Vector<E> v = null;
//存放查询结果的容器
public Page( Vector<E> v ,int per)
{
this.v = v;
each = per;
total = v.size(); //容器的大小就是总的记录数
if ( total % each == 0 )
pages = total / each; //计算总页数
else
pages = total / each + 1;
if ( current >= pages )
{
next = false;
}
else
{
next = true;
}
if ( total < each )
{
start = 0;
end = total;
}
else
{
start = 0;
end = each;
}
}
public int getCurrent()
{
return current;
}
public void setCurrent( int current )
{
this.current = current;
}
public int getEach()
{
return each;
}
public void setEach( int each )
{
this.each = each;
}
public boolean isNext()
{
return next;
}
public void setNext( boolean next )
{
this.next = next;
}
public boolean isPrevious()
{
return previous;
}
public void setPrevious( boolean previous )
{
this.previous = previous;
}
public int getEnd()
{
return end;
}
public int getPages()
{
return pages;
}
public int getStart()
{
return start;
}
public int getTotal()
{
return total;
}
//获取下一页的对象们
public Vector<E> getNextPage()
{
current = current + 1;
if ( (current - 1) > 0 )
{
previous = true;
}
else
{
previous = false;
}
if ( current >= pages )
{
next = false;
}
else
{
next = true;
}
Vector<E> os = gets();
return os;
}
//获取上一页
public Vector<E> getPreviouspage()
{
current = current - 1;
if ( current == 0 )
{
current = 1;
}
if ( current >= pages )
{
next = false;
}
else
{
next = true;
}
if ( (current - 1) > 0 )
{
previous = true;
}
else
{
previous = false;
}
Vector<E> os = gets();
return os;
}
//一开始获取的
public Vector<E> gets()
{
if ( current * each < total )
{
end = current * each;
start = end - each;
}
else
{
end = total;
start = each * (pages - 1);
}
Vector<E> gets = new Vector<E>();
for ( int i = start; i < end; i++ )
{
E o = v.get( i );
gets.add( o );
}
return gets;
}
}
而对于按不同搜索,我们需要一个FormBean,一般的搜索,都是模糊搜索,搜索个大概,而且输入的信息中文的比重也会很大,所以,我把对中文字符的转换放到了这个BEAN里,在进行select * from * where like这样的查询时,如果是like ''这样就可以得到所有的记录了,我便用这个来对付没有输入查询关键字的情况,而like '%*%'可以匹配关键字,而%%也在这里添加上了!
package com.boya.subject.view;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class SearchForm extends ActionForm
{
private static final long serialVersionUID = 1L;
private String key;
private String from;
public String getFrom()
{
return from;
}
public void setFrom( String from )
{
this.from = from;
}
public void reset( ActionMapping mapping, HttpServletRequest req )
{
this.key = null;
}
public String getKey()
{
return key;
}
public void setKey( String key )
{
try
{
key = new String( key.getBytes( "iso-8859-1" ), "gb2312" );
}
catch ( UnsupportedEncodingException e )
{
e.printStackTrace();
}
this.key = "%" + key + "%";
}
public String getAny(){
return "%%";
}
}
前期都做好了,我现在就要开始访问这个Action了,可是这个控制器还没写呢!这里是代码
public class AdminUserAction extends AdminAction
{
private Vector<Student> ss; //用来装结果的容器
private Page<Student> ps;
//分页显示的PAGE对象
protected ActionForward executeAction( ActionMapping mapping,
ActionForm form, HttpServletRequest req, HttpServletResponse res )
throws Exception
{
if ( !isSupper( req ) )
{
return notSupper( res );//如果不是超级管理员怎么办?
}
Service service = getService();//获取业务逻辑
SearchForm sf = (SearchForm) form;//获取搜索FORM
String op = req.getParameter( "op" );//获取用户对页面的操作
String search = req.getParameter( "search" );//是否执行了搜索
Vector<Student> temp = null; //用于存放临时反馈给用户的结果容器
if ( op == null )//如果用户没有执行上/下一页的操作
{
if ( search != null )//用户如果执行了搜索
{
if ( sf.getFrom().equalsIgnoreCase( "class" ) )//如果是按班级查找
{
ss = service.getAllStudentBySchoolClassForAdmin( sf
.getKey() );//获取from的关键字
}
else if ( sf.getFrom().equalsIgnoreCase( "name" ) )//如果是按姓名查找
{
ss = service.getAllStudentByNameForAdmin( sf
.getKey() );
}
else if ( sf.getFrom().equalsIgnoreCase( "user" ) )//如果是按用户名查找
{
ss = service.getAllStudentByUserForAdmin( sf
.getKey() );
}
else
{
ss = service.getAllStudentBySnForAdmin( sf.getKey() );//按学号查找
}
form.reset( mapping, req );//重置搜索表单
}
else
{
ss = service.getAllStudentForAdmin( sf.getAny() ); //用户未执行查找就显示全部,
}
if ( ss != null && ss.size() != 0 )//如果查找不为空,有记录,那就创建一个分页对象
{
ps = new Page<Student>( ss, 10 );//将查询结果和每页显示记录数作为参数构件对象
temp = ps.gets();//并获取第一页
}
}
else//如果用户执行了操作
{
if ( op.equals( "next" ) )//操作是下一页
{
temp = ps.getNextPage();
}
if ( op.equals( "previous" ) )//操作是上一页
{
temp = ps.getPreviouspage();
}
}
req.setAttribute( "search", SelectUtil.studentSearch() );//把搜索用到的表单放到request中
req.setAttribute( "students", temp );//该页显示的学生
req.setAttribute( "page", ps );//分页对象
return mapping.findForward( "student" );//请求转发
}
}
用到SelectUtil中的代码如下:
/**
* 获取学生查找类别的select
* @return 学生查找类别
* 2006-5-17 9:06:12
*/
public static Vector<LabelValueBean> studentSearch()
{
Vector<LabelValueBean> s = new Vector<LabelValueBean>();
s.add( new LabelValueBean( "按学号查找", "sn" ) );
s.add( new LabelValueBean( "按班级查找", "class" ) );
s.add( new LabelValueBean( "按姓名查找", "name" ) );
s.add( new LabelValueBean( "按用户查找", "user" ) );
return s;
}
在看页面视图前先让我们看看Model吧,
public class Student extends User
{
private String sn;
private SchoolClass schoolClass;
//这里的班级做为了一种对象,我们在视图显示的时候就有了一层嵌套
public SchoolClass getSchoolClass()
{
return schoolClass;
}
public void setSchoolClass( SchoolClass schoolClass )
{
this.schoolClass = schoolClass;
}
public String getSn()
{
return sn;
}
public void setSn( String sn )
{
this.sn = sn;
}
public String getType()
{
return "student";
}
}
在了解了model后,还是看看视图吧,
先放个查询表单:
<html:javascript dynamicJavascript="true" staticJavascript="true" formName="SearchForm" />
<html:form action="/adminUser.do?search=true" onsubmit="return validateSearchForm(this)">
<html:select property="from" >
<html:options collection="search" property="value" labelProperty="label" />
</html:select>
<html:text property="key" size="16" maxlength="16"/>
<html:image src="images/search.gif"/>
</html:form>
由于模型中有嵌套,那么我们就将用到Nested标签,其实没有嵌套也可以使用这个标签,下面的是用于显示信息的,用迭迨器进行遍历request范围的students,你不安排范围,他会自动找到的,并把每次遍历的对象起名叫student,并作为层次的根元素,
<logic:iterate id="student" name="students">
<nested:root name="student">
<nested:nest property="schoolClass"><nested:write property="schoolClass"/></nested:nest>//寻找了student的schoolClass属性对象的schoolClass嵌套
<nested:write property="name"/> //student的名字
<nested:link page="/adminActions.do?method=deleteStudent" paramId="id" paramProperty="id" onclick="return window.confirm('您真的要删除吗?')">删除</nested:link>
</nested:root>
这里是显示分页对象的:
第<bean:write name="page" property="current" />页
共<bean:write name="page" property="pages" />页
//上一页是否存在
<logic:equal name="page" property="previous" value="true">
<html:link page="/adminUser.do?part=student&op=previous">
<font color="6795b4">上一页</font>
</html:link>
</logic:equal>
<logic:notEqual name="page" property="previous" value="true">上一页 </logic:notEqual>
//下一页是否存在
<logic:equal name="page" property="next" value="true">
<html:link page="/adminUser.do?part=student&op=next">
<font color="6795b4">下一页</font>
</html:link> </logic:equal>
<logic:notEqual name="page" property="next" value="true">下一页 </logic:notEqual>
共有<bean:write name="page" property="total" />条数据
</logic:iterate>
到这里不知道您看明白了多少,在我的这个JSP页里几乎没有任何的业务逻辑,这样的设计就比把HTML和JAVA搀杂在一起好了很多。