SSH2框架设计---代码整合

来源:互联网 发布:java实现多张图片上传 编辑:程序博客网 时间:2024/05/22 02:21

         SSH2框架对实体层和表现层进行了很好的封装,并通过Spring注入的方式解决了各层之间的耦合,本文章对该框架部分实现进行代码整合,提高复用率。


       首先我们了解一下SSH2框架的基本流程:



         常见的代码整合部分如下图:




        我们按照开发从前台到后台的顺序进行分析:


        【1.jsp页面整合】

   

        最常见的应用是公共引用和组件部分进行抽取,jsp提供了一种.jspf格式的公共抽取文件,在jsp页面引用该文件时添加:

<%@ includefile="/WEB-INF/jsp/public/commons.jspf"%>


例如分页组件的提取:pageView.jspf

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%@ taglib prefix="s" uri="/struts-tags" %><div id=PageSelectorBar><div id=PageSelectorMemo>页次:${currentPage}/${pageCount}页  每页显示:${pageSize}条  总记录数:${recordCount}条</div><div id=PageSelectorSelectorArea><a href="javascript:gotoPage{1}" title="首页" style="cursor: hand;"><img src="${pageContext.request.contextPath}/style/blue/images/pageSelector/firstPage.png"/></a><s:iterator begin="%{beginPageIndex}" end="%{endPageIndex}" var="num"><s:if test="#num==currentPage"><!-- 当前页 --><span class="PageSelectorNum PageSelectorSelected">${num}</span></s:if><s:else><!-- 非当前页 --><span class="PageSelectorNum" style="cursor: hand;" onClick="gotoPage(${num});">${num }</span></s:else></s:iterator><a href="javascript:gotoPage(${pageCount})" title="尾页" style="cursor: hand;"><img src="${pageContext.request.contextPath}/style/blue/images/pageSelector/lastPage.png"/></a>转到:<select onchange="gotoPage(this.value)" id="_pn"><s:iterator begin="1" end="%{pageCount}" value="num"><option value="${num}">${num}</option></s:iterator></select><script type="text/javascript">$("#_pn").val("${currentPage}");</script></div></div><script type="text/javascript">/* function gotoPage(pageNum){window.location.href="forum_show.action?id=${id}&pageNum="+pageNum;} */function gotoPage(pageNum){$(document).forms[0].apend("<input type='hidden' name='pageNum' value='"+pageNum+"'>");document.forms[0].submit();}</script>

2. action整合


【2.1】统一实现ModelDriven接口(统一把实体类当成页面数据的收集对象,这也是为什么在struts2jsp页面中可以直接写实体属性的原因),但是存在问题:如何获得泛型集合的Class属性?


  解决方法:利用反射

//定义class:private Class<T> clazz=null;  //TODO:无法获得T的class类型//类设置为abastract类型//在构造函数利用反射技术获得类型public BaseDaoImpl(){//使用反射技术获得泛型T的类型ParameterizedType pt=(ParameterizedType) this.getClass().getGenericSuperclass();  //获取属性类型this.clazz=(Class<T>)pt.getActualTypeArguments()[0];System.out.println("clazz---->>"+clazz);}

      2.2 统一注入service,声明公共变量,如:pageNum,pageSize


3. Utils--工具方法


       【3.1】 监听器:listener

       我们经常会创建一些监听器对对象进行监听,如在页面初始化时,监听初始化对象,加载用户的所有权限地址,用以判断action的请求能否进入系统。

       
public class InitListener implements ServletContextListener {public void contextInitialized(ServletContextEvent sce) {// 获取容器与相关的Service对象ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());PrivilegeService privilegeService = (PrivilegeService) ac.getBean("privilegeServiceImpl");// 准备数据:topPrivilegeListList<Privilege> topPrivilegeList = privilegeService.findTopList();sce.getServletContext().setAttribute("topPrivilegeList", topPrivilegeList);System.out.println("------------> 已准备数据 <------------");//准备数据:allPrivilegeUrlsCollection<String> allPrivilegeUrls = privilegeService.findAllPrivilegeUrls();sce.getServletContext().setAttribute("allPrivilegeUrls", allPrivilegeUrls);System.out.println("------------> 已准备数据 <------------");}

        在web.xml配置文件中进行配置:

       <!-- 配置Spring的用于初始化容器对象的监听器 -->
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

      【 3.2】  拦截器:interceptor

       在权限控制系统中,往往需要验证所有的用户action请求,这时需要我们建立自定义拦截器拦截所有的用户请求,判断用户具有该请求权限方可进入,否则无法完成系统操作:

       
public class CheckPrivilegeInterceptor extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation invocation) throws Exception {//准备user数据User user=(User) ActionContext.getContext().getSession().get("user");//准备要拦截的url地址String namespace=invocation.getProxy().getNamespace();String actionName=invocation.getProxy().getActionName();String privUrl=namespace+actionName;//判断是否已经登录,判断是否是去登录,是则放行,否则返回登录if(user==null){if(privUrl.startsWith("/user_login")){return invocation.invoke();}else{return "loginUI";}}else{//如果登录,则判断权限if(user.hasPrivilegeByUrl(privUrl)){return invocation.invoke();}else{return "noPrivilegeError";}}}}

