基于SSM架构的CRM系统(二):项目改进&BaseMapper&BaseService&集成easyui : https://blog.csdn.net/qq_33526760/article/details/94606749
一.业务分析
要做一个xxx公司的客户电话营销系统,首先要针对目标人群获取一些基础数据(比如客户来源,客户名称,电话.....),把这些客户的基本信息保存到系统,成为潜在客户,然后营销部门针对潜在客户指定相应的开发计划,开发计划与客户之前的关系设计为一对一,由销售人员实施开发计划对潜在客户进行开发,得到更多的客户信息,得到更多的客户信息之后,把潜在客户升级为正式客户(还没有签约,但信息比较完善了),升级为正式的客户之后,继续由销售人员进行跟进,如果同一个销售人员跟进了很多次,还是没有结果,那么可能这个客户比较难搞,移交给另外的销售人员,移交的时候,生成一条移交记录,如果很多销售人员都搞不定这个客户,那么就可以先把这个客户放入资源池(通过一个字段控制状态就行了),等以后有空闲或者说有更好的销售技巧的时候,再把这个客户拿出来开发,但是,当在跟进阶段,已经达成购买意向,并且缴纳了定金,那么,通过系统生成订单,还要通过订单生成合同,合同上面有合同付款明细(分几次付的款),生成合同的同时还要生成售后服务明细,记录每次售后服务的记录,画了一个图加深理解:
客户和跟进历史是一对多的关系
二.部门,员工页面列表完善(员工模块先不做,先把部门搞定)
根据需求先设计domain,根据domain写CRUD,先集成部门和员工,这里只写部门,员工是一样的步骤
部门的字段设计:
数据项 | 字段 | 说明 | 输入格式 | 是否必填 |
ID | id | 主键,系统自动生成 | 数据库自动生成 |
|
部门编号 | sn |
| 文本 | 是 |
部门名称 | name |
| 文本 | 是 |
部门经理 | manager |
| 员工对象 |
|
上级部门 | parent |
| 部门对象 |
|
子部门 | children | 集合属性 | 部门对象 |
|
路径 | dirPath |
| 文本 |
|
状态 | state | 0 正常 ,-1停用 | 数字 |
|
员工的字段设计:
数据项 | 字段 | 说明 | 输入格式 | 是否必填 |
ID | id | 主键,系统自动生成 | 数据库自动生成 |
|
员工账号 | username |
| 文本 | 是 |
真实姓名 | realName |
| 文本 | 是 |
密码 | password |
| 文本 | 是 |
电话 | tel |
| 文本 | 是 |
邮箱 | |
| 文本 |
|
部门 | dept |
| 文本 |
|
录入时间 | inputTime |
| 日期 |
|
状态 | state | 0 正常 ,-1离职 | 数字 |
|
角色 | role |
| 角色对象 |
|
写代码顺序:
domain-->数据库建表-->Mapper.java-->Mapper.xml-->service-->service测试-->controller,jsp
domain:
public class Employee {//员工的角色先不管,后面会做处理
private Long id; // ID 数据库自动生成
private String username; // 员工账号 文本 not null
private String realName; // 真实姓名 文本 not null
private String password; // 密码 文本 not null
private String tel; // 电话 文本 not null
private String email; // 邮箱 文本
private Department dept; // 部门 文本
private Date inputTime = new Date(); // 录入时间 日期
private Integer state; // 状态 数字 0 正常 ,-1离职
public Employee() {
}
public Employee(long id) {
this.id=id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
public Date getInputTime() {
return inputTime;
}
@DateTimeFormat(pattern = "yyyy-MM-dd")
public void setInputTime(Date inputTime) {
this.inputTime = inputTime;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
@Override
public String toString() {
return "Employee [id=" + id + ", username=" + username + ", realName=" + realName + ", password=" + password
+ "]";
}
}
public class Department {
private Long id; // ID 数据库自动生成
private String sn; // 部门编号 文本 not null (此处感觉该用数字类型, 但文档要求文本)
private String name; // 部门名称 文本 not null
private Employee manager; // 部门经理 员工对象
private Department parent; // 上级部门 部门对象
private List<Department> children = new ArrayList<>(); // 子部门 集合属性 部门对象
private String dirPath; // 路径 文本
private Integer state; // 状态 0 正常 ,-1停用 数字
public Department() {
}
public Department(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Employee getManager() {
return manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
public Department getParent() {
return parent;
}
public void setParent(Department parent) {
this.parent = parent;
}
public List<Department> getChildren() {
return children;
}
public void setChildren(List<Department> children) {
this.children = children;
}
public String getDirPath() {
return dirPath;
}
public void setDirPath(String dirPath) {
this.dirPath = dirPath;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
@Override
public String toString() {
return "Department [id=" + id + ", sn=" + sn + ", name=" + name + ", dirPath=" + dirPath + ", state=" + state
+ "]";
}
}
数据库建表:
部门是自关联,所以不用设计children字段
Mapper.java:(代码中已有,此处省略)
Mapper.xml:(关联查询采用嵌套结果)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.xxx.crm.mapper.DepartmentMapper">
<resultMap id="deptMap" type="cn.xxx.crm.domain.Department">
<id property="id" column="did"/>
<result property="sn" column="sn"/>
<result property="name" column="dname"/>
<result property="dirPath" column="dirPath"/>
<result property="state" column="state"/>
<association property="manager" javaType="cn.xxx.crm.domain.Employee">
<id property="id" column="eid"/>
<result property="realName" column="ename"/>
</association>
<association property="parent" javaType="cn.xxx.crm.domain.Department">
<id property="id" column="d1id"/>
<result property="name" column="d1name"/>
</association>
</resultMap>
<!-- //通过id加载一个对象
T (Serializable id); -->
<select id="loadById" parameterType="long" resultType="cn.xxx.crm.domain.Department">
select id,name from t_department where id=#{id}
</select>
<!-- //加载所有对象
List<T> loadAll(); -->
<select id="loadAll" resultMap="deptMap">
select d.id did,d.sn,d.name dname,d.dirPath,d.state,
e.id eid,e.realName ename,d1.id d1id,d1.name d1name
from t_department d
left join t_employee e on d.manager_id = e.id
left join t_department d1 on d.parent_id = d1.id
</select>
<!-- //插入一个对象
void save(T t); -->
<insert id="save" parameterType="cn.xxx.crm.domain.Department">
insert into t_department(name) values(#{name})
</insert>
<!-- //根据id删除对象
void remove(Serializable id); -->
<delete id="remove" parameterType="long">
delete from t_department where id=#{id}
</delete>
<!-- //根据id修改对象
void update(T t); -->
<update id="update" parameterType="cn.xxx.crm.domain.Department">
update t_department set name = #{name} where id=#{id}
</update>
</mapper>
service:参照前一天文档
service测试:参照前一天文档
controller,jsp:
前台展示的对象,要进行格式化,因为系统中很多地方的表格都要进行格式化,所以,我们可以把格式化的方法写在common.js中,
那以后很多页面都要引入common.js文件,那我们在common.jsp中引入common.js,那么只要引入了common.jsp就引入了common.js:
三.jsp页面优化
先看看未优化前的部门的jsp页面有什么问题:
问题:①a标签绑定的事件太多太分散,不好维护 -->封装命令对象
②同一个组件,很多地方都通过id来获取,如果id改变了,那么要修改很多地方 -->抽取公共组件
③绑定事件的代码比写页面的代码还多,不好看 -->a标签统一绑定
未优化之前的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%@include file="/WEB-INF/views/common.jsp"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>部门管理</title>
</head>
<body>
<!-- 管理表格 -->
<table id="deptDatagrid" title="部门管理" class="easyui-datagrid"
style="width: 700px; height: 250px" url="/department/list"
toolbar="#deptToolbar" pagination="true" rownumbers="true" fit="true"
fitColumns="true" singleSelect="true">
<thead>
<tr>
<th field="id" width="50" hidden="true">id</th>
<th field="sn" width="50">编号</th>
<th field="name" width="50">部门名称</th>
<th field="dirPath" width="50">路径</th>
<th field="state" width="50" formatter="stateFormat">状态</th>
<th field="manager" width="50" formatter="objectFormat">部门经理</th>
<th field="parent" width="50" formatter="objectFormat">上级部门</th>
</tr>
</thead>
</table>
<!-- 管理表格toolbar -->
<div id="deptToolbar">
<a id='saveDeptBtn' class="easyui-linkbutton c1" iconCls="icon-add"
plain="true">新增</a> <a id='editDeptBtn' class="easyui-linkbutton c3"
iconCls="icon-edit" plain="true">编辑</a> <a id='deleteDeptBtn'
class="easyui-linkbutton c5" iconCls="icon-remove" plain="true">删除</a>
<a id='reloadDeptBtn' class="easyui-linkbutton c7"
iconCls="icon-remove" plain="true">刷新</a>
</div>
<!-- 添加和修改对话框 -->
<div id=saveOrUpdateDeptDlg class="easyui-dialog" style="width: 400px"
data-options="closed:true,modal:true,border:'thin',buttons:'#dlg-buttons'">
<form id="fm" method="post" novalidate
style="margin: 0; padding: 20px 50px">
<div style="margin-bottom: 10px">
<input name="id" type="hidden" /> <input name="name"
class="easyui-textbox" required="true" label="部门名称:"
style="width: 100%" />
</div>
</form>
</div>
<!-- 添加和修改对话框按钮 -->
<div id="dlg-buttons">
<a id="confirmSaveOrUpdateBtn" class="easyui-linkbutton c6"
iconCls="icon-ok" style="width: 90px">保存</a> <a
id="cancelSaveOrUpdateBtn" class="easyui-linkbutton c8"
iconCls="icon-cancel" style="width: 90px">取消</a>
</div>
<script type="text/javascript">
var url;
$('#saveDeptBtn').click(function(){
//清空模态框里字段的内容
$('#fm').form('clear');
//打开
$('#saveOrUpdateDeptDlg').dialog('open').dialog('center').dialog('setTitle','新增');
// url = 'save_user.php';?
});
$('#editDeptBtn').click(function(){
//清空模态框里字段的内容
$('#fm').form('clear');
//对编辑的数据进行回显
var row = $('#deptDatagrid').datagrid('getSelected');
if (row){
$('#saveOrUpdateDeptDlg').dialog('open').dialog('center').dialog('setTitle','编辑');
$('#fm').form('load',row);
// url = 'update_user.php?id='+row.id;
}else{
$.messager.alert('提示','请选择一条数据!','info');
}
});
$('#deleteDeptBtn').click(function(){
var row = $('#deptDatagrid').datagrid('getSelected');
// console.log(row);
if (row){
$.messager.confirm('Confirm','确定要删除这条记录吗?',function(r){
if (r){
$.post('/department/delete',{id:row.id},function(result){
if (result.success){
$.messager.alert('提示',result.message,'info');
$('#deptDatagrid').datagrid('reload'); // reload the user data
} else {
$.messager.alert('错误',result.message,'error');
$('#deptDatagrid').datagrid('reload');
}
},'json');
}
});
}else{
$.messager.alert('提示','请选择一条数据!','info');
}
});
$('#reloadDeptBtn').click(function(){
$('#deptDatagrid').datagrid('reload');
});
$('#confirmSaveOrUpdateBtn').click(function(){
$('#fm').form('submit',{
url : '/department/save',
success : function(data){
//应该返回一个AjaxResult转换的结果
//由于这儿是做表单提交,不是通过JQuery发送的Ajax请求,返回的是Json字符串需要转换为Json对象
// 1 eval 2 $.parseJSON 3....
data = $.parseJSON(data);
if(data.success){
$.messager.alert('提示',data.message,'info');
$('#deptDatagrid').datagrid('reload');
}else{
$.messager.alert('错误',data.message,'error');
$('#deptDatagrid').datagrid('reload');
}
}
});
$('#saveOrUpdateDeptDlg').dialog('close');
});
$('#cancelSaveOrUpdateBtn').click(function(){
$('#saveOrUpdateDeptDlg').dialog('close');
});
</script>
</body>
</html>
优化之后的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%@include file="/WEB-INF/views/common.jsp"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>部门管理</title>
</head>
<body>
<!-- 管理表格 -->
<table id="deptDatagrid" title="部门管理" class="easyui-datagrid"
style="width: 700px; height: 250px" url="/department/list"
toolbar="#deptToolbar" pagination="true" rownumbers="true" fit="true"
fitColumns="true" singleSelect="true">
<thead>
<tr>
<th field="id" width="50" hidden="true">id</th>
<th field="sn" width="50">编号</th>
<th field="name" width="50">部门名称</th>
<th field="dirPath" width="50">路径</th>
<th field="state" width="50" formatter="stateFormat">状态</th>
<th field="manager" width="50" formatter="objectFormat">部门经理</th>
<th field="parent" width="50" formatter="objectFormat">上级部门</th>
</tr>
</thead>
</table>
<!-- 管理表格toolbar -->
<div id="deptToolbar">
<a id='saveDeptBtn' data-cmd="saveDept" class="easyui-linkbutton c1" iconCls="icon-add" plain="true">新增</a>
<a id='editDeptBtn' data-cmd="editDept" class="easyui-linkbutton c3" iconCls="icon-edit" plain="true">编辑</a>
<a id='deleteDeptBtn' data-cmd="deleteDept" class="easyui-linkbutton c5" iconCls="icon-remove" plain="true">删除</a>
<a id='reloadDeptBtn' data-cmd="reloadDept" class="easyui-linkbutton c7" iconCls="icon-remove" plain="true">刷新</a>
</div>
<!-- 添加和修改对话框 -->
<div id=saveOrUpdateDeptDlg class="easyui-dialog" style="width: 400px"
data-options="closed:true,modal:true,border:'thin',buttons:'#dlg-buttons'">
<form id="fm" method="post" novalidate
style="margin: 0; padding: 20px 50px">
<div style="margin-bottom: 10px">
<input name="id" type="hidden" /> <input name="name"
class="easyui-textbox" required="true" label="部门名称:"
style="width: 100%" />
</div>
</form>
</div>
<!-- 添加和修改对话框按钮 -->
<div id="dlg-buttons">
<a id="confirmSaveOrUpdateBtn" data-cmd="confirmSaveOrUpdate" class="easyui-linkbutton c6" iconCls="icon-ok" style="width: 90px">保存</a>
<a id="cancelSaveOrUpdateBtn" data-cmd="cancelSaveOrUpdate" class="easyui-linkbutton c8" iconCls="icon-cancel" style="width: 90px">取消</a>
</div>
<script type="text/javascript">
//优化1 抽取页面需要使用的公共组件 一共有三个:数据表格,新增或编辑对话框
var deptDatagrid,saveOrUpdateDeptDlg,fm;
//优化2 给公共组件赋值
deptDatagrid=$("#deptDatagrid");
saveOrUpdateDeptDlg=$("#saveOrUpdateDeptDlg");
fm=$("#fm");
//优化3 创建一个命令对象,把模块所有功能打包到这个对象上 一共6个a标签按钮
cmdObject = {
"saveDept": function(){
//清空模态框里字段的内容
fm.form('clear');
//打开
saveOrUpdateDeptDlg.dialog('open').dialog('center').dialog('setTitle','新增');
},
"editDept":function(){
//清空模态框里字段的内容
fm.form('clear');
//对编辑的数据进行回显
var row = deptDatagrid.datagrid('getSelected');
if (row){
saveOrUpdateDeptDlg.dialog('open').dialog('center').dialog('setTitle','编辑');
fm.form('load',row);
}else{
$.messager.alert('提示','请选择一条数据!','info');
}
},
"deleteDept":function(){
var row = deptDatagrid.datagrid('getSelected');
// console.log(row);
if (row){
$.messager.confirm('Confirm','确定要删除这条记录吗?',function(r){
if (r){
$.post('/department/delete',{id:row.id},function(result){
if (result.success){
$.messager.alert('提示',result.message,'info');
deptDatagrid.datagrid('reload'); // reload the user data
} else {
$.messager.alert('错误',result.message,'error');
deptDatagrid.datagrid('reload');
}
},'json');
}
});
}else{
$.messager.alert('提示','请选择一条数据!','info');
}
},
"reloadDept":function(){
deptDatagrid.datagrid('reload');
},
"confirmSaveOrUpdate":function(){
fm.form('submit',{
url : '/department/save',
success : function(data){
//应该返回一个AjaxResult转换的结果
//由于这儿是做表单提交,不是通过JQuery发送的Ajax请求,返回的是Json字符串需要转换为Json对象
// 1 eval 2 $.parseJSON 3....
data = $.parseJSON(data);
if(data.success){
$.messager.alert('提示',data.message,'info');
deptDatagrid.datagrid('reload');
}else{
$.messager.alert('错误',data.message,'error');
deptDatagrid.datagrid('reload');
}
}
});
saveOrUpdateDeptDlg.dialog('close');
},
"confirmSaveOrUpdate":function(){
fm.form('submit',{
url : '/department/save',
success : function(data){
//应该返回一个AjaxResult转换的结果
//由于这儿是做表单提交,不是通过JQuery发送的Ajax请求,返回的是Json字符串需要转换为Json对象
// 1 eval 2 $.parseJSON 3....
data = $.parseJSON(data);
if(data.success){
$.messager.alert('提示',data.message,'info');
deptDatagrid.datagrid('reload');
}else{
$.messager.alert('错误',data.message,'error');
deptDatagrid.datagrid('reload');
}
}
});
saveOrUpdateDeptDlg.dialog('close');
},
"cancelSaveOrUpdate":function(){
saveOrUpdateDeptDlg.dialog('close');
}
}
//优化4 a标签统一绑定事件 进行动态调用
$("a[data-cmd]").click(function(){
var cmd = $(this).data("cmd");
if(cmdObject[cmd]&&!$(this).hasClass("l-btn-disabled")){
cmdObject[cmd]();
}else{
$.messager.alert('提示','a标签没有绑定事件或禁用!','info');
}
});
</script>
</body>
</html>
四.分页实现
如何进行分页??首先我们前端使用的是easyui,那先借鉴easyui里面是怎么分页的,打开easyui的demo,选中datagrid:
选择:
可以看到,请求的参数是当前页和每页显示多少行,响应式总数和当前页数据
那我们后台要用一个query对象来接收分页对象,用一个pagelist对象来封装返回的数据,由于每一个模块都要进行查询,我们把query对象抽取一个BaseQuery,不同模块的query对象继承它公共查询条件,在自己的类里面写自己特有的查询条件,pagelist对象也写成公共的工具类,加泛型,每个模块都可以使用:
public class BaseQuery {
private int page = 1;
private int rows = 10;
public BaseQuery(int page, int rows) {
super();
this.page = page;
this.rows = rows;
}
public BaseQuery() {}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
//得到分页数据的起始位置
public int getStart(){
return (this.page-1)*this.rows;
}
}
public class PageList<T> {
private int total = 0;
// 默认值null,前台可能会报null,给new ArrayList<>()这个默认值,[]不会报null
private List<T> rows = new ArrayList<>();
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public PageList(int total, List<T> rows) {
super();
this.total = total;
this.rows = rows;
}
public PageList() {}
}
代码下载:https://download.csdn.net/download/qq_33526760/11391458