本文在
https://www.jianshu.com/p/d614ac030e7c: 在pigx-visual之外构建微服务
https://www.jianshu.com/p/353793d668ab: pigx数据库操作示例
https://www.jianshu.com/p/bd81ad89035a:pigx开发示范之旅:项目规划
基础上开始,本模块主要示范多对多的开发。
一、用 代码生成工具 生成客户模块相关表文件
客户模块涉及三张表,cst_customer、bas_qualification、cst_customer_qualification
其中:cst_customer、cst_customer_qualification属于customer模块,bas_qualification属于base模块,它们分别对应目录结构中的customer及base目录。
生成三张表的文件后,将生成的后端代码复制到相应目录,注意还有mpper.xml文件。
二、修改 实体 类
由于表的主键采用UUID,所以需要修改实体类的Id属性,如下
原来为:
@TableId
private Stringid;
改为:
@TableId(value="id",type=IdType.UUID)
private Stringid;
这里只修改customer、qualification实体
三、客户模块功能设计
实现客户的增删改查
增加实现客户和客户的资质一起增加,即客户表和客户的资质表一起保存,增加是时,如果客户id、客户名称已存在,则提示:客户已存在,保存失败!
删除实现客户和客户的资质一起删除
修改实现客户和客户的资质一起修改,如果修改后的客户名称已存在,则提示:客户名称重复,更新失败!
查询实现按关键字匹配客户名称、资质名称,同时资质表在前端作为下拉查询条件匹配资质名称
四、值对象设计
从需求来看,客户对象包含客户资质对象,在customer实体中只有cst_customer表的字段属性,由于customer实体是自动生成的,考虑需求变化对表结构的影响,因此不在customer实体中添加对客户资质对象的引用,单独建立一个值对象CustomerVO来负责与前端交互,增删改查操作的对象都将是CustomerVO。
package com.mycompany.mydemo.customer.vo;
import com.mycompany.mydemo.base.entity.Qualification;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class CustomerVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private String id;
/**
* 客户名称
*/
private String name;
/**
* 资质列表
*/
private List
}
在客户查询这个需求上,有两个查询条件,一个是关键字、另一个是资质名称,在前端会以对象的形式传到后端,因此后端需要一个对象接收,为保持单一性,特建立一个CustomerRVO的类来接收前端的查询条件数据。
package com.mycompany.mydemo.customer.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 查询客户的查询条件VO
*/
@Data
public class CustomerRVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 关键字
*/
private String keyWord;
/**
* 资质名称
*/
private String qualificationName;
}
五、Service与Controller设计
在生成的代码中,已有三张表的Service、Controller,但在项目中,从前端操作来看,只会有客户及资质的概念,而客户资质属于客户,因此,对三个Service、Controller的职责做如下界定:
1:接入前端只有CustomerController 和 QualificationController,它们各自负责客户及资质的交互,CustomerQualificationController删除掉。
2:对于CustomerQualificationService,只负责关系表的增删改的操作,并且是批量操作,这些操作由CustomerService调用。
3:Controller只负责中转请求和返回Service执行的结果(包括异常),每一个请求后调用Service的一个方法,Service负责业务规则、业务逻辑的检查、计算及抛出异常,特别注意:如果抛出自定义异常,这个异常类必须继承RuntimeException,不能继承于Exception,否则Controller捕获不到异常,无法将异常消息以R对象的形式返回给前端。
CustomerService示例代码
package com.mycompany.mydemo.customer.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mycompany.common.exception.BussinessException;
import com.mycompany.mydemo.customer.entity.Customer;
import com.mycompany.mydemo.customer.mapper.CustomerMapper;
import com.mycompany.mydemo.customer.service.CustomerService;
import com.mycompany.mydemo.customer.service.CustomerQualificationService;
import com.mycompany.mydemo.customer.vo.CustomerRVO;
import com.mycompany.mydemo.customer.vo.CustomerVO;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.List;
/**
*
*
* @author pigx code generator
* @date 2019-05-29 14:41:33
*/
@Service
@AllArgsConstructor
public class CustomerServiceImpl extends ServiceImpl
private final CustomerQualificationService customerQualificationService;
//region 自定义的方法块
/**
* 按关键字查询客户
* @param keyWord
* @return
*/
@SneakyThrows
public List
return baseMapper.getCustomerListByKeyWord(keyWord);
}
/**
* 查询客户列表
* @param customerRVO
* @return
*/
@SneakyThrows
public List
return baseMapper.getCustomerList(customerRVO);
}
/**
* 新增客户及客户资质
* @param customerVO
* @return
*/
@SneakyThrows
@Transactional(rollbackFor = Exception.class)
public boolean addCustomer(CustomerVO customerVO) {
if (baseMapper.selectById(customerVO.getId()) != null){
throw new BussinessException("客户已存在,保存失败!");
}
Customer customer = new Customer();
//复制属性值
BeanUtils.copyProperties(customerVO, customer);
baseMapper.insert(customer);
//保存客户资质表
return customerQualificationService.saveCustomerQualification(customerVO);
}
/**
* 更新客户及客户资质
* @param customerVO
* @return
*/
@SneakyThrows
@Transactional(rollbackFor = Exception.class)
public boolean updateCustomer(CustomerVO customerVO) {
Customer customer = baseMapper.selectById(customerVO.getId());
if (customer == null) {
throw new BussinessException("客户不存在,更新失败!");
}
//复制属性值
BeanUtils.copyProperties(customerVO, customer);
baseMapper.updateById(customer);
//保存客户资质表
return customerQualificationService.saveCustomerQualification(customerVO);
}
//endregion
//region 重载基类的方法块
/**
* 按 Id 删除客户及客户资质
* @param id
* @return
*/
@Override
@SneakyThrows
@Transactional(rollbackFor = Exception.class)
public boolean removeById(Serializable id){
//删除客户资质
customerQualificationService.deleteByCustomerId(id);
return super.removeById(id);
}
//endregion
}
CustomerQualificationService示例
package com.mycompany.mydemo.customer.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mycompany.mydemo.customer.entity.CustomerQualification;
import com.mycompany.mydemo.customer.mapper.CustomerQualificationMapper;
import com.mycompany.mydemo.customer.service.CustomerQualificationService;
import com.mycompany.mydemo.customer.vo.CustomerVO;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
/**
*
*
* @author pigx code generator
* @date 2019-05-29 15:02:09
*/
@Service
public class CustomerQualificationServiceImpl extends ServiceImpl
//region 自定义的方法块
/**
* 保存客户资质
* @param customerVO
* @return
*/
public boolean saveCustomerQualification(CustomerVO customerVO){
//先删除再添加
this.deleteByCustomerId(customerVO.getId());
//保存客户资质表
List
.stream().map(qualification -> {
CustomerQualification customerQualification = new CustomerQualification();
customerQualification.setCustomerId(customerVO.getId());
customerQualification.setQualificationId(qualification.getId());
return customerQualification;
}).collect(Collectors.toList());
return this.saveBatch(customerQualificationList);
}
/**
* 按客户Id 删除客户资质
* @param customerId
* @return
*/
public boolean deleteByCustomerId(Serializable customerId){
return baseMapper.deleteByCustomerId(customerId);
}
//endregion
}
六、Mapper映射
CustomerMapper.xml
select ta.id, ta.name, tc.id as qualification_id, tc.name as qualification_name
from cst_customer as ta
left join cst_customer_qualification as tb on ta.id = tb.customer_id
left join bas_qualification as tc on tb.qualification_id = tc.id
where ta.name LIKE CONCAT('%',#{keyWord},'%') or tc.name LIKE CONCAT('%',#{keyWord},'%')
and ta.name LIKE CONCAT('%',#{query.keyWord},'%') or tc.name LIKE CONCAT('%',#{query.keyWord},'%')
and tc.name = #{query.qualificationName}
CustomerQualificationMapper.xml
DELETE FROM cst_customer_qualification WHERE customer_id = #{customerId}