CRM(客户关系管理)系统是企业管理中重要的一环,本文实现的Java+MySQL CRM系统采用MVC架构模式,结合Spring Boot、MyBatis-Plus等技术,实现了客户信息管理、销售机会跟踪、合同管理、统计分析等核心功能。
├── src/main/java
│ └── com/crm
│ ├── config (配置类)
│ ├── controller (控制器层)
│ ├── entity (实体类)
│ ├── mapper (数据访问层)
│ ├── service (业务逻辑层)
│ ├── dto (数据传输对象)
│ └── utils (工具类)
└── src/main/resources
├── static (静态资源)
├── templates (视图模板)
└── application.yml (配置文件)
// Customer.java
@Data
@TableName("customer")
public class Customer {
@TableId(type = IdType.AUTO)
private Long id;
private String customerName;
private String industry;
private String scale;
private String contactPerson;
private String phone;
private String email;
private String address;
private Integer status;
private Date createTime;
private Date updateTime;
}
// Opportunity.java
@Data
@TableName("opportunity")
public class Opportunity {
@TableId(type = IdType.AUTO)
private Long id;
private Long customerId;
private String opportunityName;
private Double amount;
private Integer stage;
private String probability;
private String responsiblePerson;
private Date expectedClosingDate;
private Date createTime;
}
// CustomerMapper.java
@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {
// 自定义SQL查询
@Select("SELECT * FROM customer WHERE status = #{status}")
List<Customer> selectByStatus(Integer status);
// 分页查询
IPage<Customer> selectPageVo(Page<Customer> page, @Param("ew") Wrapper<Customer> queryWrapper);
}
// OpportunityMapper.java
@Mapper
public interface OpportunityMapper extends BaseMapper<Opportunity> {
// 关联查询客户信息
@Select("SELECT o.*, c.customer_name FROM opportunity o " +
"LEFT JOIN customer c ON o.customer_id = c.id " +
"WHERE o.id = #{id}")
OpportunityVO selectOpportunityVOById(Long id);
}
// CustomerServiceImpl.java
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {
@Autowired
private CustomerMapper customerMapper;
@Override
public Page<Customer> getCustomerPage(int pageNum, int pageSize, String keyword) {
Page<Customer> page = new Page<>(pageNum, pageSize);
QueryWrapper<Customer> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(keyword)) {
wrapper.like("customer_name", keyword)
.or().like("contact_person", keyword)
.or().like("phone", keyword);
}
return customerMapper.selectPage(page, wrapper);
}
@Override
public boolean saveCustomer(Customer customer) {
if (customer.getId() == null) {
customer.setCreateTime(new Date());
return save(customer);
} else {
customer.setUpdateTime(new Date());
return updateById(customer);
}
}
}
// OpportunityServiceImpl.java
@Service
public class OpportunityServiceImpl extends ServiceImpl<OpportunityMapper, Opportunity> implements OpportunityService {
@Autowired
private OpportunityMapper opportunityMapper;
@Override
public List<Opportunity> getOpportunitiesByCustomerId(Long customerId) {
QueryWrapper<Opportunity> wrapper = new QueryWrapper<>();
wrapper.eq("customer_id", customerId);
return opportunityMapper.selectList(wrapper);
}
@Override
public boolean updateOpportunityStage(Long id, Integer stage) {
Opportunity opportunity = new Opportunity();
opportunity.setId(id);
opportunity.setStage(stage);
return updateById(opportunity);
}
}
// CustomerController.java
@RestController
@RequestMapping("/api/customer")
@Api(tags = "客户管理")
public class CustomerController {
@Autowired
private CustomerService customerService;
@GetMapping("/list")
@ApiOperation("客户列表分页查询")
public Result<Page<Customer>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String keyword) {
Page<Customer> page = customerService.getCustomerPage(pageNum, pageSize, keyword);
return Result.success(page);
}
@PostMapping("/save")
@ApiOperation("保存客户信息")
public Result<?> save(@RequestBody Customer customer) {
boolean result = customerService.saveCustomer(customer);
return result ? Result.success() : Result.error("保存失败");
}
@DeleteMapping("/{id}")
@ApiOperation("删除客户")
public Result<?> delete(@PathVariable Long id) {
boolean result = customerService.removeById(id);
return result ? Result.success() : Result.error("删除失败");
}
}
// OpportunityController.java
@RestController
@RequestMapping("/api/opportunity")
@Api(tags = "销售机会管理")
public class OpportunityController {
@Autowired
private OpportunityService opportunityService;
@GetMapping("/list/{customerId}")
@ApiOperation("获取客户的销售机会")
public Result<List<Opportunity>> listByCustomerId(@PathVariable Long customerId) {
List<Opportunity> list = opportunityService.getOpportunitiesByCustomerId(customerId);
return Result.success(list);
}
@PostMapping("/updateStage")
@ApiOperation("更新销售机会阶段")
public Result<?> updateStage(@RequestParam Long id, @RequestParam Integer stage) {
boolean result = opportunityService.updateOpportunityStage(id, stage);
return result ? Result.success() : Result.error("更新失败");
}
}
// SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/static/**", "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/index")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
<table class="table table-striped">
<thead>
<tr>
<th>IDth>
<th>客户名称th>
<th>行业th>
<th>规模th>
<th>联系人th>
<th>电话th>
<th>状态th>
<th>操作th>
tr>
thead>
<tbody>
<tr th:each="customer : ${page.records}">
<td th:text="${customer.id}">td>
<td th:text="${customer.customerName}">td>
<td th:text="${customer.industry}">td>
<td th:text="${customer.scale}">td>
<td th:text="${customer.contactPerson}">td>
<td th:text="${customer.phone}">td>
<td>
<span th:if="${customer.status == 1}" class="badge bg-success">正常span>
<span th:if="${customer.status == 0}" class="badge bg-danger">暂停span>
td>
<td>
<button class="btn btn-sm btn-primary" th:onclick="|editCustomer(${customer.id})|">编辑button>
<button class="btn btn-sm btn-danger" th:onclick="|deleteCustomer(${customer.id})|">删除button>
td>
tr>
tbody>
table>
<script>
function editCustomer(id) {
window.location.href = "/customer/edit/" + id;
}
function deleteCustomer(id) {
if (confirm("确定要删除该客户吗?")) {
fetch("/api/customer/" + id, {
method: "DELETE"
}).then(response => {
if (response.ok) {
alert("删除成功");
location.reload();
} else {
alert("删除失败");
}
});
}
}
script>
<div class="card">
<div class="card-header">
销售机会跟踪 - [[${opportunity.opportunityName}]]
div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<p>客户名称: [[${customer.customerName}]]p>
<p>金额: [[${opportunity.amount}]]p>
<p>阶段:
<select id="stageSelect" class="form-select form-select-sm">
<option value="1" th:selected="${opportunity.stage == 1}">初步接触option>
<option value="2" th:selected="${opportunity.stage == 2}">需求分析option>
<option value="3" th:selected="${opportunity.stage == 3}">方案制定option>
<option value="4" th:selected="${opportunity.stage == 4}">商务谈判option>
<option value="5" th:selected="${opportunity.stage == 5}">签约成交option>
<option value="6" th:selected="${opportunity.stage == 6}">丢失option>
select>
p>
<p>预计成交日期: [[${#dates.format(opportunity.expectedClosingDate, 'yyyy-MM-dd')}]]p>
div>
<div class="col-md-6">
<p>负责人: [[${opportunity.responsiblePerson}]]p>
<p>成功率: [[${opportunity.probability}]]p>
<p>创建时间: [[${#dates.format(opportunity.createTime, 'yyyy-MM-dd HH:mm')}]]p>
div>
div>
<div class="mt-4">
<h5>历史跟进记录h5>
<ul class="list-group" id="followUpList">
ul>
div>
<div class="mt-4">
<h5>添加跟进记录h5>
<textarea id="followUpContent" class="form-control" rows="3">textarea>
<button class="btn btn-primary mt-2" onclick="addFollowUp()">提交button>
div>
div>
div>
mvn clean package
java -jar target/crm-system.jar
// CustomerServiceTest.java
@SpringBootTest
class CustomerServiceTest {
@Autowired
private CustomerService customerService;
@Test
void testSaveCustomer() {
Customer customer = new Customer();
customer.setCustomerName("测试客户");
customer.setIndustry("信息技术");
customer.setScale("中型企业");
customer.setContactPerson("张三");
customer.setPhone("13800138000");
customer.setStatus(1);
boolean result = customerService.saveCustomer(customer);
assertTrue(result);
Customer savedCustomer = customerService.getById(customer.getId());
assertNotNull(savedCustomer);
assertEquals("测试客户", savedCustomer.getCustomerName());
}
@Test
void testGetCustomerPage() {
Page<Customer> page = customerService.getCustomerPage(1, 10, null);
assertNotNull(page);
assertTrue(page.getTotal() >= 0);
}
}
本系统实现了CRM系统的核心功能,采用Java+MySQL技术栈,结合Spring Boot框架,具有良好的可扩展性和维护性。系统采用前后端分离的设计思想,提供了友好的用户界面和完善的API接口,可作为企业级CRM系统的基础框架进行二次开发。