目录
5 结束语-----------------------------------------------------------
感谢
0 引言
信息时代的今天,各企业商家所关心的不再局限于自身的产品质量、生产设备、员工的素质,更多的是关心自己的销售群体(客户群),关心他们的想法、需求、购卖目的。
众所周知,顾客就是我们的上帝,我们只有满足了上帝的需求,上帝才能给我们带来一切。一个企业要生存、要发展,就是要不断的满足客户的需求,无论我们做出什么样的决策,最终都是为了这个的目。每个领域都有自身生存法则,但无论这个法则如何变化,为客户服务的宗旨是不会变的。作为企业,我们只有不断地挖掘新客户,维护好和老客户的关系,占领市场客户群体的绝大多数份额,才能在整个领域取得一席之地。海尔总裁张瑞敏指出:“客户资源决定企业核心竞争力”,上个世纪80年代是物品短缺的时代,而现在,信息时代是客户短缺的时代。企业发展所需的各种资源(包括人力、物力、生产力)都是可以创造的,但每个领域中的客户资源确是有限的,所以通过创新(产品的创新、企业管理的创新、服务的创新)来抢占有限的客户资源、维护好企业和客户之间的关系、了解客户的需求动向,成为企业生存发展面临的重大问题。
1 系统分析
1.1 需求分析
通过调查研究,要求系统满足有以下功能;
- 由于操作人员的计算机知识普遍较差,要求有良好的人机界面。
- 方便的数据选择查询,支持模糊查询功能。
- 管理客户的详细信息:包括客户的基本信息、联系人信息、和服务信息。
- 数据计算自动完成,尽量减少人工干预。
1.2 可行性分析
- 经济性
通过计算机网络对客户信息进行管理,使企业对自身拥有的客户有了一个更为深该的了解。不仅能全面的统计客户的购买数量,及时的了解客户的动态信息,还可以根据计算机记录的数据信息,不断的调整企业的生产发展动向。
- 技术性
√ 采用 Struts2.0+Spring3.0+Hibernate3.2 开源框架
√ 数据库采用 SQLServer 2005
框架详解:
- Struts2.0: Struts 2是Struts的下一代产品,是在 struts 和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构的差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与Servlet API完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着太大的变化,但是相对于WebWork,Struts 2只有很小的变化。
- Spring3.0: 是为了解决企业应用程序开发复杂性由Rod Johnson创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
- Hibernate3.2: 是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
- SQL是英文Structured Query Language的缩写,意思为结构化查询语言。SQL语言的主要功能就是同各种数据库建立联系,进行沟通。按照ANSI(美国国家标准协会)的规定,SQL被作为关系型数据库管理系统的标准语言。
2 总体设计
2.1 项目规划
客户关系管理系统是一个典型的数据库开发应用程序,营销管理,客户管理,服务管理,
统计报表,基础数据如下:
- 营销管理模块
该模块主要功能是对销售机会,客户开发计划进行增删改查操作。
- 客户管理模块
该模块的主要功能是对客户信息,联系人,交往记录,历史订单等增删改查操作。
- 服务管理模块
该模块主要功能是对客户服务进行添加、删除、查询等操作。
- 报表管理模块
该模块主要起到统计数据的作用。
- 基础数据模块
对字典表数据进行增删改查操作。
2.2 系统功能结构图
图1 数据表树型结构图
3 系统设计
3.1 设计目标
项目详解:
因为项目中有许多重复的代码,我们可以将他抽象出一个公共的父类(BaseDao(对数据访问,制定出增删改查方法),BaseAction(定义request,response,分页,页面返回变量)等等)
com.action (存放Action类 用来处理用户请求和业务逻辑)
com.biz(用来存放业务逻辑接口)
com.bizImpl(业务逻辑接口的实现类)
com.dao(用来存放数据访问接口)
com.daoImpl(数据访问接口实现类)
com.entity(存放实体类)
com.util(存放工具类)
JuTest(单元测试类)
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
//配置DWR
<servlet>
<servlet-name>dwr</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
//解决页面使用懒加载问题
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//定义过滤去进行拦截转码
<filter>
<filter-name>doFilter</filter-name>
<filter-class>com.util.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>doFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//Struts自带的过滤器
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//定义监听程序系统初始化时,启动
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
//指定 applicationContext.xml 位置,classpath代表src目录下
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
Datasource.properties(配置文件):
//在程序启动时由Spring工厂对此配置文件进行解析加载
datasource.type=sqlserver
hibernate.dialect=org.hibernate.dialect.SQLServerDialect
datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
datasource.url=jdbc\:sqlserver\://localhost\:1433;DatabaseName\=client
datasource.username=sa
datasource.password=123
struts.xml:
//接受页面请求(如user_login) 为跳转到userAction 下的login方法
<action name="*_*" class="{1}Action" method="{2}">
<interceptor-ref name="defaultStack"></interceptor-ref>
//返回堆栈下的信息来进行,跳转或重定向
<result name="success">${successResultValue}</result>
<result name="redirect" type="redirect">${redirectPath}</result>
</action>
applicationContext.xml(Hibernate由 Spring 控制管理):
// 加载datasource.properties 里的数据配置信息
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:datasource.properties"></property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" dependency-check="none">
<property name="driverClass">
<value>${datasource.driverClassName}</value>
</property>
<property name="jdbcUrl">
<value>${datasource.url}</value>
</property>
<property name="user">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
</bean>
//Hibernate配置与注入数据源
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"></ref>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">
updates
</prop>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">
${hibernate.show_sql}
</prop>
<prop key="hibernate.format_sql">
${hibernate.format_sql}
</prop>
<prop key="hibernate.jdbc.fetch_size">
${hibernate.jdbc.fetch_size}
</prop>
<prop key="hibernate.jdbc.batch_size">
${hibernate.jdbc.batch_size}
</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">
false
</prop>
<prop key="hibernate.connection.release_mode">
${hibernate.connection.release_mode}
</prop>
</props>
</property>
//扫描 com.entity下的所有类
<property name="packagesToScan">
<list>
<value>com.entity</value>
</list>
</property>
// Hibernate 持久化层 模板化
<bean
id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
//注入事物管理器
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--使用基于注解方式配置事务 -->
<tx:annotation-driven transaction-manager="txManager" />
</beans>
log4j.properties :
//日志信息管理
3.2 开发及运行环境
开发工具:Myeclipse 8.5(java开发工具),Powerdesigner(数据库建模工具) ,SQLServer(微软的数据库产品)
开发环境: Windows操作系统,Tomcat服务器,JDK6.0
硬件平台:
- CPU:P41。8GHz;
- 内存:256MB以上。
软件平台:
- 操作系统:Windows 系统;
- 数据库:SQL Server 2000;
- 浏览器:推荐使用IE6.0;
- Web服务器:IIS5.0;
- 分辨率:最佳效果1024*768。
3.3 数据库设计
本系统数据库采用SQLServer2005数据库,系统数据库名称为jb_crm_team0_Data.MDF。数据库jb_crm_team0_Data.MDF中包含15张表。关于数据库中的数据表请参见后文。
4 客户管理模块设计(主要代码)
√登陆与权限模块
此模块用于用户的登陆验证与权限
数据库表
用户登录界面
//用户点击登陆 提交SysUser_login
<script type="text/javascript">
function tosubmit()
{
document.forms[0].action="SysUser_login";
document.forms[0].submit();
}
</script>
后台数据接收(通过Struts与Spring控制找到请求的Action类)
//注解 将此类名定义名为SysUserAction(Spring将通过解析找到此类)
@Component("SysUserAction")
//继承事先写好的公用类 BaseAction
public class SysUserAction extends BaseAction {
//将SysUserBiz(写好的对数据进行逻辑处理的接口,增删改查方法)注入此类
@Resource(name = "SysUserBiz")
private SysUserBiz sysUserBiz;
//封装SysUser类
private SysUser sysUser;
public SysUser getSysUser() {
return sysUser;
}
public void setSysUser(SysUser sysUser) {
this.sysUser = sysUser;
}
//请求的对应方法
public String login()
{
String Msg="用户名或密码错误!";
this.setSuccessResultValue("login.jsp");
if(sysUserBiz.login(this.sysUser.getUsrName(), this.sysUser.getUsrPassword()))
{
Msg="";
this.setSuccessResultValue("html/index.jsp");
this.getRequest().getSession().setAttribute("Uname",sysUserBiz.getByName(this.sysUser.get UsrName()));
}
this.getRequest().setAttribute("Msg", Msg);
return SUCCESS;
}
营销管理模块
数据库
查询所有操作
public String getAll(){
//调用BaseAction里的分页方法
this.doPage("from SalChance", null);
this.setSuccessResultValue("/html/~sale/list.jsp") ;
return SUCCESS;
}
BaseAction的分页方法
public void doPage(String strSql, String urlparam) {
// Page page = new Page(strSql, 20, getPage(), 5,
// urlparam);//10:每页显示10条数据 5:页之间的跨度为5
page_.initPage(strSql, 10, getPage(), 5, urlparam);
setPageHtml(page_.getPageText());// 分页
setPageList(page_.getPageList());
}
模糊查询
public String getByInfo()
{
String hql ="from SalChance ";
if(salChance.getChcCustName()!=null && !salChance.getChcCustName().equals(""))
{
hql+="where chcCustName Like '%"+salChance.getChcCustName()+"%'";
}else if(salChance.getChcTitle()!=null && !salChance.getChcTitle().equals(""))
{
hql+="where chcTitle Like '%"+salChance.getChcTitle()+"%'";
}else if(salChance.getChcLinkman()!=null && !salChance.getChcLinkman().equals(""))
{
hql+="where chcLinkman Like '%"+salChance.getChcLinkman()+"%'";
}
this.doPage(hql, null);
this.setSuccessResultValue("/html/~sale/list.jsp") ;
return SUCCESS;
}
添加
public String add()
{
if(this.salChanceBiz.add(this.salChance)){
//添加成功后系统将再次加载数据,此处用到了Redirect(重定向)
this.setRedirectPath("SalChance_getAll");
return Redirect;
}
this.setSuccessResultValue("/html/~sale/add.jsp");
return SUCCESS;
}
//Form表单里控件的名字要与Action里定义的实体名字吻合。如下为Action实例的salChance类下的chcStatus字段赋值
<input type="hidden" name="salChance.chcStatus" value="0">
修改
public String update()
{
if(this.salChanceBiz.update(this.getSalChance()))
{
this.setRedirectPath("SalChance_getAll");
return Redirect;
}
return ERREO;
}
填充
public String toEdit()
{
this.getRequest().setAttribute("SalChanceByid",salChanceBiz.getSal(this.salChance.getChcId()));
this.getRequest().setAttribute("AllUser", sysUserBiz.getAll());
this.setSuccessResultValue("/html/~sale/edit.jsp");
return SUCCESS;
}
//在页面获取存在request内的数据对下拉列表填充
<select name="salChance.chcDueTo">
<option>请选择...</option>
//迭代循环
<s:iterator value="#request.AllUser" var="list">
<option
value="<s:property value="#list.usrName"/>"><s:property value="#list.usrName"/> </option>
</s:iterator></select>
//删除操作
public String del()
{
if(this.salChanceBiz.del(this.getSalChance().getChcId()))
{
this.setRedirectPath("SalChance_getAll");
return Redirect;
}
this.setSuccessResultValue("error.jsp");
return SUCCESS;
}
//通过JAVASCRIPT 提示是否要删除。
<img
οnclick="if(confirm('您确认删除这条数据?'))
{to('<%=path%>/SalChance_del?salChance.chcId=<s:property value="#list.chcId"/>')}" title="删除"src="<%=path%>/html/images/bt_del.gif" class="op_button" />
客户开发计划:此模块为客户计划操作,分三种状态,制定开发计划,开发计划得到的响应,开发结束(主要知识点介绍,其他请参见上模块)
//如果状态已完毕
//这里用到了Struts2 标签去判断
<s:if test="#list.chcStatus==3|#list.chcStatus==2">
<img
οnclick="javascript:window.location.href='<%=path%>/salPlan_getByid?salPlan.salChance.chcId=<s:property value="#list.chcId"/>¶m=3'"
title="查看" src="<%=path%>/html/images/bt_detail.gif"
class="op_button" />
</s:if>
//如果状态开发中
<s:else>
<img<s:if test="#session.Uname.sysRole.roleId==1">
οnclick="javascript:window.location.href='<%=path%>/salPlan_getByid?salPlan.salChance.chcId=<s:property value="#list.chcId"/>¶m=1'"
</s:if>
<s:else>
οnclick="javascript:alert('您没有权限!')"
</s:else>
title="制定计划" src="<%=path%>/html/images/bt_plan.gif"
class="op_button" />
<img
<s:if test="#session.Uname.sysRole.roleId==1">
οnclick="javascript:window.location.href='<%=path%>/salPlan_getByid?salPlan.salChance.chcId=<s:property value="#list.chcId"/>¶m=2'"
</s:if>
<s:else>
οnclick="javascript:alert('您没有权限!')"
</s:else>
title="执行计划" src="<%=path%>/html/images/bt_feedback.gif"class="op_button" />
<img<s:if test="#session.Uname.sysRole.roleId==1">
οnclick="alert('用户开发成功,已添加新客户记录。');window.location.href='salPlan_upChan?salChance.chcId=<s:property value="#list.chcId"/>&salChance.chcStatus=2';"
</s:if>
<s:else>
οnclick="javascript:alert('您没有权限!')"
</s:else>
title="开发成功" src="<%=path%>/html/images/bt_yes.gif"
class="op_button" />
</s:else>
//已完毕处理,考虑开发成功只需要状态的修改,所以页面只需要编号(id)和状态(status)通过id进行查询此条信息,然后将状态进行赋值,执行修改。
public String upChan()
{
String status = this.getSalChance().getChcStatus();
this.setSalChance(this.salChanceBiz.getSal(this.salChance.getChcId()));
this.getSalChance().setChcStatus(status);
if(this.salChanceBiz.update(this.getSalChance()))
{
this.setRedirectPath("salPlan_SalChanAll");
return Redirect;
}
this.setSuccessResultValue("error.jsp");
return SUCCESS;
}
客户信息管理
介绍:此模块对客户信息的管理及其对子类(联系人,交往记录,历史订单)进行操作(增删改查),如果客户等级为重点客户的信息将不显示删除操作
(主要知识点介绍,其他请参见上模块)
//等级判断如果是重点客户将没有删除按钮
//如果不是则有删除按钮
//通过Struts2标签的if标签,去判断用户等级
<s:if test="#list.custLevel!=2">
<img
<s:if test="#session.Uname.sysRole.roleId==1">
οnclick="if(confirm('您确认删除这条数据?')){to('cstCustomer_del?cstCustomer.custNo=<s:property value="#list.custNo"/>')}"
</s:if>
<s:else>
οnclick="javascript:alert('您没有权限!')"
</s:else>
title="删除" src="<%=path%>/html/images/bt_del.gif"
class="op_button" />
</s:if>
填充
public String toEdit() {
if (this.cstCustomerBiz.getCus(this.cstCustomer.getCustNo()) != null) {
this.getRequest().setAttribute("cstCust",
this.cstCustomerBiz.getCus(this.cstCustomer.getCustNo()));
this.getRequest().setAttribute("basDict",
this.basDictBiz.getByInfo("地区"));
this.getRequest().setAttribute("basDictc",
this.basDictBiz.getByInfo("客户等级"));
}
this.setSuccessResultValue("/html/~cust/cust/edit.jsp");
return SUCCESS;
}
客户流失
介绍:此模块为客户流失,分三种状态(已流失,暂缓流失,警告),默认状态为警告,我们可以进行暂缓和流失操作,确认流失之后将不可对其在操作。(查改)
通过状态判断
<s:if test="#list.lstStatus!=?">
//考虑此操作都是对信息的修改操作,只是跳转页面不同,我们可以通过参数判断跳转的页面(param)
javascript:window.location.href='cstCustomer_toRelayOrConfirm?param=relay&cstLost.lstId=8
public String toRelayOrConfirm() {
if (this.cstLostBiz.getCl(this.getCstLost().getLstId()) != null) {
this.getRequest().setAttribute("lost",
this.cstLostBiz.getCl(this.getCstLost().getLstId()));}
if (this.param.equals("relay")) {
this.setSuccessResultValue("/html/~cust/lost/relay.jsp");
} else if (this.param.equals("confirm")) {
this.setSuccessResultValue("/html/~cust/lost/confirm.jsp");
}
return SUCCESS;}
其他模块均为普通增删改查操作(省略)
5 结束语
这次我们设计比较正规化,设计之前要开题,开题报告通过才能展开设计。这不仅让我学到如何做好开题报告,也让我主动的分析设计,在展开设计之前就做了很多工作,培养了我的软件设计能力。在开始具体设计以前,我已经完成系统的结构设计,数据库规划等工作,这样以后的设计就事半功倍了。在毕业设计中除了学习了具体的专业知识外,我认为最重要却是让我们建立了软件设计的正确概念。
在这次毕业设计的过程中,我体会到要想开发一个系统软件,不仅需要相当的专业技术知识,还要有严谨缜密的思维能力。只有思想上清晰了,编程才有意义,否则就是白费力气。同时还要善于捕获细小的方面,因为那往往是这个程序的致命因素。这次毕业设计培养了我的细心和耐性,更树立了一种科学的态度。这对我以后的工作和学习也有很大的帮助和指导作用。同时也深刻认识到了本身不存在很多不足之处,还需要不断地学习来充实完善自己,只有这样才能学有所成,求得更大的发展。
通过交流我也感觉到,无论什么方面的编程,学习过程是一样的,都要经过不断的实践积累,不是一蹴而就的。回想这三个月是艰苦的三个月,也是收获的三个月。了解了正确的管理方法,积累了经验。
致谢
首先我要感谢我的指导老师赵老师,在他的督促帮助下我顺利完成了我的毕业设计。在他的指导下,我从头脑混乱到现在整个思路清晰地完成毕业设计,虽然不能说这个我的系统软件有多完善,但这却是我在赵老师的指导下一步一步完成的。在我外出实习期间,赵老师也一直通过QQ、Email来了解我们的设计进度以及在设计中遇到的困难,帮助我们解决我们设计中的难点。在整个设计过程中,他对我们严格要求,按照计划定期检查我们的设计成果,为我们理清整个设计阶段的任务,使我们能够按计划完成设计。
其次我要感谢我们计算机系的领导对我们毕业生的关心和支持,他们不仅要处理系里的一切大小事情,还要像其他老师一样带毕业设计的学生,在这样的情况下,他们还时时关心我们毕业班的学生,根据我们毕业设计的进度,督促老师多跟我们联系,以便指导我们完成毕业设计。所以我衷心的感谢他们。
最后,我要感谢在毕业设计的整个过程中帮助我的所有领导、老师和同学,没有他们的帮助我也不可能完成此次毕业设计。感谢他们给我的各方面的关心和帮助,对指导老师的认真负责的指导再次致以衷心的感谢。