         在struts.xml配置文件中声明拦截器,且放在默认拦截器的最开始:

<interceptors>    <!-- 声明拦截器 -->    <interceptor name="checkPrivilege" class="cn.itcast.oa.util.CheckPrivilegeInterceptor"></interceptor>        <!-- 重新定义默认的拦截器栈 -->    <interceptor-stack name="defaultStack">    <interceptor-ref name="checkPrivilege"></interceptor-ref>    <interceptor-ref name="defaultStack"></interceptor-ref>    </interceptor-stack>    </interceptors>

       【3.3】  加载树状列表

       树状显示结构在系统的目录显示中非常常用,我们可以采用递归方式进行实现,例如下面是部门显示的树状结构:
public class departmentUtils {public static List<Department> getAllDepartments(List<Department> topList) {List<Department> list=new ArrayList<Department>();walkGetAllDepartment("┝",topList,list);return list;}public static void walkGetAllDepartment(String prox,Collection<Department> topList,List<Department> list){for(Department top:topList){Department department=new Department();department.setId(top.getId());department.setName(prox+top.getName());list.add(department);walkGetAllDepartment("  "+prox,top.getChildren(),list);}}}

      但存在两个问题:

      1)在action输入多个空格,在jsp页面总是显示一个,这样使用全角空格即可解决。

      2)新添加节点后树状结构会发生乱序,这是因为在定义struts的一对多映射结构时,指定children为set属性,而set往往是无序的,解决方式:在映射文件中添加order-by属性设定,例如:order-by="id ASC"

     【3.4 】queryHelper(分页+过滤查询条件)

      分页显示在系统是经常使用的,但是如果添加搜索条件,并按照多个搜索条件进行升序或者降序排列,往往在拼接Hql语句时涉及多个if判断,这样,我们将拼接Hql语句的部分进行代码抽取,简化程序开发人员在Hql拼接方面的难度。

      
public class QueryHelper {private String fromClause; //From子句private String whereClause=""; //where子句private String orderByClause=""; //orederby子句private List<Object> parameters=new ArrayList<Object>();/** * 生成from子句 *  * @param clazz * @param alias */public QueryHelper(Class clazz,String alias){fromClause="From "+clazz.getSimpleName()+" " +alias;}/** * 添加where子句 *  * @param condition * @param params * @return */public QueryHelper addCondition(String condition,Object... params){if(whereClause.length()==0){whereClause=" where "+condition;}else{whereClause+=" and "+condition;}if(params!=null){for(Object p:params){parameters.add(p);}}return this;}/** * 如果第一个参数为true,则拼接where子句 *  * @param append * @param condition * @param params * @return */public QueryHelper addCondition(boolean append,String condition,Object... params){if(append){addCondition(condition,params);}return this;}/** * 添加orderBy属性 *  * @param propertyName * @param asc * @return */public QueryHelper addOrderProperty(String propertyName,boolean asc){if(orderByClause.length()==0){orderByClause=" order by "+propertyName+" "+(asc ?"ASC":"DESC");}else{orderByClause+=","+propertyName+" "+(asc? "ASC":"DESC");}return this;}/** * 判断是否要添加orderby属性 *  * @param append * @param propertyName * @param asc * @return */public QueryHelper addOrderProperty(boolean append,String propertyName,boolean asc){if(append){addOrderProperty(propertyName,asc);}return this;}/** * 获取用于生成查询数据列表的HQL语句 * @return */public String getListQueryHql(){return fromClause+whereClause+orderByClause;}/** * 获取用于生成查询总记录数的HQL语句 * @return */public String getCountQueryHql(){return "select count(*) "+fromClause+whereClause;}/** * 获取参数列表 *  * @return */public List<Object> getParameters(){return parameters;}/** * 通过prearePageBean将数据放入值栈中 * @param service * @param pageNum * @param pageSize */public void preparePageBean(DaoSupport<?> service,int pageNum,int pageSize){PageBean pageBean =service.getPageBean(pageNum, pageSize, this);ActionContext.getContext().getValueStack().push(pageBean);}}

       这样,在action中用户拼接所有可能发生的情况时,就得到了简化:

new QueryHelper(Topic.class,"t")//过滤条件.addCondition("t.forum=?", forum)  //查询的论坛实体.addCondition((viewtype==1),"t.type=?", Topic.TYPE_BEST)  //是否为精帖//排序条件.addOrderProperty((orderBy==1), "t.lastUpdateTime",asc)  //是否按照最后更新时间排序.addOrderProperty((orderBy==2), "t.postTime", asc)   //是否按照发布时间排序.addOrderProperty((orderBy==3),"t.replyCount" ,asc)  //是否按照回复数量排序.addOrderProperty((orderBy==0),"(CASE t.type WHEN 2 THEN 2 ELSE 0 END)", false).addOrderProperty((orderBy==0),"t.lastUpdateTime",false).preparePageBean(topicService, pageNum, pageSize);

【总结】

      在系统设计过程中,抽象是面向对象设计的第一步,将公共代码进行抽象封装,以组件化的形式存在,不但提高代码复用率,降低耦合,在业务变更时,也可以快速整理。

   



0 0
原创粉丝点击