主要技术点
一、数据库
1、用户权限
erp项目是给企业内部员工使用的,所以用户就是员工。有关用户权限的表有5张,包括三张主表和两张中间表。主表分别是角色表、用户表、权限表,中间表分别是角色-用户表、角色-权限表。
2、表中数据的分级
主要是菜单分级(一般在erp项目中,菜单分级对应的就是权限分级)和部门分级,除了数据本身的id外,还有这条数据的父节点id(该字段一般命名为parent_id),也就是上层数据的id,根节点数据由于没有上级数据,所以其父节点为0。
二、根据数据库中的表自动生成实体类和mapper、service、serviceImpl、controller包及其类等文件
以前常用mybatisX插件来实现,现在发现另一种方式更便捷而且不易出错,就是用mybatisPlus的逆向工程。
1、引入mybatis-plus的增强依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>最新版本</version>
</dependency>
2、执行下面的代码
项目中随便写个类,里面定义个main方法,执行下面的代码即可
// 这些代码不用记,网上搜复制粘贴即可
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class Main {
public static void main(String[] args) {
AutoGenerator autoGenerator = new AutoGenerator();
// 数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/store?useUnicode=true&characterEncoding=UTF-8");
autoGenerator.setDataSource(dataSourceConfig);
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOpen(false);
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
globalConfig.setAuthor("admin");
globalConfig.setServiceName("%sService");
autoGenerator.setGlobalConfig(globalConfig);
// 包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.southwind");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
autoGenerator.setPackageInfo(packageConfig);
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setEntityLombokModel(true);
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setInclude("role_authority","role_employee");// 要根据哪些表生成对应的实体类等文件
autoGenerator.setStrategy(strategyConfig);
autoGenerator.execute();
}
}
三、解析excel文件
1、定义模型类
excel表中的每条数据都要解析成一个Java对象,所以要定义一个模型类使得解析excel表时按照这个模型类来解析成Java对象。
// 示例
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class MaterialInputExcelModel {
@ExcelProperty("供应商代码") // excel表的列名
private String supplierCode; // 解析成对象对应的属性名
@ExcelProperty("到货日期")
private String orderDate;
@ExcelProperty("仓库代码")
private String storageCode;
@ExcelProperty("物料编码")
private String materialCode;
@ExcelProperty("物料名称")
private String materialName;
@ExcelProperty("规格型号")
private String style;
@ExcelProperty("计量单位")
private String unitName;
@ExcelProperty("采购单号")
private String orderId;
@ExcelProperty("生产批号")
private String batchNo;
@ExcelProperty("数量")
private BigDecimal orderCount;
}
2、解析逻辑
// serviceImpl中解析excel表的逻辑
// 就是将excel表中的每条数据解析成Java对象(上面定义的模型对象),将这些对象放入到list集合中,然后取出数据做后续处理,比如存到数据库中
@Override
public ImportResult excelImport(InputStream inputStream) {
//解析Excel,转换成List
List<MaterialInputExcelModel> list = new ArrayList<>();
try {
EasyExcel.read(inputStream)
.head(MaterialInputExcelModel.class)
.sheet()
.registerReadListener(new AnalysisEventListener<MaterialInputExcelModel>() {
@Override
public void invoke(MaterialInputExcelModel excelData, AnalysisContext analysisContext) {
list.add(excelData); // 将解析好的每个对象放入到定义好的list中
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}).doRead();
} catch (Exception e){
e.getStackTrace();
}
// 解析完成,进行后续操作
//把List数据存入数据库,持久化
ImportResult importResult = new ImportResult();
int row = 0;
for (MaterialInputExcelModel materialInputExcelModel : list) {
row++;
MaterialInput materialInput = new MaterialInput();
BeanUtils.copyProperties(materialInputExcelModel, materialInput);
//查询物料ID
QueryWrapper<Material> materialQueryWrapper = new QueryWrapper<>();
materialQueryWrapper.eq("material_code", materialInput.getMaterialCode());
Material material = this.materialMapper.selectOne(materialQueryWrapper);
if(material == null){
importResult.setCode(-1);
importResult.setMsg("【第"+row+"行错误】,物料不存在!");
return importResult;
}
materialInput.setMaterialId(material.getMaterialId());
//查询供应商名称
QueryWrapper<Supplier> supplierQueryWrapper = new QueryWrapper<>();
supplierQueryWrapper.eq("supplier_code", materialInputExcelModel.getSupplierCode());
Supplier supplier = this.supplierMapper.selectOne(supplierQueryWrapper);
if(supplier == null) {
importResult.setCode(-1);
importResult.setMsg("【第"+row+"行错误】,供应商不存在!");
return importResult;
}
materialInput.setSupplierId(supplier.getSupplierId());
materialInput.setSupplierName(supplier.getSupplierName());
//查询仓库名称ID
QueryWrapper<Storage> storageQueryWrapper = new QueryWrapper<>();
storageQueryWrapper.eq("storage_code", materialInputExcelModel.getStorageCode());
Storage storage = this.storageMapper.selectOne(storageQueryWrapper);
if(storage == null){
importResult.setCode(-1);
importResult.setMsg("【第"+row+"行错误】,仓库不存在!");
return importResult;
}
materialInput.setStorageName(storage.getStorageName());
materialInput.setStorageId(storage.getStorageId());
//假设一个userName
materialInput.setUserName("张三");
materialInput.setStatus(0);
//日期
materialInput.setOrderDate(CommonUtils.parseString(materialInputExcelModel.getOrderDate()));
//判断批号是否重复,如果不重复则保存,如果重复则覆盖
QueryWrapper<MaterialInput> materialInputQueryWrapper = new QueryWrapper<>();
materialInputQueryWrapper.eq("batch_no", materialInput.getBatchNo());
MaterialInput materialInput1 = this.materialInputMapper.selectOne(materialInputQueryWrapper);
if(materialInput1 != null){
Integer materialInputId = materialInput1.getMaterialInputId();
//判断订单状态,如果是未审核则进行覆盖
if(materialInput1.getStatus().equals(0)){
//覆盖
BeanUtils.copyProperties(materialInput, materialInput1);
materialInput1.setMaterialInputId(materialInputId);
int updateById = this.materialInputMapper.updateById(materialInput1);
if(updateById != 1) {
importResult.setCode(-1);
importResult.setMsg("更新失败!");
return importResult;
}
}
} else {
int insert = this.materialInputMapper.insert(materialInput);
if(insert != 1) {
importResult.setCode(-1);
importResult.setMsg("保存失败!");
return importResult;
}
}
}
importResult.setCode(0);
importResult.setMsg("导入成功!");
return importResult;
}
3、可能会遇到的问题:解析报错
错误原因:excel表中的到货日期列中的数据是数字类型的,如2024/1/26,而模型类中对应的属性是LocalDateTime类型的,类型不匹配,导致解析错误。
解决办法:将模型类中对应的属性改成String类型即可,后续对其有逻辑处理再转换成日期类型。
四、字符串类型的时间数据转换成LocalDateTime类型的时间数据
如果字符串是这种"2024-08-26 10:30:56"年月日以短横线相隔的,直接用DateTimeFormatter转换即可。
String str = "2024-08-26 10:30:56"
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.parse(str, dateTimeFormatter);
如果字符串是这种"2024/8/26"年月日以斜线相隔的,而且还没有时分秒,则要先将这个字符串改写成这种"2024-08-26 00:00:00"年月日以短横线相隔的,没有时分秒也要补上时分秒,然后再用DateTimeFormatter转换。
String string = "2024/8/26"
String[] split = string.split("/");
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < split.length; i++) {
if(i < split.length - 1){
if(split[i].length() == 1){
stringBuffer.append("0").append(split[i]).append("-");
} else {
stringBuffer.append(split[i]).append("-");
}
} else {
if(split[i].length() == 1){
stringBuffer.append("0").append(split[i]);
} else {
stringBuffer.append(split[i]);
}
}
}
stringBuffer.append(" 00:00:00");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.parse(stringBuffer.toString(), dateTimeFormatter);