----------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处] 
文章出处:http://blog.csdn.net/sdksdk0/article/details/52506671
作者:朱培      ID:sdksdk0      邮箱: zhupei@tianfang1314.cn   

--------------------------------------------------------------------------------------------

最近在做的是一个通过Struts2、Hibernate、spring框架整合做的一个CRM系统,整体开发比较简单,就是细节的地方处理还是要花费一定的功夫,我主要负责的是人事管理(包括部门管理、职务管理、员工基本信息管理)、教学管理(班级管理、课程类别管理)、系统设置(修改密码、登录、退出)。整体功能比较简单,适合一般性开发。涉及的技术要点就是通过HQL来进行数据的增删改查、部门-职务级联、分页、通过struts进行文件上传下载等。只不过有个别的地方还是花费了几个小时。

首先是对整体的开发环境的搭建:

通过分模块开发来处理,框架的使用时分为了struts和spring,不同的模块的struts的命名也不同,spring也一样,同时hibernate放到相应的实体bean的文件夹下面。

在开发中我们都有很多地方用到了Dao和DaoImpl,所以我们可以将其抽取出来,作为一个基本的Dao,然后让其他用到的类去集成这个基础的dao即可,这样大大减少了开发的代码。

在BaseDao中我们可以写好常用的几种方法:

//通用dao接口
public interface BaseDao<T> {
//保存
public void save(T t); //更新
public void update(T t); //删除
public void delete(T t); //保存或更新
public void SaveOrUpdate(T t); //查询所有
public List<T> findAll(); //条件查询
public List<T> findAll(String condition,Object... params); //离线查询
public List<T> findAll(DetachedCriteria detachedCriteria); //分页
public List<T> findAllByPage(int startIndex,int pageSize); //分页的总记录数
public int getTotalRecode(); //查找
T findById(Serializable serializable); }

然后我们需要一个DaoImpl去实现这个公共dao的方法:

public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T>{

	private Class daoImplClass;
public BaseDaoImpl() {
//运行时,通过反射获得 泛型信息的实际内容
/// * 运行时,this表示当前运行类(及子类的实例对象)
//1 获得被参数化类型 ,例如:BaseDaoImpl<CrmPost>
ParameterizedType paramType = (ParameterizedType) this.getClass().getGenericSuperclass();
//2 获得实例参数
daoImplClass = (Class) paramType.getActualTypeArguments()[0]; } @Override
public void save(T t) {
this.getHibernateTemplate().save(t);
} @Override
public void update(T t) {
this.getHibernateTemplate().update(t);
} @Override
public void delete(T t) {
this.getHibernateTemplate().delete(t);
} @Override
public void SaveOrUpdate(T t) {
this.getHibernateTemplate().saveOrUpdate(t);
} @Override
public List<T> findAll() {
return this.getHibernateTemplate().find("from " + daoImplClass.getName());
} @Override
public List<T> findAll(String condition, Object... params) {
String hql = "from " + daoImplClass.getName() + " where 1=1 " + condition;
return this.getHibernateTemplate().find(hql,params);
} public List<T> findAll(DetachedCriteria detachedCriteria) {
return this.getHibernateTemplate().findByCriteria(detachedCriteria);
} @Override
public List<T> findAllByPage(int startIndex, int pageSize) {
String hql = "from " + daoImplClass.getName();
return this.getHibernateTemplate().execute(new PageHibernateCallBack(hql, startIndex, pageSize));
} @Override
public int getTotalRecode() {
List<Long> list = this.getHibernateTemplate().find("select count(*) from " + daoImplClass.getName());
return list.get(0).intValue();
} @Override
public T findById(Serializable oid) {
List<T> allT=this.getHibernateTemplate().find(" from "+daoImplClass.getName()+" where id=? ",oid);
if(allT !=null && allT.size()==1){
return allT.get(0);
}
return null;
} /**
* 通过编写回调实现分页
*/
class PageHibernateCallBack implements HibernateCallback<List<T>> { private String hql; //查询hql语句
private Object[] params; //对应实际参数
private int firstResult; //分页开始索引
private int maxResults; //分页每页显示个数 public PageHibernateCallBack(String hql,
int firstResult, int maxResults ,Object... params) {
super();
this.hql = hql;
this.params = params;
this.firstResult = firstResult;
this.maxResults = maxResults;
} @Override
public List<T> doInHibernate(Session session) throws HibernateException,
SQLException {
// 1 创建query
Query queryObject = session.createQuery(hql);
// 2 封装参数
if (params != null) {
for (int i = 0; i < params.length; i++) {
queryObject.setParameter(i, params[i]);
}
}
// 3 分页
if (firstResult >= 0) {
queryObject.setFirstResult(firstResult);
}
if (maxResults > 0) {
queryObject.setMaxResults(maxResults);
}
//4 查询所有
return queryObject.list();
} } }

