ERP项目(进销存仓储管理系统)-1
主要技术点
一、数据库
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集合中,然后取出数据做后续处理,比如存到数据库中@Overridepublic ImportResult excelImport(InputStream inputStream) {//解析Excel,转换成ListList<MaterialInputExcelModel> list = new ArrayList<>();try {EasyExcel.read(inputStream).head(MaterialInputExcelModel.class).sheet().registerReadListener(new AnalysisEventListener<MaterialInputExcelModel>() {@Overridepublic void invoke(MaterialInputExcelModel excelData, AnalysisContext analysisContext) {list.add(excelData); // 将解析好的每个对象放入到定义好的list中}@Overridepublic 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);//查询物料IDQueryWrapper<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());//查询仓库名称IDQueryWrapper<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());//假设一个userNamematerialInput.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);