SSH2框架设计---代码整合
2017-02-07 08:42
393 查看
SSH2框架对实体层和表现层进行了很好的封装,并通过Spring注入的方式解决了各层之间的耦合,本文章对该框架部分实现进行代码整合,提高复用率。
首先我们了解一下SSH2框架的基本流程:
常见的代码整合部分如下图:
我们按照开发从前台到后台的顺序进行分析:
最常见的应用是公共引用和组件部分进行抽取,jsp提供了一种.jspf格式的公共抽取文件,在jsp页面引用该文件时添加:
<%@ includefile="/WEB-INF/jsp/public/commons.jspf"%>
例如分页组件的提取:pageView.jspf
解决方法:利用反射
2.2 统一注入service,声明公共变量,如:pageNum,pageSize
我们经常会创建一些监听器对对象进行监听,如在页面初始化时,监听初始化对象,加载用户的所有权限地址,用以判断action的请求能否进入系统。
在web.xml配置文件中进行配置:
<!-- 配置Spring的用于初始化容器对象的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
【 3.2】 拦截器:interceptor
在权限控制系统中,往往需要验证所有的用户action请求,这时需要我们建立自定义拦截器拦截所有的用户请求,判断用户具有该请求权限方可进入,否则无法完成系统操作:
在struts.xml配置文件中声明拦截器,且放在默认拦截器的最开始:
【3.3】 加载树状列表
树状显示结构在系统的目录显示中非常常用,我们可以采用递归方式进行实现,例如下面是部门显示的树状结构:
但存在两个问题:
1)在action输入多个空格,在jsp页面总是显示一个,这样使用全角空格即可解决。
2)新添加节点后树状结构会发生乱序,这是因为在定义struts的一对多映射结构时,指定children为set属性,而set往往是无序的,解决方式:在映射文件中添加order-by属性设定,例如:order-by="id ASC"
【3.4 】queryHelper(分页+过滤查询条件)
分页显示在系统是经常使用的,但是如果添加搜索条件,并按照多个搜索条件进行升序或者降序排列,往往在拼接Hql语句时涉及多个if判断,这样,我们将拼接Hql语句的部分进行代码抽取,简化程序开发人员在Hql拼接方面的难度。
这样,在action中用户拼接所有可能发生的情况时,就得到了简化:
首先我们了解一下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接口(统一把实体类当成页面数据的收集对象,这也是为什么在struts2的jsp页面中可以直接写实体属性的原因),但是存在问题:如何获得泛型集合的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"); // 准备数据:topPrivilegeList List<Privilege> topPrivilegeList = privilegeService.findTopList(); sce.getServletContext().setAttribute("topPrivilegeList", topPrivilegeList); System.out.println("------------> 已准备数据 <------------"); //准备数据:allPrivilegeUrls Collection<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 { @Override public 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);
【总结】
在系统设计过程中,抽象是面向对象设计的第一步,将公共代码进行抽象封装,以组件化的形式存在,不但提高代码复用率,降低耦合,在业务变更时,也可以快速整理。相关文章推荐
- 应用框架的设计与实现——.NET平台(9 消息队列服务代码分析)
- SSH2框架设计,最可怕的是没有异常报告
- SSH2之框架整合
- 基于.Net3.5 Nhibernate 整合 Extjs 框架设计
- 基于WPF系统框架设计(6)-整合MVVM框架(Prism)
- 应用框架的设计与实现——.NET平台4.2代码测试问题解决
- ASP.NET Web开发框架之五 设计时支持,代码生成,数据字典 ExtAspNet控件扩展
- ssh2框架整合注意事项
- 基于WPF系统框架设计(5)-Ribbon整合Avalondock 2.0实现多文档界面设计(二)
- 整合SSH2框架详细步骤
- 在ssh2整合框架中,客户端使用jquery validate ajax验证用户名是否重复时,出现问题。 请指教!
- 框架底层综合+快速开发+代码重用框架-设计(Model层)
- ASP.NET Web开发框架之五 设计时支持,代码生成,数据字典 ExtAspNet控件扩展
- 一个通用的单元测试框架的思考和设计08-实现篇-在testcase代码中执行sql语句
- 『框架设计(第2版)CLR Via C#』学习笔记(002)——将托管代码合并到程序集
- 框架底层综合+快速开发+代码重用框架-设计(Dao层)
- j2ee 设计框架 ibatis+spring+struts整合应用实例
- ssh三大框架,三层架构 整合测试!完整分页代码,JdbcTemplate等测试,存储过程调用,留着以后复习吧
- ssh2框架整合
- 共享一份C#数据库持久层框架设计思路及其部分代码(原创)