基于SSM员工客户关系管理系统
前言
本系统是一款PC端的员工客户关系管理系统,方便公司员工对客户进行管理和意向记录。用户注册以后可以登录系统,可以查看员工对接客户信息,包括用户电话、公司、职位等信息,还可以查看用户的意向等操作。页面展示不是jsp,是Ajax请求。动态生成dom节点和数据。
一、数据库设计
/*
Navicat Premium Data Transfer
Source Server : localhost_3306
Source Server Type : MySQL
Source Server Version : 80026
Source Host : localhost:3306
Source Schema : hscrm03
Target Server Type : MySQL
Target Server Version : 80026
File Encoding : 65001
Date: 18/06/2022 18:59:31
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for customer
-- ----------------------------
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer` (
`cid` int NOT NULL AUTO_INCREMENT,
`cname` varchar(12) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`csex` char(3) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`ctel` char(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`cjob` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`ccompany` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`cid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`eid` int NOT NULL AUTO_INCREMENT,
`ename` varchar(12) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`esex` char(3) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`etel` char(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`etx` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`passwd` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`eid`) USING BTREE,
UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Table structure for track
-- ----------------------------
DROP TABLE IF EXISTS `track`;
CREATE TABLE `track` (
`tid` int NOT NULL AUTO_INCREMENT,
`cid` int NULL DEFAULT NULL,
`eid` int NULL DEFAULT NULL,
`record` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`intention` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`tid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
SET FOREIGN_KEY_CHECKS = 1;
二、项目架构设计
三、配置文件
1、web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_0.xsd"
version="3.0">
<!--配置springMVC的编码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<!-- 初始化spring容器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- springmvc-->
<servlet>
<servlet-name>dispacher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- springmvc 子容器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
<!-- tomcat启动就初始化 实例化select-->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispacher</servlet-name>
<!-- 可以接受非js 请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- post请求 转put或delete-->
<filter>
<filter-name>methodeFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>methodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2、applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描bean-->
<context:component-scan base-package="com.vector">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--整合mybatis -->
<!--数据源-->
<context:property-placeholder location="classpath*:database.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--四条连接信息-->
<property name="url" value="${url}"/>
<property name="username" value="${druid.username}"/>
<property name="password" value="${druid.password}"/>
<property name="driverClassName" value="${driverClassName}"/>
<!--连接池信息-->
<property name="maxActive" value="30"></property>
<property name="minIdle" value="10"></property>
<property name="initialSize" value="15"></property>
</bean>
<!-- 会话工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--映射文件的路径-->
<property name="mapperLocations" value="classpath*:mapper/*.xml"></property>
<property name="configLocation" value="classpath:mybatis.xml"></property>
<!--别名-->
<property name="typeAliasesPackage" value="com.vector.domain"></property>
</bean>
<!--实例化mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.vector.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
3、database.properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/hscrm03?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&allowMultiQueries=true
druid.username=root
druid.password=123456
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
filters=wall,stat
#最小空闲连接数
minIdle=3
#最大空闲连接数
maxIdle=15
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis=300000
#连接有效性检查的SQL
validationQuery=SELECT 'x'
#连接有效性检查的超时时间 1 秒 -->
validationQueryTimeout=1
#从连接池获取到连接后,如果超过被空闲剔除周期,是否做一次连接有效性检查
testWhileIdle=true
#从连接池获取连接后,是否马上执行一次检查
testOnBorrow=false
#归还连接到连接池时是否马上做一次检查
testOnReturn=false
maxOpenPreparedStatements=20
#强行关闭从连接池获取而长时间未归还给druid的连接(认为异常连接)
removeAbandoned=true
#异常连接判断条件,超过180 秒 则认为是异常的,需要强行关闭
removeAbandonedTimeout=1800
#记录被判定为异常的连接
logAbandoned=true
#如果空闲时间太长即使连接池所剩连接 < minIdle 也会被剔除 55 秒 -->
maxEvictableIdleTimeMillis=55000
#是否设置自动提交,相当于每个语句一个事务
defaultAutoCommit=true
4、mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--插件引入mybatis-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 方言-->
<property name="helperDialect" value="mysql"/>
<!-- 如果pageSize为0,不分页-->
<property name="pageSizeZero" value="true"/>
</plugin>
</plugins>
</configuration>
5、spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描controller-->
<context:component-scan base-package="com.vector.controller"></context:component-scan>
<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 静态资源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/emp/**" location="/emp/"></mvc:resources>
<!-- 解决响应字符串数据的乱码问题 -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"></constructor-arg>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"></property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/"></property>
<!-- 后缀-->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
四、注册功能实现
1、regist.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css?family=Permanent+Marker" rel="stylesheet">
</head>
<body>
<div class="signup-form">
<form class="" action="" method="post">
<h1>Sign In</h1>
<input type="text" placeholder="用户名" class="txtb" id="username">
<input type="password" placeholder="密码" class="txtb" id="passwd">
<input type="password" placeholder="确认密码" class="txtb" id="passwd2">
<input type="text" placeholder="姓名" class="txtb" id="ename">
<div class="sex">
<span>性别:</span>
<input class="dx" type="radio" name="esex" value="男" checked>男
<input class="dx" type="radio" name="esex" value="女">女
</div>
<input type="text" placeholder="电话" class="txtb" id="etel">
<input type="button" value="注册 " class="signup-btn" id="btn1">
<a href="login.html ">Already Have one ?</a>
</form>
</div>
<script src="js/jquery-3.6.0.js"></script>
<script>
$("#btn1").click(function () {
//获取数据
var username = $("#username").val();
var passwd = $("#passwd").val();
var passwd2 = $("#passwd2").val();
var ename = $("#ename").val();
var esex;
if ($(".dx").get(0).checked) {
esex = '男';
} else {
esex = '女';
}
var etel = $("#etel").val();
//发送请求
$.ajax({
url: "/crm/reg",
type: "post",
data: {
ename: ename,
esex: esex,
etel: etel,
username: username,
passwd: passwd
},
success: function (respTxt) {
if (respTxt.data == -1) {
alert("用户名已存在!");
alert(respTxt.message);
return;
}
if (respTxt.data == 1) {
alert("注册成功!");
alert(respTxt.message);
location.href = "login.html";
} else {
alert("注册失败!");
return;
}
}
});
});
</script>
</body>
</html>
2、EmpController
@RestController
public class EmpController {
@Autowired
private EmpService empService;
/**
* 注册
*/
@RequestMapping("/crm/reg")
public ResponseEntity<Integer> reg(Emp emp) {
emp.setPasswd(MD5Util.toMd5(emp.getPasswd()));
int i = empService.addEmp(emp);
ResponseEntity<Integer> responseEntity = new ResponseEntity<>();
if (i == -1) {
responseEntity.setCode(200);
responseEntity.setMessage("用户名已存在!");
responseEntity.setData(i);
return responseEntity;
}
if (i == -2) {
responseEntity.setCode(500);
responseEntity.setMessage("添加失败!");
responseEntity.setData(i);
return responseEntity;
}
responseEntity.setCode(200);
responseEntity.setMessage("添加成功!");
responseEntity.setData(i);
return responseEntity;
}
}
3、EmpService
public interface EmpService {
/**
* 注册 (添加员工)
*/
int addEmp(Emp emp);
}
4、EmpServiceImpl
/**
* @description:
* @Title: EmpServiceImpl
* @Package com.vector.service.impl
* @Author 芝士汉堡
* @Date 2022/6/14 10:05
*/
@Service
public class EmpServiceImpl implements EmpService {
@Resource
private EmpMapper empMapper;
/**
* 注册 (添加员工)
*
* @param emp
*/
@Override
public int addEmp(Emp emp) {
try {
Emp empByUsername = empMapper.findEmpByUsername(emp.getUsername());
if (empByUsername == null) {
int i = empMapper.addEmp(emp);
return i;
} else {
//用户已被注册
return -1;
}
} catch (Exception e) {
//注册失败
return -2;
}
}
}
5、EmpMapper
public interface EmpMapper {
/**
* 注册 (添加员工)
*/
int addEmp(Emp emp);
}
6、Emp
/**
* @description:
* @Title: Emp
* @Package com.vector.domain
* @Author 芝士汉堡
* @Date 2022/6/14 8:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private int eid;
private String ename;
private String esex;
private String etel;
private String etx;
private String username;
private String passwd;
}
四、登录功能实现
1、login.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css?family=Permanent+Marker" rel="stylesheet">
</head>
<body>
<div class="signup-form">
<form class="" action="" method="post">
<h1>Sign Up</h1>
<input type="text" placeholder="用户名" class="txtb" id="username">
<input type="password" placeholder="密码" class="txtb" id="passwd">
<input type="button" value="登录" class="signup-btn" id="btn">
<a href="reg.html">No account yet ?</a>
</form>
</div>
<script src="js/jquery-3.6.0.js"></script>
<script>
//给登录按钮绑定点击事件
$("#btn").click(function () {
//获取数据
var username = $("#username").val();
var passwd = $("#passwd").val();
//发送请求
$.ajax({
url: "/reg/login",
type: "post",
data: {
username: username,
passwd: passwd
},
success: function (respTxt) {
if (respTxt.data == -2) {
alert("用户名不存在!");
return;
}
if (respTxt.data == -1) {
alert("您输入的账户或密码错误!");
return;
}
alert("登录成功!");
location.href = " /emp/index.html?eid="+respTxt.data;
}
});
});
</script>
</body>
</html>
2、EmpController
@RestController
public class EmpController {
@Autowired
private EmpService empService;
/**
* 登录
*/
@RequestMapping("/reg/login")
public ResponseEntity<Integer> login(Emp emp) {
emp.setPasswd(MD5Util.toMd5(emp.getPasswd()));
int i = empService.login(emp);
ResponseEntity<Integer> responseEntity = new ResponseEntity<>();
if (i == -1) {
responseEntity.setCode(200);
responseEntity.setMessage("用户密码输入错误!");
responseEntity.setData(i);
return responseEntity;
}
if (i == -2) {
responseEntity.setCode(500);
responseEntity.setMessage("没有此用户!");
responseEntity.setData(i);
return responseEntity;
}
responseEntity.setCode(200);
responseEntity.setMessage("登录成功!");
responseEntity.setData(i);
return responseEntity;
}
}
3、EmpService
public interface EmpService {
/**
* 登录 (通过用户名查找员工)
*/
int login(Emp emp);
}
4、EmpServiceImpl
/**
* @description:
* @Title: EmpServiceImpl
* @Package com.vector.service.impl
* @Author 芝士汉堡
* @Date 2022/6/14 10:05
*/
@Service
public class EmpServiceImpl implements EmpService {
@Resource
private EmpMapper empMapper;
/**
* 登录
*
* @param emp
*/
@Override
public int login(Emp emp) {
try {
Emp emp1 = empMapper.findEmpByUsername(emp.getUsername());
if (emp1.getPasswd().equals(emp.getPasswd())) {
//密码正确
return emp1.getEid();
}
//用户输入密码错误
return -1;
} catch (Exception e) {
//用户未注册·用户名输入错误
return -2;
}
}
}
5、EmpMapper
public interface EmpMapper {
/**
* 登录 (通过用户名查找员工)
*/
Emp findEmpByUsername(String username);
}
6、Emp
/**
* @description:
* @Title: Emp
* @Package com.vector.domain
* @Author 芝士汉堡
* @Date 2022/6/14 8:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private int eid;
private String ename;
private String esex;
private String etel;
private String etx;
private String username;
private String passwd;
}
五、跟踪信息功能实现
1、展示
2、添加
3、修改
六、跟踪信息功能实现
1、展示
2、添加
3、修改
七、密码修改
总结
博客只给了部分代码,全套资源+sql(开源),均已上传。