接下来我们就可以愉快的使用这些封装好的方法了

例如我们的员工信息管理模块中:

页面效果如下:

public interface  LessontypeDao  extends BaseDao<CrmLessontype>{

}

实现方法:

public class LessontypeDaoImpl extends  BaseDaoImpl<CrmLessontype>  implements LessontypeDao{

}

然后就是service进行处理:

public interface  LessontypeService {

	PageBean<CrmLessontype>  findAllPage(int pageNum,int pageSize);

	List<CrmLessontype> findAll();

	CrmLessontype findById(String lessonTypeId);

	void addOrEditLessontype(CrmLessontype model);

}

实现方法:

这里使用了一个分页查询的功能。

public class LessontypeServiceImpl implements LessontypeService {

	private LessontypeDao lessontypeDao;
public void setLessontypeDao(LessontypeDao lessontypeDao) {
this.lessontypeDao = lessontypeDao;
} @Override
public PageBean<CrmLessontype> findAllPage(int pageNum, int pageSize) { //1 查询数据库,获得总记录数
int totalRecord = lessontypeDao.getTotalRecode();
//2 分页数据
PageBean<CrmLessontype> pageBean = new PageBean<CrmLessontype>(pageNum, pageSize, totalRecord); //3 查询分页结果
pageBean.setData(lessontypeDao.findAllByPage(pageBean.getStartIndex(), pageSize)); return pageBean;
} @Override
public List<CrmLessontype> findAll() {
return lessontypeDao.findAll();
} @Override
public CrmLessontype findById(String lessonTypeId) { return lessontypeDao.findById(lessonTypeId);
} @Override
public void addOrEditLessontype(CrmLessontype model) {
lessontypeDao.SaveOrUpdate(model); } }

接下来就需要把我们的service交由spring来管理了,在applicationContext-lessontype.xml中

	<bean id="lessontypeService"  class="cn.tf.lessontype.service.impl.LessontypeServiceImpl">
<property name="lessontypeDao" ref="lessontypeDao"></property>
</bean> <bean id="lessontypeDao" class="cn.tf.lessontype.dao.impl.LessontypeDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>

然后我们可以看到前台页面是:

<table width="97%" border="1" >

  <tr class="henglan" style="font-weight:bold;">
<td width="14%" align="center">名称</td>
<td width="33%" align="center">简介</td>
<td width="13%" align="center">总学时</td>
<td width="18%" align="center">收费标准</td>
<td width="11%" align="center">编辑</td>
</tr> <s:iterator value="pageBean.data">
<tr class="tabtd1">
<td align="center"><s:property value="lessonName"/> </td>
<td align="center"><s:property value="remark"/></td>
<td align="center"><s:property value="total"/></td>
<td align="center"><s:property value="lessonCost"/></td>
<td width="11%" align="center">
<s:a namespace="/" action="lessontypeAction_addOrEditUI">
<s:param name="lessonTypeId" value="lessonTypeId"></s:param>
<img src="${pageContext.request.contextPath}/images/button/modify.gif" class="img"/>
</s:a>
</td>
</tr>
</s:iterator>
</table>
<table border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td align="right">
<p:page url="${pageContext.request.contextPath}/lessontypeAction_findAll" data="${pageBean}" />
</td>
</tr>
</table>

所以这里我们可以使用的action。所以我们需要在struts中进行配置:

    <package name="lessontype" namespace="/" extends="common">
<action name="lessontypeAction_*" class="cn.tf.lessontype.action.LessontypeAction" method="{1}">
<result name="findAll" >/WEB-INF/pages/lessontype/listLessontype.jsp</result>
<result name="addOrEditUI">/WEB-INF/pages/lessontype/addOrEditCourseType.jsp</result>
<result name="addOrEdit" type="redirectAction">lessontypeAction_findAll</result>
</action> </package>

action要跳转的类,说到这里,我们还可以对action进行一些封装,毕竟使用action也是非常多的:

public class BaseAction<T> extends ActionSupport  implements ModelDriven<T>{

	public BaseAction(){
try {
ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass();
Class<T> crmClass=(Class<T>) parameterizedType.getActualTypeArguments()[0];
t=crmClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} private T t; @Override
public T getModel() {
return t;
} //注入使用到service //分页数据
private int pageNum;
private int pageSize=2;
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
} //简化值栈操作
public void set(String key,Object o){
ActionContext.getContext().getValueStack().set(key,o);
} public void push(Object o){
ActionContext.getContext().getValueStack().push(o);
} public void put(String key,Object value){
ActionContext.getContext().put(key,value);
} public void putSession(String key,Object value){
ActionContext.getContext().getSession().put(key, value);
} }

