项目分享:通过使用SSH框架的公司-学员关系管理系统(CRM)
----------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处]
文章出处: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)的更多相关文章
- Winform开发框架之客户关系管理系统(CRM)的开发总结系列2-基于框架的开发过程
在上篇随笔<Winform开发框架之客户关系管理系统(CRM)的开发总结系列1-界面功能展示>中介绍了我的整个CRM系统的概貌,本篇继续本系列的文章,介绍如何基于我的<winform ...
- Java高级项目实战02:客户关系管理系统CRM系统模块分析与介绍
本文承接上一篇:Java高级项目实战之CRM系统01:CRM系统概念和分类.企业项目开发流程 先来CRM系统结构图: 每个模块作用介绍如下: 1.营销管理 营销机会管理:针对企业中客户的质询需求所建立 ...
- [项目分享]JSP+Servlet+JDBC实现的云端汽修后台管理系统
本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/chenlinSir/CloudDemo-servlet 难度等级:简单 基于JSP+Servlet+Jdbc的云端 ...
- SSH框架搭建 详细图文教程
转载请标明原文地址 一.什么是SSH? SSH是JavaEE中三种框架(Struts+Spring+Hibernate)的集成框架,是目前比较流行的一种Java Web开源框架. SSH主要用于Jav ...
- SSH框架搭建详细图文教程
转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/6762554.html 一.什么是SSH? SSH是JavaEE中三种框架(Struts+Spring+H ...
- [项目分享]JSP+Servlet+JDBC实现的学生信息管理系统
本文存在视频版本,请知悉 项目简介 项目来源于:https://gitee.com/liu_xu111/JavaWeb01 这次分享一个学生管理系统,我感觉这是程序员在大学时期的毕设和课程设计选择最多 ...
- javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之一 基础Struts框架搭建篇
即将开始着手写这个项目,所以希望通过这篇博客来记录自己学习的过程 今天开学第一天,就上了软件工程实践课,自己也开始着手做这个大作业了.首先我的项目名称叫做智能班车管理系统. 项目的概况: 该软件产品是 ...
- 使用myeclipse为java web项目添加SSH框架
添加SSH框架时,要严格按照先Struts,再Spring,最后Hibernate.添加方法见下方: 第一步:添加Struts框架 请按照图示一步步认真执行,配置好struts才可以进行下一步 第二步 ...
- SSH框架之一详解maven搭建多模块项目
闲来无事,思量着自己搭建一个ssh框架,一来回顾熟悉一下ssh的内容,hibernate还就没用过了,生疏了都.二来整合一下,将其他掌握的和正在学习的框架核技术糅合到一起,就当是做一个demo练手了. ...
随机推荐
- 【Java入门提高篇】Day15 Java泛型再探——泛型通配符及上下边界
上篇文章中介绍了泛型是什么,为什么要使用泛型以及如何使用泛型,相信大家对泛型有了一个基本的了解,本篇将继续讲解泛型的使用,让你对泛型有一个更好的掌握和更深入的认识. 上篇中介绍完泛型之后,是不是觉得泛 ...
- getgpc($k, $t='GP'),怎么返回的是 NULL?
<?php /** * 实用小代码 * 获得GET POST COOKIS */ $html=<<<WORD <form method="post"& ...
- JEECG 新版在线文档WIKI正式发布
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zhangdaiscott/article/details/80 JEECG 新版在线文档WIKI正式 ...
- [LeetCode] Average of Levels in Binary Tree 二叉树的层平均值
Given a non-empty binary tree, return the average value of the nodes on each level in the form of an ...
- 以太坊如何估计计算gas?
以太坊如何估计估算计算gas?Etherscan上transaction info中有个gas used by txn,结果跟remix给的结果以及geth中getTransactionReceipt ...
- [JLOI 2011]飞行路线&[USACO 09FEB]Revamping Trails
Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并 ...
- [ZJOI2016]小星星
题目描述 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星. 有一天她发现,她的饰品被破坏了,很多细线都被拆掉了.这个饰品只剩下了 ...
- [POI2007]ZAP-Queries
题目描述 Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He ha ...
- SPOJ COT(树上的点权第k大)
Count on a tree Time Limit: 129MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Submi ...
- [Apio2009][bzoj1179]Atm
题意:一个n个点m条单向边的图,每个点有权值,给定出发点和p个可以停止的点,你可以随便走一条路径从出发点走到一个可以停止的点,但是每个点的点权只能计算一次,求能得到的最大权值. n,m<=500 ...