然后我们就来愉快的引用一下吧:

public class LessontypeAction  extends BaseAction<CrmLessontype> {

		private CrmLessontype crmLessontype = new CrmLessontype();
@Override
public CrmLessontype getModel() {
return this.crmLessontype;
}
//2 service
private LessontypeService lessontypeService;
public void setLessontypeService(LessontypeService lessontypeService) {
this.lessontypeService = lessontypeService;
} //3 分页数据
private int pageNum;
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
private int pageSize = 5 ; /**
* 查询所有--分页
* @return
*/
public String findAll(){ PageBean<CrmLessontype> pageBean = this.lessontypeService.findAllPage(pageNum, pageSize); this.set("pageBean", pageBean); return "findAll";
} //打开添加或修改页面
public String addOrEditUI(){ CrmLessontype findLessontype=this.lessontypeService.findById(this.getModel().getLessonTypeId());
this.push(findLessontype); return "addOrEditUI";
} public String addOrEdit(){
this.lessontypeService.addOrEditLessontype(this.getModel());
return "addOrEdit";
} }

这样的话整个开发流程就完成了。接下来的就是很多类似的操作了。整体来说是很简单的,当然,虽然简单还是需要花费时间的哈!

例如我在修改员工信息整理的时候,就遇到了这个密码更新的问题。

我最开始是在这里把密码显示出来的,然后一更新,坏了,把加密后的数据又加密一次存进去了,因为我这里这个密码是通过md5加密处理了,所以回显出来也没有多大的意义,毕竟md5密码不能解密!既然不显示那么我密码肯定是没有修改吧,但是在hibernate中,使用SaveOrUpdate来更新,然后突然,啪的一下密码变成空了,我想坏了,不能这么干,因为如果这里不显示的话,这个员工的实体还是每个选项都要赋值的,所以我在最后面用了另外一个方法:使用bulkUpdate来操作就可以了。

这个地方的话我和修改用户密码一起组合起来写了,所以用了一个if  ..else..

	@Override
public void update(CrmStaff crmStaff) { String staffCode=crmStaff.getStaffCode(); if(staffCode!=null){
//修改密码
String loginPwd=crmStaff.getLoginPwd();
String staffId=crmStaff.getStaffId(); String hql1="update CrmStaff c set c.loginPwd=? where c.staffId=?";
this.getHibernateTemplate().bulkUpdate(hql1,loginPwd,staffId); }else{
String loginName=crmStaff.getLoginName();
String staffName=crmStaff.getStaffName();
String gender=crmStaff.getGender();
String postId=crmStaff.getCrmPost().getPostId();
Date onDutyDate=crmStaff.getOnDutyDate();
String staffId=crmStaff.getStaffId(); String hql="update CrmStaff c set c.loginName=? ,c.staffName=?,c.gender=?,c.crmPost.postId=?, c.onDutyDate=? where c.staffId=? ";
this.getHibernateTemplate().bulkUpdate(hql, loginName,staffName,gender,postId,onDutyDate,staffId); } }

哎,虽然麻烦了一些,好歹功能最后被我实现了,要是哪位小伙伴有更好的想法,欢迎留言交流哦!希望更懂的小伙伴们可以不吝赐教哦!项目源码我已经放到我的github中啦!

项目总结:这是一个非常好的SSH框架的项目,非常简单,整个过程更多的是需要细心和耐心,对于一些相似的功能如果想要复制黏贴的话千万要记得修改相应的地方,不然的话...就会”蹦,傻卡拉卡“ 系统就炸掉了,哈哈!还有就是通过js来打开'window.showModalDialog弹出模态窗口的时候貌似只兼容火狐浏览器。至于解决窗口的嵌套我们可以使用

if(top.location!= self.location){

top.location= self.location;  //赋值成功之后,将马上跳转

}

来解决。好了,今天的项目分享就到这里啦!明天又是新的一天啦!

项目源码:https://github.com/sdksdk0/CRM

项目分享:通过使用SSH框架的公司-学员关系管理系统(CRM)的更多相关文章

  1. Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程

    在上篇随笔<Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示>中介绍了我的整个CRM系统的概貌,本篇继续本系列的文章,介绍如何基于我的<winform ...

  2. Java高级项目实战02:客户关系管理系统CRM系统模块分析与介绍

    本文承接上一篇:Java高级项目实战之CRM系统01:CRM系统概念和分类.企业项目开发流程 先来CRM系统结构图: 每个模块作用介绍如下: 1.营销管理 营销机会管理:针对企业中客户的质询需求所建立 ...

  3. [项目分享]JSP+Servlet+JDBC实现的云端汽修后台管理系统

    本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/chenlinSir/CloudDemo-servlet 难度等级:简单 基于JSP+Servlet+Jdbc的云端 ...

  4. SSH框架搭建 详细图文教程

    转载请标明原文地址 一.什么是SSH? SSH是JavaEE中三种框架(Struts+Spring+Hibernate)的集成框架,是目前比较流行的一种Java Web开源框架. SSH主要用于Jav ...

  5. SSH框架搭建详细图文教程

    转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/6762554.html 一.什么是SSH? SSH是JavaEE中三种框架(Struts+Spring+H ...

  6. [项目分享]JSP+Servlet+JDBC实现的学生信息管理系统

    本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/liu_xu111/JavaWeb01 这次分享一个学生管理系统,我感觉这是程序员在大学时期的毕设和课程设计选择最多 ...

  7. javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之一 基础Struts框架搭建篇

    即将开始着手写这个项目,所以希望通过这篇博客来记录自己学习的过程 今天开学第一天,就上了软件工程实践课,自己也开始着手做这个大作业了.首先我的项目名称叫做智能班车管理系统. 项目的概况: 该软件产品是 ...

  8. 使用myeclipse为java web项目添加SSH框架

    添加SSH框架时,要严格按照先Struts,再Spring,最后Hibernate.添加方法见下方: 第一步:添加Struts框架 请按照图示一步步认真执行,配置好struts才可以进行下一步 第二步 ...

  9. SSH框架之一详解maven搭建多模块项目

    闲来无事,思量着自己搭建一个ssh框架,一来回顾熟悉一下ssh的内容,hibernate还就没用过了,生疏了都.二来整合一下,将其他掌握的和正在学习的框架核技术糅合到一起,就当是做一个demo练手了. ...

随机推荐

  1. POJ-2349 Arctic Network---MST的第m长的边

    题目链接: https://vjudge.net/problem/POJ-2349 题目大意: 要在n个节点之间建立通信网络,其中m个节点可以用卫星直接连接,剩下的节点都要用线路连接,求剩下这些线路中 ...

  2. hdu1003 Max Sum---最大子段和+记录开始结束点

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1003 题目大意: 求最大子段和,并且输出最大子段和的起始位置和终止位置. 思路: 根据最大子段和基本 ...

  3. scrapy中的request

    scrapy中的request 初始化参数 class scrapy.http.Request( url [ , callback, method='GET', headers, body, cook ...

  4. [转]scrapy中的logging

    logging模块是Python提供的自己的程序日志记录模块. 在大型软件使用过程中,出现的错误有时候很难进行重现,因此需要通过分析日志来确认错误位置,这也是写程序时要使用日志的最重要的原因. scr ...

  5. $rootscope说明

    scope是AngularJS中的作用域(其实就是存储数据的地方),很类似JavaScript的原型链 .搜索的时候,优先找自己的scope,如果没有找到就沿着作用域链向上搜索,直至到达根作用域roo ...

  6. 华为防火墙USG5500-企业双ISP出口

    需求:(1)技术部IP地址自动获取,网段为192.168.10.0/24,该部门访问Internet的报文正常情况下流入链路ISP1. 总经办IP地址自动获取,网段为192.168.20.0/24,该 ...

  7. 学习React系列(九)——高阶函数

    定义:高阶组件就是一个函数,且该函数接收一个组件作为参数,并返回一个新的组件. (上一篇已经说过了高阶组件可以用来解决交叉问题) 一.不要改变原始组件,使用组合 class A extends Rea ...

  8. chrome浏览器再次打开黑屏一段时间

    打开chrome设置 最下面-显示高级设置 再拉到最下面-使用硬件加速模式(把勾去掉)

  9. ubuntu12.04更新到14.04,win7误删BCD引导项,导致两个系统都无法进入

    解决办法: 制作老毛桃U盘启动盘,使用BCD编辑软件,对C/boot下的BCD文件进行编辑,添加win7引导向. 开机进入win7后,使用easyBCD添加ubuntu14.04启动项,选择grub2 ...

  10. ActiveMQ笔记:源码分析

    本文对ActiveMQ的启动过程,以及BrokerService,TransportConnector和NetworkConnector等几个重要的模块的代码做一个简要的分析. 启动过程 如果要快速地 ...