diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/manager/AddressManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/manager/AddressManager.java index b48e0fe..d366ae9 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/manager/AddressManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/manager/AddressManager.java @@ -5,16 +5,21 @@ import lombok.extern.slf4j.Slf4j; import net.lab1024.sa.admin.constant.AdminCacheConst; import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; - import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; -import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 收货地址 Manager + * 收货单位 Manager * * @author hj * @since 2024-12-26 15:35:23 @@ -27,19 +32,156 @@ public class AddressManager extends ServiceImpl { @Resource private AddressDao addressDao; + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); + /** - * 根据类目id 移除缓存 + * 查询收货单位(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @CacheEvict(value = {AdminCacheConst.Base.ADDRESS_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear ADDRESS_ENTITY"); + @Cacheable(value = AdminCacheConst.Base.ADDRESS_ENTITY, key = "#addressId", unless = "#result == null") + public AddressEntity queryAddress(Long addressId) { + try { + readLock.lock(); + return addressDao.selectById(addressId); + } finally { + readLock.unlock(); + } } /** - * 查詢类目 + * 创建收货单位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 */ - @Cacheable(AdminCacheConst.Base.ADDRESS_ENTITY) - public AddressEntity queryAddress(Long addressId) { - return addressDao.selectById(addressId); + @Transactional(rollbackFor = Exception.class) + public AddressEntity insert(AddressEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新收货单位缓存", () -> refreshCache(entity.getAddressId())); + return entity; } + + /** + * 更新收货单位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public AddressEntity update(AddressEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新收货单位缓存", () -> refreshCache(entity.getAddressId())); + return entity; + } + + /** + * 删除收货单位(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long addressId) { + super.removeById(addressId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除收货单位缓存", () -> evictCache(addressId)); + } + + /** + * 批量创建收货单位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchInsert(List entities) { + super.saveBatch(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新收货单位缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量更新收货单位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchUpdate(List entities) { + super.updateBatchById(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新收货单位缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量删除收货单位(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List addressIds) { + super.removeByIds(addressIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除收货单位缓存", () -> addressIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long addressId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(addressId); + // 重新查询并缓存最新数据 + AddressEntity entity = addressDao.selectById(addressId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.ADDRESS_ENTITY); + if (cache != null) { + cache.put(addressId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 批量刷新缓存 + * 先收集所有ID,再逐一刷新,减少锁争用 + */ + private void batchRefreshCache(Collection entities) { + List addressIds = entities.stream() + .map(AddressEntity::getAddressId) + .distinct() + .toList(); + addressIds.forEach(this::refreshCache); + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long addressId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.ADDRESS_ENTITY); + if (cache != null) { + cache.evict(addressId); + } + } finally { + writeLock.unlock(); + } + } + } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressQueryService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressQueryService.java index 560d8be..7394ac0 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressQueryService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressQueryService.java @@ -1,50 +1,23 @@ package net.lab1024.sa.admin.module.business.wms.base.address.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Maps; -import jakarta.annotation.Resource; -import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressQueryForm; import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressSelect; import net.lab1024.sa.admin.module.business.wms.base.address.domain.vo.AddressExcelVO; import net.lab1024.sa.admin.module.business.wms.base.address.domain.vo.AddressVO; -import net.lab1024.sa.admin.module.business.wms.base.address.manager.AddressManager; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.vo.ItemsExcelVO; -import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; import net.lab1024.sa.base.common.domain.PageResult; -import net.lab1024.sa.base.common.util.SmartPageUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; - -@Service -public class AddressQueryService { - - @Resource - private AddressDao addressDao; - - @Resource - private AddressManager addressManager; +public interface AddressQueryService { /** * 分页查询 * * @param queryForm 查询参数 * @return PageResult */ - public PageResult queryPage(AddressQueryForm queryForm) { - Page page = SmartPageUtil.convert2PageQuery(queryForm); - List list = addressDao.queryPage(page, queryForm); - return SmartPageUtil.convert2PageResult(page, list); - } + PageResult queryPage(AddressQueryForm queryForm); /** * 地址下拉查询 @@ -52,9 +25,7 @@ public class AddressQueryService { * @param addressSelect 入参 * @return List */ - public List queryAddress(AddressSelect addressSelect) { - return addressDao.selectList(null); - } + List queryAddress(AddressSelect addressSelect); /** * 根据地址id集合查询地址信息 @@ -62,20 +33,8 @@ public class AddressQueryService { * @param addressIdList 地址id集合 * @return Map */ - public Map queryAddressList(List addressIdList) { - if (CollectionUtils.isEmpty(addressIdList)) { - return Collections.emptyMap(); - } - addressIdList = addressIdList.stream().distinct().collect(Collectors.toList()); - Map addressMap = Maps.newHashMap(); - for (Long addressId : addressIdList) { - AddressEntity address = addressManager.queryAddress(addressId); - if (address != null) { - addressMap.put(addressId, address); - } - } - return addressMap; - } + Map queryAddressList(List addressIdList); + /** * 根据地址name集合查询地址信息 @@ -83,49 +42,13 @@ public class AddressQueryService { * @param addressNameList 地址name集合 * @return Map */ - public Map queryAddressByNameList(List addressNameList) { - if (CollectionUtils.isEmpty(addressNameList)) { - return Collections.emptyMap(); - } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(AddressEntity::getName, addressNameList); - - List addressList = addressDao.selectList(queryWrapper); - if (CollectionUtils.isEmpty(addressList)) { - return Collections.emptyMap(); - } - return addressList.stream() - .collect(Collectors.toMap(AddressEntity::getName, address -> address, (existing, replacement) -> existing)); - } - - /** - * 根据地址名称查询地址信息 - * - * @param addressName 地址名称 - * @return AddressEntity - */ - public AddressEntity queryByAddressName(String addressName) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(AddressEntity::getName, addressName); - return addressDao.selectOne(queryWrapper); - } + Map queryAddressByNameList(List addressNameList); /** * 地址导出 * * @return List */ - public List getAddressExcelVOList() { - List addressList = addressDao.selectList(null); - return addressList.stream() - .map(address -> - AddressExcelVO.builder() - .name(address.getName()) - .person(address.getPerson()) - .telephone(address.getTelephone()) - .address(address.getAddress()) - .build() - ) - .collect(Collectors.toList()); - } + List getAddressExcelVOList(); + } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressService.java index 8dc2ec6..b6f3c79 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/AddressService.java @@ -1,38 +1,12 @@ package net.lab1024.sa.admin.module.business.wms.base.address.service; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import cn.idev.excel.FastExcel; -import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; +import java.util.List; + import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressAddForm; -import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressImportForm; import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.address.manager.AddressManager; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemsImportForm; -import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; -import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; -import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressImportForm; -import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.address.manager.AddressManager; -import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; -import net.lab1024.sa.base.common.exception.BusinessException; -import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.util.SmartRequestUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; /** @@ -43,17 +17,7 @@ import org.springframework.web.multipart.MultipartFile; * copyright 友仓 */ -@Service -public class AddressService { - - @Resource - private AddressDao addressDao; - - @Resource - private AddressManager addressManager; - - @Resource - private AddressQueryService addressQueryService; +public interface AddressService { /** * 添加 @@ -61,15 +25,7 @@ public class AddressService { * @param addForm 添加参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO add(AddressAddForm addForm) { - AddressEntity addressEntity = SmartBeanUtil.copy(addForm, AddressEntity.class); - addressDao.insert(addressEntity); - - //更新缓存 - addressManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO add(AddressAddForm addForm); /** * 更新 @@ -77,15 +33,7 @@ public class AddressService { * @param updateForm 更新参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO update(AddressUpdateForm updateForm) { - AddressEntity addressEntity = SmartBeanUtil.copy(updateForm, AddressEntity.class); - addressDao.updateById(addressEntity); - - //更新缓存 - addressManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO update(AddressUpdateForm updateForm); /** * 批量删除 @@ -93,18 +41,7 @@ public class AddressService { * @param idList 集合 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)) { - return ResponseDTO.ok(); - } - - addressManager.removeBatchByIds(idList); - - //更新缓存 - addressManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO batchDelete(List idList); /** * 单个删除 @@ -112,17 +49,7 @@ public class AddressService { * @param addressId id * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO delete(Long addressId) { - if (null == addressId) { - return ResponseDTO.ok(); - } - - addressDao.deleteById(addressId); - //更新缓存 - addressManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO delete(Long addressId); /** * 收货地址导入 @@ -130,45 +57,7 @@ public class AddressService { * @param file 上传文件 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO importAddress(MultipartFile file) { - List dataList; - try { - dataList = FastExcel.read(file.getInputStream()).head(AddressImportForm.class) - .sheet() - .doReadSync(); - } catch (IOException e) { - throw new BusinessException("数据格式存在问题,无法读取"); - } - if (CollectionUtils.isEmpty(dataList)) { - return ResponseDTO.userErrorParam("数据为空"); - } - - //获取所有去重后的收货单位 - List addressName = dataList.stream().map(AddressImportForm::getName).distinct().collect(Collectors.toList()); - - //查询数据库存在的物料 - Map exitAddressMap = addressQueryService.queryAddressByNameList(addressName); - - List insertToAddress = new ArrayList<>(); - List updateToAddress = new ArrayList<>(); - for (AddressImportForm addressImportForm : dataList) { - - - //物料 - AddressEntity address = exitAddressMap.get(addressImportForm.getName()); - - //物料为空则新增,否则更新 - if (address == null) { - insertToAddress.add(createAddress(addressImportForm.getName(), addressImportForm.getPerson(), addressImportForm.getTelephone(), addressImportForm.getAddress())); - } else { - updateToAddress.add(createAddress(addressImportForm.getName(), addressImportForm.getPerson(), addressImportForm.getTelephone(), addressImportForm.getAddress())); - } - } - - JoinerResult resultMsg = JoinerResult.createJoiner(); - return ResponseDTOUtils.buildResponseSussDTO(insertToAddress, updateToAddress, addressManager::saveBatch, addressManager::updateBatchById, resultMsg); - } + ResponseDTO importAddress(MultipartFile file); /** * 创建收货地址 @@ -179,14 +68,5 @@ public class AddressService { * @param address 地址 * @return AddressEntity */ - public AddressEntity createAddress(String name, String person, String telephone, String address) { - return AddressEntity.builder() - .name(name) - .person(person) - .telephone(telephone) - .address(address) - .createUserId(SmartRequestUtil.getRequestUser().getUserId()) - .createUserName(SmartRequestUtil.getRequestUser().getUserName()) - .build(); - } + AddressEntity createAddress(String name, String person, String telephone, String address); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressQueryServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressQueryServiceImpl.java new file mode 100644 index 0000000..f3197e1 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressQueryServiceImpl.java @@ -0,0 +1,116 @@ +package net.lab1024.sa.admin.module.business.wms.base.address.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.address.dao.AddressDao; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressQueryForm; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressSelect; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.vo.AddressExcelVO; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.vo.AddressVO; +import net.lab1024.sa.admin.module.business.wms.base.address.manager.AddressManager; +import net.lab1024.sa.admin.module.business.wms.base.address.service.AddressQueryService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AddressQueryServiceImpl implements AddressQueryService { + + @Resource + private AddressDao addressDao; + + @Resource + private AddressManager addressManager; + + /** + * 分页查询 + * + * @param queryForm 查询参数 + * @return PageResult + */ + public PageResult queryPage(AddressQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = addressDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 地址下拉查询 + * + * @param addressSelect 入参 + * @return List + */ + public List queryAddress(AddressSelect addressSelect) { + return addressDao.selectList(null); + } + + /** + * 根据地址id集合查询地址信息 + * + * @param addressIdList 地址id集合 + * @return Map + */ + public Map queryAddressList(List addressIdList) { + if (CollectionUtils.isEmpty(addressIdList)) { + return Collections.emptyMap(); + } + addressIdList = addressIdList.stream().distinct().collect(Collectors.toList()); + Map addressMap = Maps.newHashMap(); + for (Long addressId : addressIdList) { + AddressEntity address = addressManager.queryAddress(addressId); + if (address != null) { + addressMap.put(addressId, address); + } + } + return addressMap; + } + + /** + * 根据地址name集合查询地址信息 + * + * @param addressNameList 地址name集合 + * @return Map + */ + public Map queryAddressByNameList(List addressNameList) { + if (CollectionUtils.isEmpty(addressNameList)) { + return Collections.emptyMap(); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(AddressEntity::getName, addressNameList); + + List addressList = addressDao.selectList(queryWrapper); + if (CollectionUtils.isEmpty(addressList)) { + return Collections.emptyMap(); + } + return addressList.stream() + .collect(Collectors.toMap(AddressEntity::getName, address -> address, (existing, replacement) -> existing)); + } + + /** + * 地址导出 + * + * @return List + */ + public List getAddressExcelVOList() { + List addressList = addressDao.selectList(null); + return addressList.stream() + .map(address -> + AddressExcelVO.builder() + .name(address.getName()) + .person(address.getPerson()) + .telephone(address.getTelephone()) + .address(address.getAddress()) + .build() + ) + .collect(Collectors.toList()); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressServiceImpl.java new file mode 100644 index 0000000..bedcc52 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/address/service/impl/AddressServiceImpl.java @@ -0,0 +1,166 @@ +package net.lab1024.sa.admin.module.business.wms.base.address.service.impl; + +import cn.idev.excel.FastExcel; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.entity.AddressEntity; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressAddForm; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressImportForm; +import net.lab1024.sa.admin.module.business.wms.base.address.domain.form.AddressUpdateForm; +import net.lab1024.sa.admin.module.business.wms.base.address.manager.AddressManager; +import net.lab1024.sa.admin.module.business.wms.base.address.service.AddressQueryService; +import net.lab1024.sa.admin.module.business.wms.base.address.service.AddressService; +import net.lab1024.sa.admin.util.JoinerResult; +import net.lab1024.sa.admin.util.ResponseDTOUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AddressServiceImpl implements AddressService { + + @Resource + private AddressManager addressManager; + + @Resource + private AddressQueryService addressQueryService; + + /** + * 添加 + * + * @param addForm 添加参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(AddressAddForm addForm) { + AddressEntity addressEntity = SmartBeanUtil.copy(addForm, AddressEntity.class); + //新增并更新缓存 + addressManager.insert(addressEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm 更新参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(AddressUpdateForm updateForm) { + AddressEntity addressEntity = SmartBeanUtil.copy(updateForm, AddressEntity.class); + //更新并更新缓存 + addressManager.update(addressEntity); + return ResponseDTO.ok(); + } + + + /** + * 批量删除 + * + * @param idList 集合 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)) { + return ResponseDTO.ok(); + } + + //删除并删除缓存 + addressManager.batchDelete(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + * + * @param addressId id + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long addressId) { + if (null == addressId) { + return ResponseDTO.ok(); + } + + //删除并删除缓存 + addressManager.deleteById(addressId); + return ResponseDTO.ok(); + } + + /** + * 收货地址导入 + * + * @param file 上传文件 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO importAddress(MultipartFile file) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(AddressImportForm.class) + .sheet() + .doReadSync(); + } catch (IOException e) { + throw new BusinessException("数据格式存在问题,无法读取"); + } + if (CollectionUtils.isEmpty(dataList)) { + return ResponseDTO.userErrorParam("数据为空"); + } + + //获取所有去重后的收货单位 + List addressName = dataList.stream().map(AddressImportForm::getName).distinct().collect(Collectors.toList()); + + //查询数据库存在的物料 + Map exitAddressMap = addressQueryService.queryAddressByNameList(addressName); + + List insertToAddress = new ArrayList<>(); + List updateToAddress = new ArrayList<>(); + for (AddressImportForm addressImportForm : dataList) { + + + //物料 + AddressEntity address = exitAddressMap.get(addressImportForm.getName()); + + //物料为空则新增,否则更新 + if (address == null) { + insertToAddress.add(createAddress(addressImportForm.getName(), addressImportForm.getPerson(), addressImportForm.getTelephone(), addressImportForm.getAddress())); + } else { + updateToAddress.add(createAddress(addressImportForm.getName(), addressImportForm.getPerson(), addressImportForm.getTelephone(), addressImportForm.getAddress())); + } + } + + JoinerResult resultMsg = JoinerResult.createJoiner(); + return ResponseDTOUtil.buildResponseDTO(insertToAddress,updateToAddress,addressManager::batchInsert,addressManager::batchUpdate,resultMsg); + } + + /** + * 创建收货地址 + * + * @param name 收货单位 + * @param person 联系人 + * @param telephone 电话 + * @param address 地址 + * @return AddressEntity + */ + public AddressEntity createAddress(String name, String person, String telephone, String address) { + return AddressEntity.builder() + .name(name) + .person(person) + .telephone(telephone) + .address(address) + .createUserId(SmartRequestUtil.getRequestUser().getUserId()) + .createUserName(SmartRequestUtil.getRequestUser().getUserName()) + .build(); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/manager/AreaManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/manager/AreaManager.java index 7a7f35a..da8ae27 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/manager/AreaManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/manager/AreaManager.java @@ -7,15 +7,24 @@ import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEnti import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 库区信息 Manager + * 库区信息 Manager * * @author hj - * @since 2025-03-11 11:12:36 + * @since 2025-03-11 11:12:36 * copyright 友仓 */ @Service @@ -25,20 +34,121 @@ public class AreaManager extends ServiceImpl { @Resource private AreaDao areaDao; - /** - * 根据类目id 移除缓存 - */ - @CacheEvict(value = {AdminCacheConst.Base.AREA_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear AREA_ENTITY"); - } + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); /** - * 查詢类目 + * 查询库区(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @Cacheable(AdminCacheConst.Base.AREA_ENTITY) + @Cacheable(value = AdminCacheConst.Base.AREA_ENTITY, key = "#areaId", unless = "#result == null") public AreaEntity queryArea(Long areaId) { - return areaDao.selectById(areaId); + try { + readLock.lock(); + return areaDao.selectById(areaId); + } finally { + readLock.unlock(); + } } + /** + * 创建库区(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public AreaEntity insert(AreaEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新库区缓存", () -> refreshCache(entity.getAreaId())); + return entity; + } + + /** + * 更新库区(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public AreaEntity update(AreaEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新库区缓存", () -> refreshCache(entity.getAreaId())); + return entity; + } + + /** + * 删除库区(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long areaId) { + super.removeById(areaId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除库区缓存", () -> evictCache(areaId)); + } + + /** + * 批量删除库区(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List areaIds) { + super.removeByIds(areaIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除库区缓存", () -> areaIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long areaId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(areaId); + // 重新查询并缓存最新数据 + AreaEntity entity = areaDao.selectById(areaId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.AREA_ENTITY); + if (cache != null) { + cache.put(areaId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long areaId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.AREA_ENTITY); + if (cache != null) { + cache.evict(areaId); + } + } finally { + writeLock.unlock(); + } + } } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaQueryService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaQueryService.java index 730f69d..c1970bb 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaQueryService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaQueryService.java @@ -1,33 +1,18 @@ package net.lab1024.sa.admin.module.business.wms.base.area.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Maps; -import jakarta.annotation.Resource; -import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; + import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaQueryForm; import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaSelect; import net.lab1024.sa.admin.module.business.wms.base.area.domain.vo.AreaVO; -import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.vo.AreaVO; import net.lab1024.sa.base.common.domain.PageResult; -import net.lab1024.sa.base.common.util.SmartPageUtil; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; -import java.util.Collections; + import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -@Service -public class AreaQueryService { - @Resource - private AreaDao areaDao; - @Resource - private AreaManager areaManager; +public interface AreaQueryService { /** * 分页查询 @@ -35,11 +20,7 @@ public class AreaQueryService { * @param queryForm 查询参数 * @return PageResult */ - public PageResult queryPage(AreaQueryForm queryForm) { - Page page = SmartPageUtil.convert2PageQuery(queryForm); - List list = areaDao.queryPage(page, queryForm); - return SmartPageUtil.convert2PageResult(page, list); - } + PageResult queryPage(AreaQueryForm queryForm); /** * 库区下拉查询 @@ -47,18 +28,7 @@ public class AreaQueryService { * @param areaSelect 入参 * @return List */ - public List queryArea(AreaSelect areaSelect) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - //是否启用 - if (areaSelect.getDisabledFlag() != null) { - queryWrapper.eq(AreaEntity::getDisabledFlag, areaSelect.getDisabledFlag()); - } - //库区名称 - if (CollectionUtils.isNotEmpty(areaSelect.getAreaNames())) { - queryWrapper.in(AreaEntity::getAreaName, areaSelect.getAreaNames()); - } - return areaDao.selectList(queryWrapper); - } + List queryArea(AreaSelect areaSelect); /** * 根据库区id集合查询库区信息 @@ -66,20 +36,7 @@ public class AreaQueryService { * @param areaIdList 库区id集合 * @return Map */ - public Map queryAreaList(List areaIdList) { - if (CollectionUtils.isEmpty(areaIdList)) { - return Collections.emptyMap(); - } - areaIdList = areaIdList.stream().distinct().collect(Collectors.toList()); - Map areaMap = Maps.newHashMap(); - for (Long areaId : areaIdList) { - AreaEntity area = areaManager.queryArea(areaId); - if (area != null) { - areaMap.put(areaId, area); - } - } - return areaMap; - } + Map queryAreaList(List areaIdList); /** * 根据库区name集合查询库区信息 @@ -87,20 +44,7 @@ public class AreaQueryService { * @param areaNameList 库区name集合 * @return Map */ - public Map queryAreaByNameList(List areaNameList) { - if (CollectionUtils.isEmpty(areaNameList)) { - return Collections.emptyMap(); - } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(AreaEntity::getAreaName, areaNameList); - - List areaList = areaDao.selectList(queryWrapper); - if (CollectionUtils.isEmpty(areaList)) { - return Collections.emptyMap(); - } - return areaList.stream() - .collect(Collectors.toMap(AreaEntity::getAreaName, area -> area, (existing, replacement) -> existing)); - } + Map queryAreaByNameList(List areaNameList); /** * 根据库区名称查询库区信息 @@ -108,10 +52,6 @@ public class AreaQueryService { * @param areaName 库区名称 * @return AreaEntity */ - public AreaEntity queryByAreaName(String areaName) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(AreaEntity::getAreaName, areaName); - return areaDao.selectOne(queryWrapper); - } + AreaEntity queryByAreaName(String areaName); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaService.java index ecf5c42..c8543b3 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/AreaService.java @@ -2,26 +2,10 @@ package net.lab1024.sa.admin.module.business.wms.base.area.service; import java.util.*; -import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; + import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaAddForm; import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; -import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; -import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaAddForm; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; -import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; -import net.lab1024.sa.base.common.code.UserErrorCode; -import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; -import org.springframework.transaction.annotation.Transactional; /** * 库区信息 Service @@ -31,21 +15,8 @@ import org.springframework.transaction.annotation.Transactional; * copyright 友仓 */ -@Service -public class AreaService { - - @Resource - private AreaDao areaDao; - - @Resource - private AreaManager areaManager; - - @Resource - private AreaQueryService areaQueryService; - - @Resource - private LocationQueryService locationQueryService; +public interface AreaService { /** * 添加 @@ -53,18 +24,7 @@ public class AreaService { * @param addForm 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO add(AreaAddForm addForm) { - AreaEntity existingArea = areaQueryService.queryByAreaName(addForm.getAreaName()); - if (existingArea != null) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - AreaEntity areaEntity = SmartBeanUtil.copy(addForm, AreaEntity.class); - areaDao.insert(areaEntity); - //更新缓存 - areaManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO add(AreaAddForm addForm); /** * 更新 @@ -72,18 +32,7 @@ public class AreaService { * @param updateForm 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO update(AreaUpdateForm updateForm) { - AreaEntity existingArea = areaQueryService.queryByAreaName(updateForm.getAreaName()); - if (existingArea != null && !existingArea.getAreaId().equals(updateForm.getAreaId())) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - AreaEntity areaEntity = SmartBeanUtil.copy(updateForm, AreaEntity.class); - areaDao.updateById(areaEntity); - //更新缓存 - areaManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO update(AreaUpdateForm updateForm); /** * 批量删除 @@ -91,33 +40,7 @@ public class AreaService { * @param idList 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - JoinerResult joiner = JoinerResult.createJoiner(); - List idsToDelete = new ArrayList<>(); - for (Long id : idList) { - AreaEntity area = areaManager.queryArea(id); - if (!locationQueryService.checkLocationExist(id)) { - joiner.getErrorMsg().add(area.getAreaName() + "已关联库位,无法删除"); - } else { - idsToDelete.add(id); - joiner.getSussMsg().add(area.getAreaName() + "删除成功"); - } - } - - //删除库区 - if (CollectionUtils.isNotEmpty(idsToDelete)) { - areaManager.removeBatchByIds(idsToDelete); - //更新缓存 - areaManager.removeCache(); - } - - return ResponseDTOUtils.buildResponseDTO(joiner); - } + ResponseDTO batchDelete(List idList); /** * 单个删除 @@ -125,23 +48,5 @@ public class AreaService { * @param areaId 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO delete(Long areaId) { - if (null == areaId) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - AreaEntity area = areaManager.queryArea(areaId); - if (!locationQueryService.checkLocationExist(areaId)) { - return ResponseDTO.userErrorParam(area.getAreaName() + "已关联库位,无法删除"); - } - - areaDao.deleteById(areaId); - - //更新缓存 - areaManager.removeCache(); - return ResponseDTO.ok(); - } - - + ResponseDTO delete(Long areaId); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaQueryServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaQueryServiceImpl.java new file mode 100644 index 0000000..dd362da --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaQueryServiceImpl.java @@ -0,0 +1,118 @@ +package net.lab1024.sa.admin.module.business.wms.base.area.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaQueryForm; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaSelect; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.vo.AreaVO; +import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; +import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AreaQueryServiceImpl implements AreaQueryService { + + @Resource + private AreaDao areaDao; + + @Resource + private AreaManager areaManager; + + /** + * 分页查询 + * + * @param queryForm 查询参数 + * @return PageResult + */ + public PageResult queryPage(AreaQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = areaDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 库区下拉查询 + * + * @param areaSelect 入参 + * @return List + */ + public List queryArea(AreaSelect areaSelect) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //是否启用 + if (areaSelect.getDisabledFlag() != null) { + queryWrapper.eq(AreaEntity::getDisabledFlag, areaSelect.getDisabledFlag()); + } + //库区名称 + if (CollectionUtils.isNotEmpty(areaSelect.getAreaNames())) { + queryWrapper.in(AreaEntity::getAreaName, areaSelect.getAreaNames()); + } + return areaDao.selectList(queryWrapper); + } + + /** + * 根据库区id集合查询库区信息 + * + * @param areaIdList 库区id集合 + * @return Map + */ + public Map queryAreaList(List areaIdList) { + if (CollectionUtils.isEmpty(areaIdList)) { + return Collections.emptyMap(); + } + areaIdList = areaIdList.stream().distinct().collect(Collectors.toList()); + Map areaMap = Maps.newHashMap(); + for (Long areaId : areaIdList) { + AreaEntity area = areaManager.queryArea(areaId); + if (area != null) { + areaMap.put(areaId, area); + } + } + return areaMap; + } + + /** + * 根据库区name集合查询库区信息 + * + * @param areaNameList 库区name集合 + * @return Map + */ + public Map queryAreaByNameList(List areaNameList) { + if (CollectionUtils.isEmpty(areaNameList)) { + return Collections.emptyMap(); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(AreaEntity::getAreaName, areaNameList); + + List areaList = areaDao.selectList(queryWrapper); + if (CollectionUtils.isEmpty(areaList)) { + return Collections.emptyMap(); + } + return areaList.stream() + .collect(Collectors.toMap(AreaEntity::getAreaName, area -> area, (existing, replacement) -> existing)); + } + + /** + * 根据库区名称查询库区信息 + * + * @param areaName 库区名称 + * @return AreaEntity + */ + public AreaEntity queryByAreaName(String areaName) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(AreaEntity::getAreaName, areaName); + return areaDao.selectOne(queryWrapper); + } + +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaServiceImpl.java new file mode 100644 index 0000000..5317ecc --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/area/service/impl/AreaServiceImpl.java @@ -0,0 +1,127 @@ +package net.lab1024.sa.admin.module.business.wms.base.area.service.impl; + +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaAddForm; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaUpdateForm; +import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; +import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; +import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaService; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; +import net.lab1024.sa.admin.util.JoinerResult; +import net.lab1024.sa.admin.util.ResponseDTOUtil; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class AreaServiceImpl implements AreaService { + + @Resource + private AreaManager areaManager; + + @Resource + private AreaQueryService areaQueryService; + + @Resource + private LocationQueryService locationQueryService; + + + /** + * 添加 + * + * @param addForm 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(AreaAddForm addForm) { + AreaEntity existingArea = areaQueryService.queryByAreaName(addForm.getAreaName()); + if (existingArea != null) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + AreaEntity areaEntity = SmartBeanUtil.copy(addForm, AreaEntity.class); + //新增并新增缓存 + areaManager.insert(areaEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(AreaUpdateForm updateForm) { + AreaEntity existingArea = areaQueryService.queryByAreaName(updateForm.getAreaName()); + if (existingArea != null && !existingArea.getAreaId().equals(updateForm.getAreaId())) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + AreaEntity areaEntity = SmartBeanUtil.copy(updateForm, AreaEntity.class); + //更新并更新缓存 + areaManager.update(areaEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + JoinerResult resultMsg = JoinerResult.createJoiner(); + List idsToDelete = new ArrayList<>(); + for (Long id : idList) { + AreaEntity area = areaManager.queryArea(id); + if (!locationQueryService.checkLocationExist(id)) { + resultMsg.getErrorMsg().add(area.getAreaName() + "已关联库位,无法删除"); + } else { + idsToDelete.add(id); + resultMsg.getSussMsg().add(area.getAreaName() + "删除成功"); + } + } + + //删除库区 + if (CollectionUtils.isNotEmpty(idsToDelete)) { + //删除并删除缓存 + areaManager.batchDelete(idsToDelete); + } + + return ResponseDTOUtil.buildResponseDTO(resultMsg); + } + + /** + * 单个删除 + * + * @param areaId 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long areaId) { + if (null == areaId) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + AreaEntity area = areaManager.queryArea(areaId); + if (!locationQueryService.checkLocationExist(areaId)) { + return ResponseDTO.userErrorParam(area.getAreaName() + "已关联库位,无法删除"); + } + + //单个删除并删除缓存 + areaManager.deleteById(areaId); + return ResponseDTO.ok(); + } + +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/manager/CustomerManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/manager/CustomerManager.java index e9ccfe0..0b8e687 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/manager/CustomerManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/manager/CustomerManager.java @@ -7,14 +7,21 @@ import net.lab1024.sa.admin.module.business.wms.base.customer.domain.entity.Cust import net.lab1024.sa.admin.module.business.wms.base.customer.dao.CustomerDao; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import net.lab1024.sa.admin.module.business.wms.base.customer.dao.CustomerDao; -import net.lab1024.sa.admin.module.business.wms.base.customer.domain.entity.CustomerEntity; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 客户管理 Manager + * 客户管理 Manager * * @author 霍锦 * @since 2025-03-25 10:42:33 @@ -27,19 +34,121 @@ public class CustomerManager extends ServiceImpl { @Resource private CustomerDao customerDao; + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); + /** - * 根据类目id 移除缓存 + * 查询客户(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @CacheEvict(value = {AdminCacheConst.Base.CUSTOMER_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear CUSTOMER_ENTITY"); + @Cacheable(value = AdminCacheConst.Base.CUSTOMER_ENTITY, key = "#customerId", unless = "#result == null") + public CustomerEntity queryCustomer(Long customerId) { + try { + readLock.lock(); + return customerDao.selectById(customerId); + } finally { + readLock.unlock(); + } } /** - * 查詢类目 + * 创建客户(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 */ - @Cacheable(AdminCacheConst.Base.CUSTOMER_ENTITY) - public CustomerEntity queryCustomer(Long customerId) { - return customerDao.selectById(customerId); + @Transactional(rollbackFor = Exception.class) + public CustomerEntity insert(CustomerEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新客户缓存", () -> refreshCache(entity.getCustomerId())); + return entity; + } + + /** + * 更新客户(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public CustomerEntity update(CustomerEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新客户缓存", () -> refreshCache(entity.getCustomerId())); + return entity; + } + + /** + * 删除客户(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long customerId) { + super.removeById(customerId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除客户缓存", () -> evictCache(customerId)); + } + + /** + * 批量删除客户(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List customerIds) { + super.removeByIds(customerIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除客户缓存", () -> customerIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long customerId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(customerId); + // 重新查询并缓存最新数据 + CustomerEntity entity = customerDao.selectById(customerId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.CUSTOMER_ENTITY); + if (cache != null) { + cache.put(customerId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long customerId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.CUSTOMER_ENTITY); + if (cache != null) { + cache.evict(customerId); + } + } finally { + writeLock.unlock(); + } } } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/service/CustomerService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/service/CustomerService.java index 2defe4e..8795f54 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/service/CustomerService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/customer/service/CustomerService.java @@ -29,9 +29,6 @@ import org.springframework.transaction.annotation.Transactional; @Service public class CustomerService { - @Resource - private CustomerDao customerDao; - @Resource private CustomerManager customerManager; @@ -51,9 +48,8 @@ public class CustomerService { return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); } CustomerEntity customerEntity = SmartBeanUtil.copy(addForm, CustomerEntity.class); - customerDao.insert(customerEntity); - //更新缓存 - customerManager.removeCache(); + //新增并新增缓存 + customerManager.insert(customerEntity); return ResponseDTO.ok(); } @@ -70,9 +66,8 @@ public class CustomerService { return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); } CustomerEntity customerEntity = SmartBeanUtil.copy(updateForm, CustomerEntity.class); - customerDao.updateById(customerEntity); - //更新缓存 - customerManager.removeCache(); + //更新并更新缓存 + customerManager.update(customerEntity); return ResponseDTO.ok(); } @@ -87,10 +82,8 @@ public class CustomerService { if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } - - customerManager.removeBatchByIds(idList); - //更新缓存 - customerManager.removeCache(); + //批量删除并删除缓存 + customerManager.batchDelete(idList); return ResponseDTO.ok(); } @@ -105,10 +98,8 @@ public class CustomerService { if (null == customerId) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } - - customerDao.deleteById(customerId); //更新缓存 - customerManager.removeCache(); + customerManager.deleteById(customerId); return ResponseDTO.ok(); } } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/manager/ItemManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/manager/ItemManager.java index e0d3ad4..c277204 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/manager/ItemManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/manager/ItemManager.java @@ -3,20 +3,27 @@ package net.lab1024.sa.admin.module.business.wms.base.item.manager; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import net.lab1024.sa.admin.constant.AdminCacheConst; -import net.lab1024.sa.admin.module.business.wms.base.area.dao.AreaDao; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.List; +import java.util.Collection; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 物料信息 Manager + * 物料信息 Manager * * @Author 霍锦 * @Date 2024-11-25 17:08:18 @@ -25,23 +32,160 @@ import org.springframework.stereotype.Service; @Service @Slf4j public class ItemManager extends ServiceImpl { + @Resource private ItemDao itemDao; - /** - * 移除所以缓存 - */ - @CacheEvict(value = {AdminCacheConst.Base.ITEM_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear ITEM_ENTITY"); - } + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); /** - * 查詢物料 + * 查询物料(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @Cacheable(AdminCacheConst.Base.ITEM_ENTITY) + @Cacheable(value = AdminCacheConst.Base.ITEM_ENTITY, key = "#itemId", unless = "#result == null") public ItemEntity queryItem(Long itemId) { - return itemDao.selectById(itemId); + try { + readLock.lock(); + return itemDao.selectById(itemId); + } finally { + readLock.unlock(); + } } -} + /** + * 创建物料(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public ItemEntity insert(ItemEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新物料缓存", () -> refreshCache(entity.getItemId())); + return entity; + } + + /** + * 更新物料(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public ItemEntity update(ItemEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新物料缓存", () -> refreshCache(entity.getItemId())); + return entity; + } + + /** + * 删除物料(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long itemId) { + super.removeById(itemId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除物料缓存", () -> evictCache(itemId)); + } + + /** + * 批量创建物料(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchInsert(List entities) { + super.saveBatch(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新物料缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量更新物料(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchUpdate(List entities) { + super.updateBatchById(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新物料缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量删除物料(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List itemIds) { + super.removeByIds(itemIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除物料缓存", () -> itemIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long itemId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(itemId); + // 重新查询并缓存最新数据 + ItemEntity entity = itemDao.selectById(itemId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.ITEM_ENTITY); + if (cache != null) { + cache.put(itemId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 批量刷新缓存 + * 先收集所有ID,再逐一刷新,减少锁争用 + */ + private void batchRefreshCache(Collection entities) { + List itemIds = entities.stream() + .map(ItemEntity::getItemId) + .distinct() + .toList(); + itemIds.forEach(this::refreshCache); + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long itemId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.ITEM_ENTITY); + if (cache != null) { + cache.evict(itemId); + } + } finally { + writeLock.unlock(); + } + } + +} \ No newline at end of file diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemQueryService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemQueryService.java index 954e9f1..5705675 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemQueryService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemQueryService.java @@ -24,17 +24,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -@Service -public class ItemQueryService { - @Resource - private ItemDao itemDao; - - @Resource - private ItemManager itemManager; - - @Resource - private DictService dictService; +public interface ItemQueryService { /** * 分页查询 @@ -42,11 +33,7 @@ public class ItemQueryService { * @param queryForm 入参 * @return PageResult */ - public PageResult queryPage(ItemQueryForm queryForm) { - Page page = SmartPageUtil.convert2PageQuery(queryForm); - List list = itemDao.queryPage(page, queryForm); - return SmartPageUtil.convert2PageResult(page, list); - } + PageResult queryPage(ItemQueryForm queryForm); /** * 物料下拉查询 @@ -54,14 +41,7 @@ public class ItemQueryService { * @param itemSelect 入参 * @return List */ - public List queryItem(ItemSelect itemSelect) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - //是否启用 - if (itemSelect.getDisabledFlag() != null) { - queryWrapper.eq(ItemEntity::getDisabledFlag, itemSelect.getDisabledFlag()); - } - return itemDao.selectList(queryWrapper); - } + List queryItem(ItemSelect itemSelect); /** * 根据物料id集合查询物料信息 @@ -69,20 +49,7 @@ public class ItemQueryService { * @param itemIdList 客户id集合 * @return Map */ - public Map queryItemList(List itemIdList) { - if (CollectionUtils.isEmpty(itemIdList)) { - return Collections.emptyMap(); - } - itemIdList = itemIdList.stream().distinct().collect(Collectors.toList()); - Map itemMap = Maps.newHashMap(); - for (Long itemId : itemIdList) { - ItemEntity item = itemManager.queryItem(itemId); - if (item != null) { - itemMap.put(itemId, item); - } - } - return itemMap; - } + Map queryItemList(List itemIdList); /** * 根据物料编码查询 @@ -90,11 +57,7 @@ public class ItemQueryService { * @param itemCode 物料编码 * @return ItemEntity */ - public ItemEntity queryByItemCode(String itemCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(ItemEntity::getItemCode, itemCode); - return itemDao.selectOne(queryWrapper); - } + ItemEntity queryByItemCode(String itemCode); /** * 根据物料编码集合查询物料信息 @@ -102,11 +65,7 @@ public class ItemQueryService { * @param itemCodes 物料编码集合 * @return List */ - public List queryByItemCodes(List itemCodes) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(ItemEntity::getItemCode, itemCodes); - return itemDao.selectList(queryWrapper); - } + List queryByItemCodes(List itemCodes); /** * 根据物料编码集合查询物料信息 @@ -114,33 +73,12 @@ public class ItemQueryService { * @param itemCodes 物料集合 * @return Map */ - public Map queryItemListToMap(List itemCodes) { - if (CollectionUtils.isEmpty(itemCodes)) { - return Collections.emptyMap(); - } - List items = queryByItemCodes(itemCodes); - return items.stream() - .collect(Collectors.toMap(ItemEntity::getItemCode, item -> item, (existing, replacement) -> existing)); - - } + Map queryItemListToMap(List itemCodes); /** * 物料导出 * * @return List */ - public List getItemsExcelVOList() { - List itemsList = itemDao.selectList(null); - return itemsList.stream() - .map(item -> - ItemsExcelVO.builder() - .itemCode(item.getItemCode()) - .itemName(item.getItemName()) - .itemType(dictService.getDictDataLabel(DictConst.ITEM_TYPE.getValue(), item.getItemType())) - .unit(dictService.getDictDataLabel(DictConst.ITEM_UNIT.getValue(), item.getUnit())) - .disabledFlag(item.getDisabledFlag() ? "启用" : "禁用") - .build() - ) - .collect(Collectors.toList()); - } + List getItemsExcelVOList(); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemService.java index cbf6342..eb37199 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/ItemService.java @@ -1,35 +1,12 @@ package net.lab1024.sa.admin.module.business.wms.base.item.service; -import java.io.IOException; import java.math.BigDecimal; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import cn.idev.excel.FastExcel; -import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemAddForm; import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemsImportForm; -import net.lab1024.sa.admin.module.business.wms.base.item.manager.ItemManager; -import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemAddForm; -import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; -import net.lab1024.sa.admin.util.ValidateDictKey; -import net.lab1024.sa.base.common.code.UserErrorCode; -import net.lab1024.sa.base.common.exception.BusinessException; -import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.util.SmartRequestUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; /** @@ -39,21 +16,7 @@ import org.springframework.web.multipart.MultipartFile; * @since 2024-11-25 17:08:18 * copyright 友仓 */ - -@Service -public class ItemService { - - @Resource - private ItemDao itemDao; - - @Resource - private ItemManager itemManager; - - @Resource - private ItemQueryService itemQueryService; - - @Resource - private ValidateDictKey ValidateDictKey; +public interface ItemService { /** * 添加 @@ -61,19 +24,7 @@ public class ItemService { * @param addForm 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO add(ItemAddForm addForm) { - ItemEntity existingItem = itemQueryService.queryByItemCode(addForm.getItemCode()); - if (existingItem != null) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - ItemEntity itemEntity = SmartBeanUtil.copy(addForm, ItemEntity.class); - itemDao.insert(itemEntity); - - //更新缓存 - itemManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO add(ItemAddForm addForm); /** * 更新 @@ -81,18 +32,7 @@ public class ItemService { * @param updateForm 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO update(ItemUpdateForm updateForm) { - ItemEntity existingItem = itemQueryService.queryByItemCode(updateForm.getItemCode()); - if (existingItem != null && !existingItem.getItemId().equals(updateForm.getItemId())) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - ItemEntity itemEntity = SmartBeanUtil.copy(updateForm, ItemEntity.class); - itemDao.updateById(itemEntity); - //更新缓存 - itemManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO update(ItemUpdateForm updateForm); /** * 批量删除 @@ -100,18 +40,7 @@ public class ItemService { * @param idList 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - itemManager.removeBatchByIds(idList); - - //更新缓存 - itemManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO batchDelete(List idList); /** * 单个删除 @@ -119,18 +48,7 @@ public class ItemService { * @param itemId 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO delete(Long itemId) { - if (null == itemId) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - itemDao.deleteById(itemId); - - //更新缓存 - itemManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO delete(Long itemId); /** * 物料导入 @@ -138,62 +56,7 @@ public class ItemService { * @param file 上传文件 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO importItems(MultipartFile file) { - List dataList; - try { - dataList = FastExcel.read(file.getInputStream()).head(ItemsImportForm.class) - .sheet() - .doReadSync(); - } catch (IOException e) { - throw new BusinessException("数据格式存在问题,无法读取"); - } - if (CollectionUtils.isEmpty(dataList)) { - return ResponseDTO.userErrorParam("数据为空"); - } - - //获取所有去重后的物料类型 - List itemTypes = dataList.stream().map(ItemsImportForm::getItemType).distinct().collect(Collectors.toList()); - - //验证物料类型 - Map itemTypeMap = ValidateDictKey.validateDictCodes(itemTypes, DictConst.ITEM_TYPE.getValue()); - - //获取所有去重后的包装单位 - List units = dataList.stream().map(ItemsImportForm::getUnit).distinct().collect(Collectors.toList()); - - //验证包装单位 - Map unitMap = ValidateDictKey.validateDictCodes(units, DictConst.ITEM_UNIT.getValue()); - - //获取所有去重后的容器编码 - List itemCodes = dataList.stream().map(ItemsImportForm::getItemCode).distinct().collect(Collectors.toList()); - - //查询数据库存在的物料 - Map exitItemMap = itemQueryService.queryItemListToMap(itemCodes); - - List insertToItem = new ArrayList<>(); - List updateToItem = new ArrayList<>(); - for (ItemsImportForm itemsImportForm : dataList) { - - //物料类型 - String itemType = itemTypeMap.get(itemsImportForm.getItemType()); - - //包装单位 - String unit = unitMap.get(itemsImportForm.getUnit()); - - //物料 - ItemEntity item = exitItemMap.get(itemsImportForm.getItemCode()); - - //物料为空则新增,否则更新 - if (item == null) { - insertToItem.add(createItem(itemsImportForm.getItemCode(), itemsImportForm.getItemName(), unit, BigDecimal.ONE, itemType)); - } else { - updateToItem.add(createItem(itemsImportForm.getItemCode(), itemsImportForm.getItemName(), unit, BigDecimal.ONE, itemType)); - } - } - - JoinerResult resultMsg = JoinerResult.createJoiner(); - return ResponseDTOUtils.buildResponseSussDTO(insertToItem, updateToItem, itemManager::saveBatch, itemManager::updateBatchById, resultMsg); - } + ResponseDTO importItems(MultipartFile file); /** * 创建物料 @@ -205,18 +68,6 @@ public class ItemService { * @param itemType 物料类型 * @return ItemEntity */ - public ItemEntity createItem(String itemCode, String itemName, String unit, BigDecimal packFactor, String itemType) { - return ItemEntity.builder() - .itemCode(itemCode) - .itemName(itemName) - .unit(unit) - .packFactor(packFactor) - .disabledFlag(true) - .itemType(itemType) - .createUserId(SmartRequestUtil.getRequestUser().getUserId()) - .createUserName(SmartRequestUtil.getRequestUser().getUserName()) - .build(); - } - + ItemEntity createItem(String itemCode, String itemName, String unit, BigDecimal packFactor, String itemType); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemQueryServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemQueryServiceImpl.java new file mode 100644 index 0000000..3a4ac1d --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemQueryServiceImpl.java @@ -0,0 +1,146 @@ +package net.lab1024.sa.admin.module.business.wms.base.item.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemQueryForm; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemSelect; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.vo.ItemVO; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.vo.ItemsExcelVO; +import net.lab1024.sa.admin.module.business.wms.base.item.manager.ItemManager; +import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemQueryService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import net.lab1024.sa.base.module.support.dict.service.DictService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class ItemQueryServiceImpl implements ItemQueryService { + + @Resource + private ItemDao itemDao; + + @Resource + private ItemManager itemManager; + + @Resource + private DictService dictService; + + /** + * 分页查询 + * + * @param queryForm 入参 + * @return PageResult + */ + public PageResult queryPage(ItemQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = itemDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 物料下拉查询 + * + * @param itemSelect 入参 + * @return List + */ + public List queryItem(ItemSelect itemSelect) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //是否启用 + if (itemSelect.getDisabledFlag() != null) { + queryWrapper.eq(ItemEntity::getDisabledFlag, itemSelect.getDisabledFlag()); + } + return itemDao.selectList(queryWrapper); + } + + /** + * 根据物料id集合查询物料信息 + * + * @param itemIdList 客户id集合 + * @return Map + */ + public Map queryItemList(List itemIdList) { + if (CollectionUtils.isEmpty(itemIdList)) { + return Collections.emptyMap(); + } + itemIdList = itemIdList.stream().mapToLong(Long::longValue).distinct().boxed().toList(); + Map itemMap = Maps.newHashMap(); + for (Long itemId : itemIdList) { + ItemEntity item = itemManager.queryItem(itemId); + if (item != null) { + itemMap.put(itemId, item); + } + } + return itemMap; + } + + /** + * 根据物料编码查询 + * + * @param itemCode 物料编码 + * @return ItemEntity + */ + public ItemEntity queryByItemCode(String itemCode) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ItemEntity::getItemCode, itemCode); + return itemDao.selectOne(queryWrapper); + } + + /** + * 根据物料编码集合查询物料信息 + * + * @param itemCodes 物料编码集合 + * @return List + */ + public List queryByItemCodes(List itemCodes) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(ItemEntity::getItemCode, itemCodes); + return itemDao.selectList(queryWrapper); + } + + /** + * 根据物料编码集合查询物料信息 + * + * @param itemCodes 物料集合 + * @return Map + */ + public Map queryItemListToMap(List itemCodes) { + if (CollectionUtils.isEmpty(itemCodes)) { + return Collections.emptyMap(); + } + List items = queryByItemCodes(itemCodes); + return items.stream() + .collect(Collectors.toMap(ItemEntity::getItemCode, item -> item, (existing, replacement) -> existing)); + + } + + /** + * 物料导出 + * + * @return List + */ + public List getItemsExcelVOList() { + List itemsList = itemDao.selectList(null); + return itemsList.stream() + .map(item -> + ItemsExcelVO.builder() + .itemCode(item.getItemCode()) + .itemName(item.getItemName()) + .itemType(dictService.getDictDataLabel(DictConst.ITEM_TYPE.getValue(), item.getItemType())) + .unit(dictService.getDictDataLabel(DictConst.ITEM_UNIT.getValue(), item.getUnit())) + .disabledFlag(item.getDisabledFlag() ? "启用" : "禁用") + .build() + ) + .collect(Collectors.toList()); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemServiceImpl.java new file mode 100644 index 0000000..5136aa7 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/item/service/impl/ItemServiceImpl.java @@ -0,0 +1,197 @@ +package net.lab1024.sa.admin.module.business.wms.base.item.service.impl; + +import cn.idev.excel.FastExcel; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemAddForm; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemUpdateForm; +import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemsImportForm; +import net.lab1024.sa.admin.module.business.wms.base.item.manager.ItemManager; +import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemQueryService; +import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemService; +import net.lab1024.sa.admin.util.JoinerResult; +import net.lab1024.sa.admin.util.ResponseDTOUtil; +import net.lab1024.sa.admin.util.ValidateDictKey; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class ItemServiceImpl implements ItemService { + + @Resource + private ItemManager itemManager; + + @Resource + private ItemQueryService itemQueryService; + + @Resource + private ValidateDictKey validateDictKey; + + /** + * 添加 + * + * @param addForm 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(ItemAddForm addForm) { + ItemEntity existingItem = itemQueryService.queryByItemCode(addForm.getItemCode()); + if (existingItem != null) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + ItemEntity itemEntity = SmartBeanUtil.copy(addForm, ItemEntity.class); + //新增并新增缓存 + itemManager.insert(itemEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(ItemUpdateForm updateForm) { + ItemEntity existingItem = itemQueryService.queryByItemCode(updateForm.getItemCode()); + if (existingItem != null && !existingItem.getItemId().equals(updateForm.getItemId())) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + ItemEntity itemEntity = SmartBeanUtil.copy(updateForm, ItemEntity.class); + //更新并更新缓存 + itemManager.update(itemEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + //批量删除并删除缓存 + itemManager.batchDelete(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + * + * @param itemId 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long itemId) { + if (null == itemId) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + //单个删除并删除缓存 + itemManager.deleteById(itemId); + return ResponseDTO.ok(); + } + + /** + * 物料导入 + * + * @param file 上传文件 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO importItems(MultipartFile file) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(ItemsImportForm.class) + .sheet() + .doReadSync(); + } catch (IOException e) { + throw new BusinessException("数据格式存在问题,无法读取"); + } + if (CollectionUtils.isEmpty(dataList)) { + return ResponseDTO.userErrorParam("数据为空"); + } + + //获取所有去重后的物料类型 + List itemTypes = dataList.stream().map(ItemsImportForm::getItemType).distinct().collect(Collectors.toList()); + + //验证物料类型 + Map itemTypeMap = validateDictKey.validateDictCodes(itemTypes, DictConst.ITEM_TYPE.getValue()); + + //获取所有去重后的包装单位 + List units = dataList.stream().map(ItemsImportForm::getUnit).distinct().collect(Collectors.toList()); + + //验证包装单位 + Map unitMap = validateDictKey.validateDictCodes(units, DictConst.ITEM_UNIT.getValue()); + + //获取所有去重后的容器编码 + List itemCodes = dataList.stream().map(ItemsImportForm::getItemCode).distinct().collect(Collectors.toList()); + + //查询数据库存在的物料 + Map exitItemMap = itemQueryService.queryItemListToMap(itemCodes); + + List insertToItem = new ArrayList<>(); + List updateToItem = new ArrayList<>(); + for (ItemsImportForm itemsImportForm : dataList) { + + //物料类型 + String itemType = itemTypeMap.get(itemsImportForm.getItemType()); + + //包装单位 + String unit = unitMap.get(itemsImportForm.getUnit()); + + //物料 + ItemEntity item = exitItemMap.get(itemsImportForm.getItemCode()); + + //物料为空则新增,否则更新 + if (item == null) { + insertToItem.add(createItem(itemsImportForm.getItemCode(), itemsImportForm.getItemName(), unit, BigDecimal.ONE, itemType)); + } else { + updateToItem.add(createItem(itemsImportForm.getItemCode(), itemsImportForm.getItemName(), unit, BigDecimal.ONE, itemType)); + } + } + JoinerResult resultMsg = JoinerResult.createJoiner(); + return ResponseDTOUtil.buildResponseDTO(insertToItem,updateToItem,itemManager::batchInsert, itemManager::batchUpdate,resultMsg); + } + + /** + * 创建物料 + * + * @param itemCode 物料编码 + * @param itemName 物料名称 + * @param unit 包装单位 + * @param packFactor 包装系数 + * @param itemType 物料类型 + * @return ItemEntity + */ + public ItemEntity createItem(String itemCode, String itemName, String unit, BigDecimal packFactor, String itemType) { + return ItemEntity.builder() + .itemCode(itemCode) + .itemName(itemName) + .unit(unit) + .packFactor(packFactor) + .disabledFlag(true) + .itemType(itemType) + .createUserId(SmartRequestUtil.getRequestUser().getUserId()) + .createUserName(SmartRequestUtil.getRequestUser().getUserName()) + .build(); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/manager/LocationManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/manager/LocationManager.java index 9fcb206..a2796f6 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/manager/LocationManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/manager/LocationManager.java @@ -7,40 +7,184 @@ import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 库位信息 Manager + * 库位信息 Manager * * @author 霍锦 - * @since 2024-11-18 14:17:31 + * @since 2024-11-18 14:17:31 * copyright 友仓 */ @Service @Slf4j public class LocationManager extends ServiceImpl { - @Resource private LocationDao locationDao; - /** - * 根据类目id 移除缓存 - */ - @CacheEvict(value = {AdminCacheConst.Base.LOCATION_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear LOCATION_ENTITY"); - } + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); /** - * 查詢类目 + * 查询库位(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @Cacheable(AdminCacheConst.Base.LOCATION_ENTITY) + @Cacheable(value = AdminCacheConst.Base.LOCATION_ENTITY, key = "#locationId", unless = "#result == null") public LocationEntity queryLocation(Long locationId) { - return locationDao.selectById(locationId); + try { + readLock.lock(); + return locationDao.selectById(locationId); + } finally { + readLock.unlock(); + } } + /** + * 创建库位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public LocationEntity insert(LocationEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新库位缓存", () -> refreshCache(entity.getLocationId())); + return entity; + } + + /** + * 更新库位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public LocationEntity update(LocationEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新库位缓存", () -> refreshCache(entity.getLocationId())); + return entity; + } + + /** + * 删除库位(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long locationId) { + super.removeById(locationId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除库位缓存", () -> evictCache(locationId)); + } + + /** + * 批量创建库位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchInsert(List entities) { + super.saveBatch(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新库位缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量更新库位(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchUpdate(List entities) { + super.updateBatchById(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新库位缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量删除库位(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List locationIds) { + super.removeByIds(locationIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除库位缓存", () -> locationIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long locationId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(locationId); + // 重新查询并缓存最新数据 + LocationEntity entity = locationDao.selectById(locationId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.LOCATION_ENTITY); + if (cache != null) { + cache.put(locationId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 批量刷新缓存 + * 先收集所有ID,再逐一刷新,减少锁争用 + */ + private void batchRefreshCache(Collection entities) { + List locationIds = entities.stream() + .map(LocationEntity::getLocationId) + .distinct() + .toList(); + + locationIds.forEach(this::refreshCache); + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long locationId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.LOCATION_ENTITY); + if (cache != null) { + cache.evict(locationId); + } + } finally { + writeLock.unlock(); + } + } } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationQueryService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationQueryService.java index 8ceeec2..c40007d 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationQueryService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationQueryService.java @@ -1,63 +1,16 @@ package net.lab1024.sa.admin.module.business.wms.base.location.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Maps; -import jakarta.annotation.Resource; -import net.lab1024.sa.admin.constant.UsageStatusEnum; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaSelect; -import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; -import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; -import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationQueryForm; import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationSelect; import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationsExcelVO; import net.lab1024.sa.admin.module.business.wms.base.location.domain.vo.LocationVO; -import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaSelect; -import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; -import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; -import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationQueryForm; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationSelect; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationsExcelVO; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.vo.LocationVO; -import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; import net.lab1024.sa.base.common.domain.PageResult; -import net.lab1024.sa.base.common.util.SmartEnumUtil; -import net.lab1024.sa.base.common.util.SmartPageUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import net.lab1024.sa.base.module.support.dict.service.DictService; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -@Service -public class LocationQueryService { - - @Resource - private LocationDao locationDao; - - @Resource - private AreaManager areaManager; - - @Resource - private LocationManager locationManager; - - @Resource - private AreaQueryService areaQueryService; - - @Resource - private DictService dictService; +public interface LocationQueryService { /** * 分页查询 @@ -65,21 +18,7 @@ public class LocationQueryService { * @param queryForm 查询参数 * @return PageResult */ - public PageResult queryPage(LocationQueryForm queryForm) { - Page page = SmartPageUtil.convert2PageQuery(queryForm); - List list = locationDao.queryPage(page, queryForm); - - // 查询库区名称 - List areaIdList = list.stream().map(LocationVO::getAreaId).distinct().collect(Collectors.toList()); - Map areaMap = areaQueryService.queryAreaList(areaIdList); - list.forEach(locationVO -> { - AreaEntity area = areaMap.get(locationVO.getAreaId()); - if (area != null) { - locationVO.setAreaName(area.getAreaName()); - } - }); - return SmartPageUtil.convert2PageResult(page, list); - } + PageResult queryPage(LocationQueryForm queryForm); /** * 实体转VO @@ -87,23 +26,7 @@ public class LocationQueryService { * @param entity 实体 * @return LocationVO */ - public LocationVO entityToVO(LocationEntity entity) { - AreaEntity area = areaManager.queryArea(entity.getAreaId()); - return LocationVO.builder() - .locationId(entity.getLocationId()) - .locationCode(entity.getLocationCode()) - .status(entity.getStatus()) - .areaId(entity.getAreaId()) - .areaName(area == null ? null : area.getAreaName()) - .disabledFlag(entity.getDisabledFlag()) - .locationRow(entity.getLocationRow()) - .locationLine(entity.getLocationLine()) - .locationCow(entity.getLocationCow()) - .locationType(entity.getLocationType()) - .remark(entity.getRemark()) - .createTime(entity.getCreateTime()) - .build(); - } + LocationVO entityToVO(LocationEntity entity); /** @@ -112,37 +35,7 @@ public class LocationQueryService { * @param locationSelect 查询参数 * @return List */ - public List queryLocation(LocationSelect locationSelect) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - //是否启用 - if (locationSelect.getDisabledFlag() != null) { - queryWrapper.eq(LocationEntity::getDisabledFlag, locationSelect.getDisabledFlag()); - } - //库区 - if (CollectionUtils.isNotEmpty(locationSelect.getAreaNames())) { - AreaSelect areaSelect = AreaSelect.builder().areaNames(locationSelect.getAreaNames()).build(); - areaSelect.setAreaNames(locationSelect.getAreaNames()); - List areaList = areaQueryService.queryArea(areaSelect); - if (CollectionUtils.isNotEmpty(areaList)) { - List areaIdList = areaList.stream().map(AreaEntity::getAreaId).collect(Collectors.toList()); - queryWrapper.in(LocationEntity::getAreaId, areaIdList); - } - } - - //库位类型 - if (StringUtils.isNotBlank(locationSelect.getLocationType())) { - queryWrapper.eq(LocationEntity::getLocationType, locationSelect.getLocationType()); - } - - //库位状态 - if (StringUtils.isNotBlank(locationSelect.getStatus())) { - queryWrapper.eq(LocationEntity::getStatus, locationSelect.getStatus()); - } - - List list = locationDao.selectList(queryWrapper); - - return list.stream().map(this::entityToVO).collect(Collectors.toList()); - } + List queryLocation(LocationSelect locationSelect); /** * 根据库位ID集合查询库位信息 @@ -150,32 +43,14 @@ public class LocationQueryService { * @param locationIdList 库位ID集合 * @return Map */ - public Map queryLocationList(List locationIdList) { - if (CollectionUtils.isEmpty(locationIdList)) { - return Collections.emptyMap(); - } - locationIdList = locationIdList.stream().distinct().collect(Collectors.toList()); - Map locationMap = Maps.newHashMap(); - for (Long locationId : locationIdList) { - LocationEntity location = locationManager.queryLocation(locationId); - if (location != null) { - locationMap.put(locationId, location); - } - } - return locationMap; - } + Map queryLocationList(List locationIdList); /** * 验证库区是否存在库位 * * @param areaId 库区 */ - public Boolean checkLocationExist(Long areaId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(LocationEntity::getAreaId, areaId); - List list = locationDao.selectList(queryWrapper); - return list.isEmpty(); - } + Boolean checkLocationExist(Long areaId); /** * 根据库位编码查询库位信息 @@ -183,11 +58,7 @@ public class LocationQueryService { * @param locationCode 库位编码 * @return LocationEntity */ - public LocationEntity queryByLocationCode(String locationCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(LocationEntity::getLocationCode, locationCode); - return locationDao.selectOne(queryWrapper); - } + LocationEntity queryByLocationCode(String locationCode); /** * 根据库位编码集合查询库位信息 @@ -195,11 +66,7 @@ public class LocationQueryService { * @param locationCodes 库位编码集合 * @return List */ - public List queryByLocationCodes(List locationCodes) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(LocationEntity::getLocationCode, locationCodes); - return locationDao.selectList(queryWrapper); - } + List queryByLocationCodes(List locationCodes); /** * 根据库位编码集合查询库位信息 @@ -207,39 +74,13 @@ public class LocationQueryService { * @param locationCodes 库位集合 * @return Map */ - public Map queryLocationListToMap(List locationCodes) { - if (CollectionUtils.isEmpty(locationCodes)) { - return Collections.emptyMap(); - } - List locations = queryByLocationCodes(locationCodes); - return locations.stream() - .collect(Collectors.toMap(LocationEntity::getLocationCode, location -> location, (existing, replacement) -> existing)); - - } + Map queryLocationListToMap(List locationCodes); /** * 库位导出 * * @return List */ - public List getLocationsExcelVOList() { - List locationsList = locationDao.selectList(null); - //库区 - List areaIds = locationsList.stream().map(LocationEntity::getAreaId).distinct().collect(Collectors.toList()); - Map areaMap = areaQueryService.queryAreaList(areaIds); - return locationsList.stream() - .map(location -> - LocationsExcelVO.builder() - .areaName(areaMap.get(location.getAreaId()).getAreaName()) - .locationCode(location.getLocationCode()) - .locationType(dictService.getDictDataLabel(DictConst.LOC_TYPE.getValue(), location.getLocationType())) - .status(SmartEnumUtil.getEnumDescByValue(location.getStatus(), UsageStatusEnum.class)) - .disabledFlag(location.getDisabledFlag() ? "启用" : "禁用") - .build() - ) - .collect(Collectors.toList()); - - } - + List getLocationsExcelVOList(); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationService.java index 48963cd..012e1ff 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/LocationService.java @@ -1,32 +1,9 @@ package net.lab1024.sa.admin.module.business.wms.base.location.service; -import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; -import cn.idev.excel.FastExcel; -import lombok.extern.slf4j.Slf4j; -import net.lab1024.sa.admin.constant.UsageStatusEnum; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; -import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; -import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.*; -import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; -import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; -import net.lab1024.sa.admin.util.ValidateDictKey; -import net.lab1024.sa.base.common.code.UserErrorCode; -import net.lab1024.sa.base.common.exception.BusinessException; -import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.util.SmartRequestUtil; -import net.lab1024.sa.base.common.util.SmartStringUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; /** @@ -37,24 +14,7 @@ import org.springframework.web.multipart.MultipartFile; * copyright 友仓 */ -@Service -@Slf4j -public class LocationService { - - @Resource - private LocationDao locationDao; - - @Resource - private LocationManager locationManager; - - @Resource - private AreaQueryService areaQueryService; - - @Resource - private LocationQueryService locationQueryService; - - @Resource - private ValidateDictKey ValidateDictKey; +public interface LocationService { /** * 添加 @@ -62,19 +22,7 @@ public class LocationService { * @param addForm 添加参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO add(LocationAddForm addForm) { - LocationEntity existingLocation = locationQueryService.queryByLocationCode(addForm.getLocationCode()); - if (existingLocation != null) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - LocationEntity locationEntity = SmartBeanUtil.copy(addForm, LocationEntity.class); - locationDao.insert(locationEntity); - - //更新缓存 - locationManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO add(LocationAddForm addForm); /** * 更新 @@ -82,18 +30,7 @@ public class LocationService { * @param updateForm 更新参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO update(LocationUpdateForm updateForm) { - LocationEntity existingLocation = locationQueryService.queryByLocationCode(updateForm.getLocationCode()); - if (existingLocation != null && !existingLocation.getLocationId().equals(updateForm.getLocationId())) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - LocationEntity locationEntity = SmartBeanUtil.copy(updateForm, LocationEntity.class); - locationDao.updateById(locationEntity); - //更新缓存 - locationManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO update(LocationUpdateForm updateForm); /** * 批量删除 @@ -101,17 +38,7 @@ public class LocationService { * @param idList 删除参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - locationManager.removeBatchByIds(idList); - //更新缓存 - locationManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO batchDelete(List idList); /** * 单个删除 @@ -119,17 +46,7 @@ public class LocationService { * @param locationId 入参 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO delete(Long locationId) { - if (null == locationId) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - locationDao.deleteById(locationId); - //更新缓存 - locationManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO delete(Long locationId); /** * 批量调整 @@ -137,107 +54,7 @@ public class LocationService { * @param multipleAdjust 参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO multipleAdjust(MultipleAdjust multipleAdjust) { - - if (CollectionUtils.isEmpty(multipleAdjust.getLocationIds())) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - //查询库位 - Map locationEntityMap = locationQueryService.queryLocationList(multipleAdjust.getLocationIds()); - - //批量更新 - List updateToLocation = new ArrayList<>(); - - //调整状态,true:空闲;false:占用 - String status = multipleAdjust.getStatus() ? UsageStatusEnum.FREE.getValue() : UsageStatusEnum.USED.getValue(); - - //是否启用,true:启用;false:禁用 - Boolean disabledFlag = multipleAdjust.getDisabledFlag(); - - //更新状态 - locationEntityMap.forEach((locationId, location) -> { - location.setStatus(status); - location.setDisabledFlag(disabledFlag); - updateToLocation.add(location); - }); - - if (CollectionUtils.isNotEmpty(updateToLocation)) { - locationManager.updateBatchById(updateToLocation); - } - - //更新缓存 - locationManager.removeCache(); - return ResponseDTO.ok(); - - - } - - /** - * 创建库位 - * - * @param locationCode 库位编码 - * @param areaId 区域ID - * @param locationRow 行 - * @param locationLine 列 - * @param locationCow 层 - * @param locationType 类型 - * @return LocationEntity - */ - public LocationEntity createLocation(String locationCode, Long areaId, String locationRow, String locationLine, String locationCow, String locationType) { - return LocationEntity.builder() - .locationCode(locationCode) - .locationName(locationCode) - .status(UsageStatusEnum.FREE.getValue()) - .areaId(areaId) - .disabledFlag(true) - .locationRow(locationRow) - .locationLine(locationLine) - .locationCow(locationCow) - .locationType(locationType) - .createUserId(SmartRequestUtil.getRequestUser().getUserId()) - .createUserName(SmartRequestUtil.getRequestUser().getUserName()) - .build(); - } - - - public LocationEntity createLocation(String locationCode, Long areaId, String locationType) { - int firstDashIndex = locationCode.indexOf('-'); - if (firstDashIndex == -1) { - return createLocation(locationCode, areaId, null, null, null, locationType); - } - String[] parts = locationCode.substring(firstDashIndex + 1).split("-"); - if (parts.length < 3) { - return createLocation(locationCode, areaId, null, null, null, locationType); - } - String row = parts[0]; - String col = parts[1]; - String layer = parts[2]; - return createLocation(locationCode, areaId, row, col, layer, locationType); - } - - /** - * 批量新增 - * - * @param locationCodes 库位集合 - * @param areaId 库区 - * @param locationType 库位类型 - */ - public void multipleInsert(List locationCodes, Long areaId, String locationType) { - List insertToLocation = new ArrayList<>(); - for (String locationCode : locationCodes) { - LocationEntity location = createLocation(locationCode, areaId, locationType); - insertToLocation.add(location); - } - //批量新增 - if (CollectionUtils.isNotEmpty(insertToLocation)) { - locationManager.saveBatch(insertToLocation); - } - - // 更新缓存 - locationManager.removeCache(); - } + ResponseDTO multipleAdjust(MultipleAdjust multipleAdjust); /** * 批量新增 @@ -245,38 +62,7 @@ public class LocationService { * @param multipleInsert 参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO multipleInsert(MultipleInsert multipleInsert) { - //入参的所以库位集合 - List locationCodes = multipleInsert.getLocationCodes(); - - //查询数据库已存在的库位集合 - List list = locationQueryService.queryByLocationCodes(locationCodes); - JoinerResult joiner = JoinerResult.createJoiner(); - if (CollectionUtils.isNotEmpty(list)) { - List existingLocationCodes = list.stream() - .map(LocationEntity::getLocationCode) - .toList(); - // 获取两个集合的交集说明库位已存在;提示错误 - List getIntersection = SmartStringUtil.getIntersection(locationCodes, existingLocationCodes); - joiner.getErrorMsg().add(getIntersection + "库位已存在,新增失败"); - // 获取两个集合的非交集说明库位不存在;批量新增 - List difference = SmartStringUtil.getDifference(locationCodes, existingLocationCodes); - if (CollectionUtils.isNotEmpty(difference)) { - //批量新增 - multipleInsert(difference, multipleInsert.getAreaId(), multipleInsert.getLocationType()); - joiner.getSussMsg().add(difference + "库位新增成功"); - } - - return ResponseDTOUtils.buildResponseDTO(joiner); - } - - // 没有查询到库位,直接新增 - multipleInsert(locationCodes, multipleInsert.getAreaId(), multipleInsert.getLocationType()); - joiner.getSussMsg().add(locationCodes + "库位新增成功"); - - return ResponseDTOUtils.buildResponseDTO(joiner); - } + ResponseDTO multipleInsert(MultipleInsert multipleInsert); /** * 库位导入 @@ -284,100 +70,14 @@ public class LocationService { * @param file 上传文件 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO importLocations(MultipartFile file) { - List dataList; - try { - dataList = FastExcel.read(file.getInputStream()).head(LocationsImportForm.class) - .sheet() - .doReadSync(); - } catch (IOException e) { - throw new BusinessException("数据格式存在问题,无法读取"); - } - if (CollectionUtils.isEmpty(dataList)) { - return ResponseDTO.userErrorParam("数据为空"); - } + ResponseDTO importLocations(MultipartFile file); - //获取所有去重后的库区 - List areaNames = dataList.stream().map(LocationsImportForm::getAreaName).distinct().collect(Collectors.toList()); - - //验证库区 - Map areaMap = validateArea(areaNames); - - //获取所有去重后的库位类型 - List locationTypes = dataList.stream().map(LocationsImportForm::getLocationType).distinct().collect(Collectors.toList()); - - //验证库位类型 - Map locationTypeMap = ValidateDictKey.validateDictCodes(locationTypes, DictConst.LOC_TYPE.getValue()); - - //获取所有去重后的库位编码 - List locationCodes = dataList.stream().map(LocationsImportForm::getLocationCode).distinct().collect(Collectors.toList()); - - //查询数据库存在的库位编码 - Map exitLocationMap = locationQueryService.queryLocationListToMap(locationCodes); - - List insertToLocation = new ArrayList<>(); - List updateToLocation = new ArrayList<>(); - for (LocationsImportForm locationsImportForm : dataList) { - //库区 - AreaEntity area = areaMap.get(locationsImportForm.getAreaName()); - - //库位类型 - String locationType = locationTypeMap.get(locationsImportForm.getLocationType()); - - //库位 - LocationEntity location = exitLocationMap.get(locationsImportForm.getLocationCode()); - - //库位为空则新增,否则更新 - if (location == null) { - insertToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType)); - } else { - updateToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType)); - } - } - - JoinerResult resultMsg = JoinerResult.createJoiner(); - return ResponseDTOUtils.buildResponseSussDTO(insertToLocation, updateToLocation, locationManager::saveBatch, locationManager::updateBatchById, resultMsg); - } - - /** - * 验证库区 - * - * @param areaNames 库区集合 - * @return Map - */ - public Map validateArea(List areaNames) { - //查询数据库存在的库区 - Map areaMap = areaQueryService.queryAreaByNameList(areaNames); - if (areaMap.isEmpty()) { - throw new BusinessException(areaNames + "库区不存在,在库区管理中维护库区"); - } - - //获取map的key集合 - List exitAreaNameList = areaMap.keySet().stream().toList(); - //获取两个集合的非交集说明库区不存在;提示错误 - List diffAreaName = SmartStringUtil.getDifference(areaNames, exitAreaNameList); - if (CollectionUtils.isNotEmpty(diffAreaName)) { - throw new BusinessException(diffAreaName + "库区不存在,在库区管理中维护库区"); - } - return areaMap; - } - - /** + /** * 更新库位状态 * * @param locationId 库位id * @param status 状态 */ - @Transactional(rollbackFor = Exception.class) - public void updateLocationStatus(Long locationId, String status) { - if (locationId != null) { - LocationEntity location = locationDao.selectById(locationId); - if (location != null) { - location.setStatus(status); - locationDao.updateById(location); - } - } - } + void updateLocationStatus(Long locationId, String status); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationQueryServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationQueryServiceImpl.java new file mode 100644 index 0000000..277c35f --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationQueryServiceImpl.java @@ -0,0 +1,234 @@ +package net.lab1024.sa.admin.module.business.wms.base.location.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.constant.UsageStatusEnum; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.form.AreaSelect; +import net.lab1024.sa.admin.module.business.wms.base.area.manager.AreaManager; +import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; +import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationQueryForm; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationSelect; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.LocationsExcelVO; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.vo.LocationVO; +import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import net.lab1024.sa.base.module.support.dict.service.DictService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class LocationQueryServiceImpl implements LocationQueryService { + + @Resource + private LocationDao locationDao; + + @Resource + private AreaManager areaManager; + + @Resource + private LocationManager locationManager; + + @Resource + private AreaQueryService areaQueryService; + + @Resource + private DictService dictService; + + /** + * 分页查询 + * + * @param queryForm 查询参数 + * @return PageResult + */ + public PageResult queryPage(LocationQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = locationDao.queryPage(page, queryForm); + + // 查询库区名称 + List areaIdList = list.stream().map(LocationVO::getAreaId).distinct().collect(Collectors.toList()); + Map areaMap = areaQueryService.queryAreaList(areaIdList); + list.forEach(locationVO -> { + AreaEntity area = areaMap.get(locationVO.getAreaId()); + if (area != null) { + locationVO.setAreaName(area.getAreaName()); + } + }); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 实体转VO + * + * @param entity 实体 + * @return LocationVO + */ + public LocationVO entityToVO(LocationEntity entity) { + AreaEntity area = areaManager.queryArea(entity.getAreaId()); + return LocationVO.builder() + .locationId(entity.getLocationId()) + .locationCode(entity.getLocationCode()) + .status(entity.getStatus()) + .areaId(entity.getAreaId()) + .areaName(area == null ? null : area.getAreaName()) + .disabledFlag(entity.getDisabledFlag()) + .locationRow(entity.getLocationRow()) + .locationLine(entity.getLocationLine()) + .locationCow(entity.getLocationCow()) + .locationType(entity.getLocationType()) + .remark(entity.getRemark()) + .createTime(entity.getCreateTime()) + .build(); + } + + + /** + * 库位下拉查询 + * + * @param locationSelect 查询参数 + * @return List + */ + public List queryLocation(LocationSelect locationSelect) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //是否启用 + if (locationSelect.getDisabledFlag() != null) { + queryWrapper.eq(LocationEntity::getDisabledFlag, locationSelect.getDisabledFlag()); + } + //库区 + if (CollectionUtils.isNotEmpty(locationSelect.getAreaNames())) { + AreaSelect areaSelect = AreaSelect.builder().areaNames(locationSelect.getAreaNames()).build(); + areaSelect.setAreaNames(locationSelect.getAreaNames()); + List areaList = areaQueryService.queryArea(areaSelect); + if (CollectionUtils.isNotEmpty(areaList)) { + List areaIdList = areaList.stream().map(AreaEntity::getAreaId).collect(Collectors.toList()); + queryWrapper.in(LocationEntity::getAreaId, areaIdList); + } + } + + //库位类型 + if (StringUtils.isNotBlank(locationSelect.getLocationType())) { + queryWrapper.eq(LocationEntity::getLocationType, locationSelect.getLocationType()); + } + + //库位状态 + if (StringUtils.isNotBlank(locationSelect.getStatus())) { + queryWrapper.eq(LocationEntity::getStatus, locationSelect.getStatus()); + } + + List list = locationDao.selectList(queryWrapper); + + return list.stream().map(this::entityToVO).collect(Collectors.toList()); + } + + /** + * 根据库位ID集合查询库位信息 + * + * @param locationIdList 库位ID集合 + * @return Map + */ + public Map queryLocationList(List locationIdList) { + if (CollectionUtils.isEmpty(locationIdList)) { + return Collections.emptyMap(); + } + locationIdList = locationIdList.stream().distinct().collect(Collectors.toList()); + Map locationMap = Maps.newHashMap(); + for (Long locationId : locationIdList) { + LocationEntity location = locationManager.queryLocation(locationId); + if (location != null) { + locationMap.put(locationId, location); + } + } + return locationMap; + } + + /** + * 验证库区是否存在库位 + * + * @param areaId 库区 + */ + public Boolean checkLocationExist(Long areaId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(LocationEntity::getAreaId, areaId); + List list = locationDao.selectList(queryWrapper); + return list.isEmpty(); + } + + /** + * 根据库位编码查询库位信息 + * + * @param locationCode 库位编码 + * @return LocationEntity + */ + public LocationEntity queryByLocationCode(String locationCode) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(LocationEntity::getLocationCode, locationCode); + return locationDao.selectOne(queryWrapper); + } + + /** + * 根据库位编码集合查询库位信息 + * + * @param locationCodes 库位编码集合 + * @return List + */ + public List queryByLocationCodes(List locationCodes) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(LocationEntity::getLocationCode, locationCodes); + return locationDao.selectList(queryWrapper); + } + + /** + * 根据库位编码集合查询库位信息 + * + * @param locationCodes 库位集合 + * @return Map + */ + public Map queryLocationListToMap(List locationCodes) { + if (CollectionUtils.isEmpty(locationCodes)) { + return Collections.emptyMap(); + } + List locations = queryByLocationCodes(locationCodes); + return locations.stream() + .collect(Collectors.toMap(LocationEntity::getLocationCode, location -> location, (existing, replacement) -> existing)); + + } + + /** + * 库位导出 + * + * @return List + */ + public List getLocationsExcelVOList() { + List locationsList = locationDao.selectList(null); + //库区 + List areaIds = locationsList.stream().map(LocationEntity::getAreaId).distinct().collect(Collectors.toList()); + Map areaMap = areaQueryService.queryAreaList(areaIds); + return locationsList.stream() + .map(location -> + LocationsExcelVO.builder() + .areaName(areaMap.get(location.getAreaId()).getAreaName()) + .locationCode(location.getLocationCode()) + .locationType(dictService.getDictDataLabel(DictConst.LOC_TYPE.getValue(), location.getLocationType())) + .status(SmartEnumUtil.getEnumDescByValue(location.getStatus(), UsageStatusEnum.class)) + .disabledFlag(location.getDisabledFlag() ? "启用" : "禁用") + .build() + ) + .collect(Collectors.toList()); + + } + +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationServiceImpl.java new file mode 100644 index 0000000..3e40da5 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/location/service/impl/LocationServiceImpl.java @@ -0,0 +1,367 @@ +package net.lab1024.sa.admin.module.business.wms.base.location.service.impl; + +import cn.idev.excel.FastExcel; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.UsageStatusEnum; +import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService; +import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.*; +import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationService; +import net.lab1024.sa.admin.util.JoinerResult; +import net.lab1024.sa.admin.util.ResponseDTOUtil; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.common.util.SmartStringUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class LocationServiceImpl implements LocationService { + @Resource + private LocationDao locationDao; + + @Resource + private LocationManager locationManager; + + @Resource + private AreaQueryService areaQueryService; + + @Resource + private LocationQueryService locationQueryService; + + @Resource + private net.lab1024.sa.admin.util.ValidateDictKey ValidateDictKey; + + /** + * 添加 + * + * @param addForm 添加参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(LocationAddForm addForm) { + LocationEntity existingLocation = locationQueryService.queryByLocationCode(addForm.getLocationCode()); + if (existingLocation != null) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + LocationEntity locationEntity = SmartBeanUtil.copy(addForm, LocationEntity.class); + //新增并新增缓存 + locationManager.insert(locationEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm 更新参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(LocationUpdateForm updateForm) { + LocationEntity existingLocation = locationQueryService.queryByLocationCode(updateForm.getLocationCode()); + if (existingLocation != null && !existingLocation.getLocationId().equals(updateForm.getLocationId())) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + LocationEntity locationEntity = SmartBeanUtil.copy(updateForm, LocationEntity.class); + //更新并更新缓存 + locationManager.update(locationEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList 删除参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + //删除并删除缓存 + locationManager.batchDelete(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + * + * @param locationId 入参 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long locationId) { + if (null == locationId) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + //删除并删除缓存 + locationManager.deleteById(locationId); + return ResponseDTO.ok(); + } + + /** + * 批量调整 + * + * @param multipleAdjust 参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO multipleAdjust(MultipleAdjust multipleAdjust) { + + if (CollectionUtils.isEmpty(multipleAdjust.getLocationIds())) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + //查询库位 + Map locationEntityMap = locationQueryService.queryLocationList(multipleAdjust.getLocationIds()); + + //批量更新 + List updateToLocation = new ArrayList<>(); + + //调整状态,true:空闲;false:占用 + String status = multipleAdjust.getStatus() ? UsageStatusEnum.FREE.getValue() : UsageStatusEnum.USED.getValue(); + + //是否启用,true:启用;false:禁用 + Boolean disabledFlag = multipleAdjust.getDisabledFlag(); + + //更新状态 + locationEntityMap.forEach((locationId, location) -> { + location.setStatus(status); + location.setDisabledFlag(disabledFlag); + updateToLocation.add(location); + }); + + if (CollectionUtils.isNotEmpty(updateToLocation)) { + //更新并更新缓存 + locationManager.batchUpdate(updateToLocation); + } + + + return ResponseDTO.ok(); + + + } + + /** + * 创建库位 + * + * @param locationCode 库位编码 + * @param areaId 区域ID + * @param locationRow 行 + * @param locationLine 列 + * @param locationCow 层 + * @param locationType 类型 + * @return LocationEntity + */ + public LocationEntity createLocation(String locationCode, Long areaId, String locationRow, String locationLine, String locationCow, String locationType) { + return LocationEntity.builder() + .locationCode(locationCode) + .locationName(locationCode) + .status(UsageStatusEnum.FREE.getValue()) + .areaId(areaId) + .disabledFlag(true) + .locationRow(locationRow) + .locationLine(locationLine) + .locationCow(locationCow) + .locationType(locationType) + .createUserId(SmartRequestUtil.getRequestUser().getUserId()) + .createUserName(SmartRequestUtil.getRequestUser().getUserName()) + .build(); + } + + + public LocationEntity createLocation(String locationCode, Long areaId, String locationType) { + int firstDashIndex = locationCode.indexOf('-'); + if (firstDashIndex == -1) { + return createLocation(locationCode, areaId, null, null, null, locationType); + } + String[] parts = locationCode.substring(firstDashIndex + 1).split("-"); + if (parts.length < 3) { + return createLocation(locationCode, areaId, null, null, null, locationType); + } + String row = parts[0]; + String col = parts[1]; + String layer = parts[2]; + return createLocation(locationCode, areaId, row, col, layer, locationType); + } + + /** + * 批量新增 + * + * @param locationCodes 库位集合 + * @param areaId 库区 + * @param locationType 库位类型 + */ + public void multipleInsert(List locationCodes, Long areaId, String locationType) { + List insertToLocation = new ArrayList<>(); + for (String locationCode : locationCodes) { + LocationEntity location = createLocation(locationCode, areaId, locationType); + insertToLocation.add(location); + } + if (CollectionUtils.isNotEmpty(insertToLocation)) { + // 批量新增并更新缓存 + locationManager.batchInsert(insertToLocation); + } + } + + /** + * 批量新增 + * + * @param multipleInsert 参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO multipleInsert(MultipleInsert multipleInsert) { + //入参的所以库位集合 + List locationCodes = multipleInsert.getLocationCodes(); + + //查询数据库已存在的库位集合 + List list = locationQueryService.queryByLocationCodes(locationCodes); + JoinerResult resultMsg = JoinerResult.createJoiner(); + if (CollectionUtils.isNotEmpty(list)) { + List existingLocationCodes = list.stream() + .map(LocationEntity::getLocationCode) + .toList(); + // 获取两个集合的交集说明库位已存在;提示错误 + List getIntersection = SmartStringUtil.getIntersection(locationCodes, existingLocationCodes); + resultMsg.getErrorMsg().add(getIntersection + "库位已存在,新增失败"); + // 获取两个集合的非交集说明库位不存在;批量新增 + List difference = SmartStringUtil.getDifference(locationCodes, existingLocationCodes); + if (CollectionUtils.isNotEmpty(difference)) { + //批量新增 + multipleInsert(difference, multipleInsert.getAreaId(), multipleInsert.getLocationType()); + resultMsg.getSussMsg().add(difference + "库位新增成功"); + } + + return ResponseDTOUtil.buildResponseDTO(resultMsg); + } + + // 没有查询到库位,直接新增 + multipleInsert(locationCodes, multipleInsert.getAreaId(), multipleInsert.getLocationType()); + resultMsg.getSussMsg().add(locationCodes + "库位新增成功"); + + return ResponseDTOUtil.buildResponseDTO(resultMsg); + } + + /** + * 库位导入 + * + * @param file 上传文件 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO importLocations(MultipartFile file) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(LocationsImportForm.class) + .sheet() + .doReadSync(); + } catch (IOException e) { + throw new BusinessException("数据格式存在问题,无法读取"); + } + if (CollectionUtils.isEmpty(dataList)) { + return ResponseDTO.userErrorParam("数据为空"); + } + + //获取所有去重后的库区 + List areaNames = dataList.stream().map(LocationsImportForm::getAreaName).distinct().collect(Collectors.toList()); + + //验证库区 + Map areaMap = validateArea(areaNames); + + //获取所有去重后的库位类型 + List locationTypes = dataList.stream().map(LocationsImportForm::getLocationType).distinct().collect(Collectors.toList()); + + //验证库位类型 + Map locationTypeMap = ValidateDictKey.validateDictCodes(locationTypes, DictConst.LOC_TYPE.getValue()); + + //获取所有去重后的库位编码 + List locationCodes = dataList.stream().map(LocationsImportForm::getLocationCode).distinct().collect(Collectors.toList()); + + //查询数据库存在的库位编码 + Map exitLocationMap = locationQueryService.queryLocationListToMap(locationCodes); + + List insertToLocation = new ArrayList<>(); + List updateToLocation = new ArrayList<>(); + for (LocationsImportForm locationsImportForm : dataList) { + //库区 + AreaEntity area = areaMap.get(locationsImportForm.getAreaName()); + + //库位类型 + String locationType = locationTypeMap.get(locationsImportForm.getLocationType()); + + //库位 + LocationEntity location = exitLocationMap.get(locationsImportForm.getLocationCode()); + + //库位为空则新增,否则更新 + if (location == null) { + insertToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType)); + } else { + updateToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType)); + } + } + + JoinerResult resultMsg = JoinerResult.createJoiner(); + return ResponseDTOUtil.buildResponseDTO(insertToLocation, updateToLocation, locationManager::batchInsert, locationManager::batchUpdate, resultMsg); + } + + /** + * 验证库区 + * + * @param areaNames 库区集合 + * @return Map + */ + public Map validateArea(List areaNames) { + //查询数据库存在的库区 + Map areaMap = areaQueryService.queryAreaByNameList(areaNames); + if (areaMap.isEmpty()) { + throw new BusinessException(areaNames + "库区不存在,在库区管理中维护库区"); + } + + //获取map的key集合 + List exitAreaNameList = areaMap.keySet().stream().toList(); + //获取两个集合的非交集说明库区不存在;提示错误 + List diffAreaName = SmartStringUtil.getDifference(areaNames, exitAreaNameList); + if (CollectionUtils.isNotEmpty(diffAreaName)) { + throw new BusinessException(diffAreaName + "库区不存在,在库区管理中维护库区"); + } + return areaMap; + } + + /** + * 更新库位状态 + * + * @param locationId 库位id + * @param status 状态 + */ + @Transactional(rollbackFor = Exception.class) + public void updateLocationStatus(Long locationId, String status) { + if (locationId != null) { + LocationEntity location = locationManager.queryLocation(locationId); + if (location != null) { + location.setStatus(status); + locationManager.update(location); + } + } + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/manager/StockManager.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/manager/StockManager.java index ea1777a..bfd448b 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/manager/StockManager.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/manager/StockManager.java @@ -7,15 +7,25 @@ import net.lab1024.sa.admin.module.business.wms.base.stock.dao.StockDao; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.cache.annotation.CacheEvict; +import net.lab1024.sa.admin.util.TransactionCommitUtil; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * 容器信息 Manager + * 容器信息 Manager * * @author 霍锦 - * @since 2024-11-26 11:37:48 + * @since 2024-11-26 11:37:48 * copyright 友仓 */ @Service @@ -25,20 +35,156 @@ public class StockManager extends ServiceImpl { @Resource private StockDao stockDao; - /** - * 根据类目id 移除缓存 - */ - @CacheEvict(value = {AdminCacheConst.Base.STOCK_ENTITY}, allEntries = true) - public void removeCache() { - log.info("clear LOCATION_ENTITY"); - } + @Resource + private CacheManager cacheManager; + + // 使用读写锁保证高并发下的缓存操作安全 + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + private final Lock readLock = rwLock.readLock(); + private final Lock writeLock = rwLock.writeLock(); /** - * 查詢类目 + * 查询容器(带缓存) + * 使用Spring Cache自动缓存查询结果 */ - @Cacheable(AdminCacheConst.Base.STOCK_ENTITY) + @Cacheable(value = AdminCacheConst.Base.STOCK_ENTITY, key = "#stockId", unless = "#result == null") public StockEntity queryStock(Long stockId) { - return stockDao.selectById(stockId); + try { + readLock.lock(); + return stockDao.selectById(stockId); + } finally { + readLock.unlock(); + } } + /** + * 创建容器(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public StockEntity insert(StockEntity entity) { + super.save(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新容器缓存", () -> refreshCache(entity.getStockId())); + return entity; + } + + /** + * 更新容器(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public StockEntity update(StockEntity entity) { + super.updateById(entity); + // 在事务提交后刷新缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("刷新容器缓存", () -> refreshCache(entity.getStockId())); + return entity; + } + + /** + * 删除容器(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void deleteById(Long stockId) { + super.removeById(stockId); + // 在事务提交后清除缓存,确保数据库操作成功后再更新缓存 + executeAfterCommit("清除容器缓存", () -> evictCache(stockId)); + } + + /** + * 批量创建容器(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchInsert(List entities) { + super.saveBatch(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新容器缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量更新容器(带缓存) + * 事务提交后执行缓存刷新,保证数据一致性 + */ + @Transactional(rollbackFor = Exception.class) + public void batchUpdate(List entities) { + super.updateBatchById(entities); + // 在事务提交后批量刷新缓存 + executeAfterCommit("批量刷新容器缓存", () -> batchRefreshCache(entities)); + } + + /** + * 批量删除容器(清理缓存) + * 事务提交后清除缓存 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List stockIds) { + super.removeByIds(stockIds); + // 在事务提交后批量清除缓存 + executeAfterCommit("批量清除容器缓存", () -> stockIds.forEach(this::evictCache)); + } + + /** + * 通用方法:事务提交后执行操作 + * + * @param operationDesc 操作描述(用于日志) + * @param operation 要执行的操作 + */ + private void executeAfterCommit(String operationDesc, Runnable operation) { + TransactionCommitUtil.executeAfterCommit(operationDesc, operation); + } + + /** + * 刷新单个缓存 + * 使用写锁确保并发安全 + */ + public void refreshCache(Long stockId) { + try { + writeLock.lock(); + // 先清除可能存在的旧缓存 + evictCache(stockId); + // 重新查询并缓存最新数据 + StockEntity entity = stockDao.selectById(stockId); + + // 手动更新缓存,避免使用@CachePut注解可能导致的问题 + if (entity != null) { + Cache cache = cacheManager.getCache(AdminCacheConst.Base.STOCK_ENTITY); + if (cache != null) { + cache.put(stockId, entity); + } + } + } finally { + writeLock.unlock(); + } + } + + /** + * 批量刷新缓存 + * 先收集所有ID,再逐一刷新,减少锁争用 + */ + private void batchRefreshCache(Collection entities) { + List stockIds = entities.stream() + .map(StockEntity::getStockId) + .distinct() + .toList(); + + stockIds.forEach(this::refreshCache); + } + + /** + * 手动清除缓存 + * 使用写锁确保并发安全 + */ + private void evictCache(Long stockId) { + try { + writeLock.lock(); + Cache cache = cacheManager.getCache(AdminCacheConst.Base.STOCK_ENTITY); + if (cache != null) { + cache.evict(stockId); + } + } finally { + writeLock.unlock(); + } + } } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockQueryService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockQueryService.java index eb353d3..6fd6a70 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockQueryService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockQueryService.java @@ -1,58 +1,17 @@ package net.lab1024.sa.admin.module.business.wms.base.stock.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Maps; -import jakarta.annotation.Resource; -import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.vo.LocationVO; -import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; -import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; -import net.lab1024.sa.admin.module.business.wms.base.stock.dao.StockDao; + import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockQueryForm; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockSelect; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.vo.StockVO; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.vo.StocksExcelVO; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockQueryForm; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockSelect; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.vo.StocksExcelVO; -import net.lab1024.sa.admin.module.business.wms.base.stock.manager.StockManager; import net.lab1024.sa.base.common.domain.PageResult; -import net.lab1024.sa.base.common.util.SmartPageUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import net.lab1024.sa.base.module.support.dict.service.DictService; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -@Service -public class StockQueryService { - - @Resource - private StockDao stockDao; - - @Resource - private LocationManager locationManager; - - @Resource - private StockManager stockManager; - - @Resource - private DictService dictService; - - @Resource - private LocationQueryService locationQueryService; +public interface StockQueryService { /** * 分页查询 @@ -60,21 +19,7 @@ public class StockQueryService { * @param queryForm 查询参数 * @return PageResult */ - public PageResult queryPage(StockQueryForm queryForm) { - Page page = SmartPageUtil.convert2PageQuery(queryForm); - List list = stockDao.queryPage(page, queryForm); - - // 查询库位编码 - List locationIdList = list.stream().map(StockVO::getLocationId).distinct().collect(Collectors.toList()); - Map locationMap = locationQueryService.queryLocationList(locationIdList); - list.forEach(StockVO -> { - LocationEntity location = locationMap.get(StockVO.getLocationId()); - if (location != null) { - StockVO.setLocationCode(location.getLocationCode()); - } - }); - return SmartPageUtil.convert2PageResult(page, list); - } + PageResult queryPage(StockQueryForm queryForm); /** * 根据容器id集合查询容器信息 @@ -82,20 +27,7 @@ public class StockQueryService { * @param stockIdList 容器id集合 * @return Map */ - public Map queryStockList(List stockIdList) { - if (CollectionUtils.isEmpty(stockIdList)) { - return Collections.emptyMap(); - } - stockIdList = stockIdList.stream().distinct().collect(Collectors.toList()); - Map stockMap = Maps.newHashMap(); - for (Long stockId : stockIdList) { - StockEntity stock = stockManager.queryStock(stockId); - if (stock != null) { - stockMap.put(stockId, stock); - } - } - return stockMap; - } + Map queryStockList(List stockIdList); /** * 容器下拉查询 @@ -103,18 +35,7 @@ public class StockQueryService { * @param stockSelect 入参 * @return List */ - public List queryStock(StockSelect stockSelect) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - //是否启用 - if (stockSelect.getDisabledFlag() != null) { - queryWrapper.eq(StockEntity::getDisabledFlag, stockSelect.getDisabledFlag()); - } - //状态 - if (StringUtils.isNotBlank(stockSelect.getStatus())) { - queryWrapper.eq(StockEntity::getStatus, stockSelect.getStatus()); - } - return stockDao.selectList(queryWrapper); - } + List queryStock(StockSelect stockSelect); /** * 根据容器编码查询容器信息 @@ -122,11 +43,7 @@ public class StockQueryService { * @param stockCode 容器编码 * @return StockEntity */ - public StockEntity queryByStockCode(String stockCode) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(StockEntity::getStockCode, stockCode); - return stockDao.selectOne(queryWrapper); - } + StockEntity queryByStockCode(String stockCode); /** * 根据容器编码集合查询容器信息 @@ -134,11 +51,7 @@ public class StockQueryService { * @param stockCodes 容器料编码集合 * @return List */ - public List queryByItemCodes(List stockCodes) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(StockEntity::getStockCode, stockCodes); - return stockDao.selectList(queryWrapper); - } + List queryByItemCodes(List stockCodes); /** * 根据容器编码集合查询容器信息 @@ -146,15 +59,7 @@ public class StockQueryService { * @param stockCodes 容器编码集合 * @return Map */ - public Map queryStockListToMap(List stockCodes) { - if (CollectionUtils.isEmpty(stockCodes)) { - return Collections.emptyMap(); - } - List stocks = queryByItemCodes(stockCodes); - return stocks.stream() - .collect(Collectors.toMap(StockEntity::getStockCode, stock -> stock, (existing, replacement) -> existing)); - - } + Map queryStockListToMap(List stockCodes); /** * 根据库位id查询容器信息 @@ -162,28 +67,12 @@ public class StockQueryService { * @param locationId 库位 * @return StockEntity */ - public StockEntity queryStockByLocationId(Long locationId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(StockEntity::getLocationId, locationId); - return stockDao.selectOne(queryWrapper); - } + StockEntity queryStockByLocationId(Long locationId); /** * 容器导出 * * @return List */ - public List getStocksExcelVOList() { - List stocksList = stockDao.selectList(null); - return stocksList.stream() - .map(stock -> - StocksExcelVO.builder() - .stockCode(stock.getStockCode()) - .stockType(dictService.getDictDataLabel(DictConst.STOCK_TYPE.getValue(), stock.getStockType())) - .locationCode(locationManager.queryLocation(stock.getLocationId()) == null ? "" : locationManager.queryLocation(stock.getLocationId()).getLocationCode()) - .disabledFlag(stock.getDisabledFlag() ? "启用" : "禁用") - .build() - ) - .collect(Collectors.toList()); - } + List getStocksExcelVOList(); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockService.java index 61f0f12..e0df910 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/StockService.java @@ -1,44 +1,12 @@ package net.lab1024.sa.admin.module.business.wms.base.stock.service; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import cn.idev.excel.FastExcel; -import net.lab1024.sa.admin.constant.UsageStatusEnum; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; -import net.lab1024.sa.admin.module.business.wms.base.item.domain.form.ItemsImportForm; -import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; -import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationService; -import net.lab1024.sa.admin.module.business.wms.base.stock.dao.StockDao; +import java.util.List; + import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockAddForm; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StocksImportForm; -import net.lab1024.sa.admin.module.business.wms.base.stock.manager.StockManager; -import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockUpdateForm; -import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StocksImportForm; -import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; -import net.lab1024.sa.admin.util.ValidateDictKey; -import net.lab1024.sa.base.common.code.SystemErrorCode; -import net.lab1024.sa.base.common.code.UserErrorCode; -import net.lab1024.sa.base.common.exception.BusinessException; -import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.util.SmartRequestUtil; -import net.lab1024.sa.base.module.support.dict.constant.DictConst; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; /** @@ -49,27 +17,7 @@ import org.springframework.web.multipart.MultipartFile; * copyright 友仓 */ -@Service -public class StockService { - - @Resource - private StockDao stockDao; - - @Resource - private LocationDao locationDao; - - @Resource - private StockManager stockManager; - - @Resource - private ValidateDictKey ValidateDictKey; - - @Resource - private StockQueryService stockQueryService; - - @Resource - private LocationService locationService; - +public interface StockService { /** * 添加 @@ -77,19 +25,7 @@ public class StockService { * @param addForm 添加参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO add(StockAddForm addForm) { - StockEntity existingStock = stockQueryService.queryByStockCode(addForm.getStockCode()); - if (existingStock != null) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - StockEntity stockEntity = SmartBeanUtil.copy(addForm, StockEntity.class); - stockDao.insert(stockEntity); - - //更新缓存 - stockManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO add(StockAddForm addForm); /** * 更新 @@ -97,36 +33,7 @@ public class StockService { * @param updateForm 更新参数 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO update(StockUpdateForm updateForm) { - StockEntity existingStock = stockQueryService.queryByStockCode(updateForm.getStockCode()); - if (existingStock != null && !existingStock.getStockId().equals(updateForm.getStockId())) { - return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); - } - //当前更新的容器的库位 - if (existingStock != null && existingStock.getLocationId() != null) { - //更新库位状态 - locationService.updateLocationStatus(existingStock.getLocationId(), UsageStatusEnum.FREE.getValue()); - } - - if (updateForm.getLocationId() != null) { - LocationEntity location = locationDao.selectById(updateForm.getLocationId()); - StockEntity curStock = stockQueryService.queryStockByLocationId(updateForm.getLocationId()); - if (curStock != null && existingStock != null) { - if (!curStock.getStockId().equals(existingStock.getStockId())) { - return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, location.getLocationCode() + "库位绑定的当前容器为" + curStock.getStockCode()); - } - } - //更新库位状态 - locationService.updateLocationStatus(updateForm.getLocationId(), UsageStatusEnum.USED.getValue()); - } - StockEntity stockEntity = SmartBeanUtil.copy(updateForm, StockEntity.class); - stockDao.updateById(stockEntity); - - //更新缓存 - stockManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO update(StockUpdateForm updateForm); /** * 批量删除 @@ -134,19 +41,7 @@ public class StockService { * @param idList id集合 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - //批量删除 - stockManager.removeBatchByIds(idList); - - //更新缓存 - stockManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO batchDelete(List idList); /** * 单个删除 @@ -154,18 +49,7 @@ public class StockService { * @param stockId 容器Id * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO delete(Long stockId) { - if (null == stockId) { - return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); - } - - stockDao.deleteById(stockId); - - //更新缓存 - stockManager.removeCache(); - return ResponseDTO.ok(); - } + ResponseDTO delete(Long stockId); /** * 容器导入 @@ -173,53 +57,7 @@ public class StockService { * @param file 上传文件 * @return ResponseDTO */ - @Transactional(rollbackFor = Exception.class) - public ResponseDTO importStocks(MultipartFile file) { - List dataList; - try { - dataList = FastExcel.read(file.getInputStream()).head(StocksImportForm.class) - .sheet() - .doReadSync(); - } catch (IOException e) { - throw new BusinessException("数据格式存在问题,无法读取"); - } - if (CollectionUtils.isEmpty(dataList)) { - return ResponseDTO.userErrorParam("数据为空"); - } - - //获取所有去重后的容器类型 - List stockTypes = dataList.stream().map(StocksImportForm::getStockType).distinct().collect(Collectors.toList()); - - //验证容器类型 - Map itemTypeMap = ValidateDictKey.validateDictCodes(stockTypes, DictConst.STOCK_TYPE.getValue()); - - //获取所有去重后的容器编码 - List stockCodes = dataList.stream().map(StocksImportForm::getStockCode).distinct().collect(Collectors.toList()); - - //查询数据库存在的容器 - Map exitStockMap = stockQueryService.queryStockListToMap(stockCodes); - - List insertToStock = new ArrayList<>(); - List updateToStock = new ArrayList<>(); - for (StocksImportForm stocksImportForm : dataList) { - - //容器类型 - String stockType = itemTypeMap.get(stocksImportForm.getStockType()); - - //容器 - StockEntity stock = exitStockMap.get(stocksImportForm.getStockCode()); - - //容器为空新增,否则更新 - if (stock == null) { - insertToStock.add(createStock(stocksImportForm.getStockCode(), stockType)); - } else { - updateToStock.add(createStock(stocksImportForm.getStockCode(), stockType)); - } - } - - JoinerResult resultMsg = JoinerResult.createJoiner(); - return ResponseDTOUtils.buildResponseSussDTO(insertToStock, updateToStock, stockManager::saveBatch, stockManager::updateBatchById, resultMsg); - } + ResponseDTO importStocks(MultipartFile file); /** * 创建容器 @@ -228,14 +66,5 @@ public class StockService { * @param stockType 容器类型 * @return StockEntity */ - public StockEntity createStock(String stockCode, String stockType) { - return StockEntity.builder() - .stockCode(stockCode) - .stockType(stockType) - .status(UsageStatusEnum.FREE.getValue()) - .disabledFlag(true) - .createUserId(SmartRequestUtil.getRequestUser().getUserId()) - .createUserName(SmartRequestUtil.getRequestUser().getUserName()) - .build(); - } + StockEntity createStock(String stockCode, String stockType); } diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockQueryServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockQueryServiceImpl.java new file mode 100644 index 0000000..debd4d2 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockQueryServiceImpl.java @@ -0,0 +1,181 @@ +package net.lab1024.sa.admin.module.business.wms.base.stock.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; +import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; +import net.lab1024.sa.admin.module.business.wms.base.stock.dao.StockDao; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockQueryForm; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockSelect; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.vo.StockVO; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.vo.StocksExcelVO; +import net.lab1024.sa.admin.module.business.wms.base.stock.manager.StockManager; +import net.lab1024.sa.admin.module.business.wms.base.stock.service.StockQueryService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import net.lab1024.sa.base.module.support.dict.service.DictService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +public class StockQueryServiceImpl implements StockQueryService { + @Resource + private StockDao stockDao; + + @Resource + private LocationManager locationManager; + + @Resource + private StockManager stockManager; + + @Resource + private DictService dictService; + + @Resource + private LocationQueryService locationQueryService; + + /** + * 分页查询 + * + * @param queryForm 查询参数 + * @return PageResult + */ + public PageResult queryPage(StockQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = stockDao.queryPage(page, queryForm); + + // 查询库位编码 + List locationIdList = list.stream().map(StockVO::getLocationId).filter(Objects::nonNull).distinct().toList(); + Map locationMap = locationQueryService.queryLocationList(locationIdList); + list.forEach(StockVO -> { + LocationEntity location = locationMap.get(StockVO.getLocationId()); + if (location != null) { + StockVO.setLocationCode(location.getLocationCode()); + } + }); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 根据容器id集合查询容器信息 + * + * @param stockIdList 容器id集合 + * @return Map + */ + public Map queryStockList(List stockIdList) { + if (CollectionUtils.isEmpty(stockIdList)) { + return Collections.emptyMap(); + } + stockIdList = stockIdList.stream().distinct().collect(Collectors.toList()); + Map stockMap = Maps.newHashMap(); + for (Long stockId : stockIdList) { + StockEntity stock = stockManager.queryStock(stockId); + if (stock != null) { + stockMap.put(stockId, stock); + } + } + return stockMap; + } + + /** + * 容器下拉查询 + * + * @param stockSelect 入参 + * @return List + */ + public List queryStock(StockSelect stockSelect) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //是否启用 + if (stockSelect.getDisabledFlag() != null) { + queryWrapper.eq(StockEntity::getDisabledFlag, stockSelect.getDisabledFlag()); + } + //状态 + if (StringUtils.isNotBlank(stockSelect.getStatus())) { + queryWrapper.eq(StockEntity::getStatus, stockSelect.getStatus()); + } + return stockDao.selectList(queryWrapper); + } + + /** + * 根据容器编码查询容器信息 + * + * @param stockCode 容器编码 + * @return StockEntity + */ + public StockEntity queryByStockCode(String stockCode) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StockEntity::getStockCode, stockCode); + return stockDao.selectOne(queryWrapper); + } + + /** + * 根据容器编码集合查询容器信息 + * + * @param stockCodes 容器料编码集合 + * @return List + */ + public List queryByItemCodes(List stockCodes) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(StockEntity::getStockCode, stockCodes); + return stockDao.selectList(queryWrapper); + } + + /** + * 根据容器编码集合查询容器信息 + * + * @param stockCodes 容器编码集合 + * @return Map + */ + public Map queryStockListToMap(List stockCodes) { + if (CollectionUtils.isEmpty(stockCodes)) { + return Collections.emptyMap(); + } + List stocks = queryByItemCodes(stockCodes); + return stocks.stream() + .collect(Collectors.toMap(StockEntity::getStockCode, stock -> stock, (existing, replacement) -> existing)); + + } + + /** + * 根据库位id查询容器信息 + * + * @param locationId 库位 + * @return StockEntity + */ + public StockEntity queryStockByLocationId(Long locationId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StockEntity::getLocationId, locationId); + return stockDao.selectOne(queryWrapper); + } + + /** + * 容器导出 + * + * @return List + */ + public List getStocksExcelVOList() { + List stocksList = stockDao.selectList(null); + return stocksList.stream() + .map(stock -> + StocksExcelVO.builder() + .stockCode(stock.getStockCode()) + .stockType(dictService.getDictDataLabel(DictConst.STOCK_TYPE.getValue(), stock.getStockType())) + .locationCode(locationManager.queryLocation(stock.getLocationId()) == null ? "" : locationManager.queryLocation(stock.getLocationId()).getLocationCode()) + .disabledFlag(stock.getDisabledFlag() ? "启用" : "禁用") + .build() + ) + .collect(Collectors.toList()); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockServiceImpl.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockServiceImpl.java new file mode 100644 index 0000000..4c6e02d --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/base/stock/service/impl/StockServiceImpl.java @@ -0,0 +1,212 @@ +package net.lab1024.sa.admin.module.business.wms.base.stock.service.impl; + +import cn.idev.excel.FastExcel; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.constant.UsageStatusEnum; +import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; +import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; +import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationService; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockAddForm; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StockUpdateForm; +import net.lab1024.sa.admin.module.business.wms.base.stock.domain.form.StocksImportForm; +import net.lab1024.sa.admin.module.business.wms.base.stock.manager.StockManager; +import net.lab1024.sa.admin.module.business.wms.base.stock.service.StockQueryService; +import net.lab1024.sa.admin.module.business.wms.base.stock.service.StockService; +import net.lab1024.sa.admin.util.JoinerResult; +import net.lab1024.sa.admin.util.ResponseDTOUtil; +import net.lab1024.sa.base.common.code.SystemErrorCode; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.dict.constant.DictConst; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class StockServiceImpl implements StockService { + @Resource + private LocationDao locationDao; + + @Resource + private StockManager stockManager; + + @Resource + private net.lab1024.sa.admin.util.ValidateDictKey ValidateDictKey; + + @Resource + private StockQueryService stockQueryService; + + @Resource + private LocationService locationService; + + + /** + * 添加 + * + * @param addForm 添加参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(StockAddForm addForm) { + StockEntity existingStock = stockQueryService.queryByStockCode(addForm.getStockCode()); + if (existingStock != null) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + StockEntity stockEntity = SmartBeanUtil.copy(addForm, StockEntity.class); + //添加并更新缓存 + stockManager.insert(stockEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm 更新参数 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(StockUpdateForm updateForm) { + StockEntity existingStock = stockQueryService.queryByStockCode(updateForm.getStockCode()); + if (existingStock != null && !existingStock.getStockId().equals(updateForm.getStockId())) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg()); + } + //当前更新的容器的库位 + if (existingStock != null && existingStock.getLocationId() != null) { + //更新库位状态 + locationService.updateLocationStatus(existingStock.getLocationId(), UsageStatusEnum.FREE.getValue()); + } + + if (updateForm.getLocationId() != null) { + LocationEntity location = locationDao.selectById(updateForm.getLocationId()); + StockEntity curStock = stockQueryService.queryStockByLocationId(updateForm.getLocationId()); + if (curStock != null && existingStock != null) { + if (!curStock.getStockId().equals(existingStock.getStockId())) { + return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, location.getLocationCode() + "库位绑定的当前容器为" + curStock.getStockCode()); + } + } + //更新库位状态 + locationService.updateLocationStatus(updateForm.getLocationId(), UsageStatusEnum.USED.getValue()); + } + StockEntity stockEntity = SmartBeanUtil.copy(updateForm, StockEntity.class); + //更新并更新缓存 + stockManager.update(stockEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList id集合 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + //删除并删除缓存 + stockManager.batchDelete(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + * + * @param stockId 容器Id + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long stockId) { + if (null == stockId) { + return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); + } + + //删除并删除缓存 + stockManager.deleteById(stockId); + return ResponseDTO.ok(); + } + + /** + * 容器导入 + * + * @param file 上传文件 + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO importStocks(MultipartFile file) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(StocksImportForm.class) + .sheet() + .doReadSync(); + } catch (IOException e) { + throw new BusinessException("数据格式存在问题,无法读取"); + } + if (CollectionUtils.isEmpty(dataList)) { + return ResponseDTO.userErrorParam("数据为空"); + } + + //获取所有去重后的容器类型 + List stockTypes = dataList.stream().map(StocksImportForm::getStockType).distinct().collect(Collectors.toList()); + + //验证容器类型 + Map itemTypeMap = ValidateDictKey.validateDictCodes(stockTypes, DictConst.STOCK_TYPE.getValue()); + + //获取所有去重后的容器编码 + List stockCodes = dataList.stream().map(StocksImportForm::getStockCode).distinct().collect(Collectors.toList()); + + //查询数据库存在的容器 + Map exitStockMap = stockQueryService.queryStockListToMap(stockCodes); + + List insertToStock = new ArrayList<>(); + List updateToStock = new ArrayList<>(); + for (StocksImportForm stocksImportForm : dataList) { + + //容器类型 + String stockType = itemTypeMap.get(stocksImportForm.getStockType()); + + //容器 + StockEntity stock = exitStockMap.get(stocksImportForm.getStockCode()); + + //容器为空新增,否则更新 + if (stock == null) { + insertToStock.add(createStock(stocksImportForm.getStockCode(), stockType)); + } else { + updateToStock.add(createStock(stocksImportForm.getStockCode(), stockType)); + } + } + + JoinerResult resultMsg = JoinerResult.createJoiner(); + return ResponseDTOUtil.buildResponseDTO(insertToStock, updateToStock, stockManager::batchInsert, stockManager::batchUpdate, resultMsg); + } + + /** + * 创建容器 + * + * @param stockCode 容器编码 + * @param stockType 容器类型 + * @return StockEntity + */ + public StockEntity createStock(String stockCode, String stockType) { + return StockEntity.builder() + .stockCode(stockCode) + .stockType(stockType) + .status(UsageStatusEnum.FREE.getValue()) + .disabledFlag(true) + .createUserId(SmartRequestUtil.getRequestUser().getUserId()) + .createUserName(SmartRequestUtil.getRequestUser().getUserName()) + .build(); + } +} diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/ReceiveService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/ReceiveService.java index 9de1e20..2df8fb6 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/ReceiveService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/ReceiveService.java @@ -1,14 +1,11 @@ package net.lab1024.sa.admin.module.business.wms.receive; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemQueryService; -import net.lab1024.sa.admin.module.business.wms.base.location.dao.LocationDao; import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity; import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService; -import net.lab1024.sa.admin.module.business.wms.base.stock.dao.StockDao; import net.lab1024.sa.admin.module.business.wms.base.stock.domain.entity.StockEntity; import net.lab1024.sa.admin.module.business.wms.base.stock.service.StockQueryService; import net.lab1024.sa.admin.module.business.wms.inventory.domain.entity.InventoryEntity; @@ -16,16 +13,12 @@ import net.lab1024.sa.admin.module.business.wms.inventory.manager.InventoryManag import net.lab1024.sa.admin.module.business.wms.inventory.service.InventoryQueryService; import net.lab1024.sa.admin.module.business.wms.inventory.service.InventoryService; import net.lab1024.sa.admin.module.business.wms.itemKey.domain.entity.ItemKeyEntity; -import net.lab1024.sa.admin.module.business.wms.itemKey.manager.ItemKeyManager; -import net.lab1024.sa.admin.module.business.wms.itemKey.service.ItemKeyQueryService; import net.lab1024.sa.admin.module.business.wms.itemKey.service.ItemKeyService; import net.lab1024.sa.admin.module.business.wms.receive.asn.dao.AsnDao; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.entity.AsnEntity; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.BatchReceiveForm; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.BatchReturnForm; -import net.lab1024.sa.admin.module.business.wms.receive.asn.service.AsnQueryService; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.entity.AsnDetailEntity; -import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.vo.AsnDetailVO; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.manager.AsnDetailManager; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.service.AsnDetailQueryService; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.service.AsnDetailService; @@ -35,14 +28,11 @@ import net.lab1024.sa.admin.module.business.wms.task.domain.entity.TaskEntity; import net.lab1024.sa.admin.module.business.wms.task.manager.TaskManager; import net.lab1024.sa.admin.module.business.wms.task.service.TaskQueryService; import net.lab1024.sa.admin.module.business.wms.task.service.TaskService; -import net.lab1024.sa.admin.module.business.wms.itemKey.domain.entity.ItemKeyEntity; -import net.lab1024.sa.admin.module.business.wms.receive.asn.service.AsnQueryService; import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; +import net.lab1024.sa.admin.util.ResponseDTOUtil; import net.lab1024.sa.base.common.code.UserErrorCode; import net.lab1024.sa.base.common.domain.ResponseDTO; import net.lab1024.sa.base.common.util.SmartBigDecimalUtil; -import net.lab1024.sa.base.common.util.SmartRequestUtil; import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; import net.lab1024.sa.base.module.support.serialnumber.constant.SerialNumberIdEnum; @@ -115,13 +105,13 @@ public class ReceiveService { */ @Transactional(rollbackFor = Exception.class) public ResponseDTO batchReceive(BatchReceiveForm batchReceiveForm) { - Long statrTime = System.currentTimeMillis(); + Long startTime = System.currentTimeMillis(); List asnDetails = asnDetailQueryService.queryAsnDetailList(batchReceiveForm.getAsnDetailIds()); if (CollectionUtils.isEmpty(asnDetails)) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } //消息提示 - JoinerResult joiner = JoinerResult.createJoiner(); + JoinerResult resultMsg = JoinerResult.createJoiner(); //查询物料 List itemIds = asnDetails.stream().map(AsnDetailEntity::getItemId).distinct().toList(); @@ -146,12 +136,12 @@ public class ReceiveService { ItemEntity item = itemMap.get(asnDetail.getItemId()); if (SmartBigDecimalUtil.subtract(asnDetail.getOrderQuantity(), asnDetail.getReceivedQuantity(), 2).compareTo(BigDecimal.ZERO) == 0) { - joiner.getErrorMsg().add(item.getItemCode() + "明细已收货"); + resultMsg.getErrorMsg().add(item.getItemCode() + "明细已收货"); continue; } if (asnDetail.getReceivedQuantity().compareTo(asnDetail.getOrderQuantity()) > 0) { - joiner.getErrorMsg().add(item.getItemCode() + "收货数量不能大于订单数量"); + resultMsg.getErrorMsg().add(item.getItemCode() + "收货数量不能大于订单数量"); continue; } @@ -185,7 +175,7 @@ public class ReceiveService { //生成库存日志 - joiner.getSussMsg().add(item.getItemCode() + "收货成功"); + resultMsg.getSussMsg().add(item.getItemCode() + "收货成功"); } //批量操作 @@ -195,12 +185,12 @@ public class ReceiveService { asnDetailService.refreshAsn(batchReceiveForm.getAsnId()); //操作日志 - dataTracerService.addTrace(asn.getAsnId(), DataTracerTypeEnum.ASN, "批量收货:" + joiner.getSussMsg().toString() + joiner.getErrorMsg().toString()); + dataTracerService.addTrace(asn.getAsnId(), DataTracerTypeEnum.ASN, "批量收货:" + resultMsg.getSussMsg().toString() + resultMsg.getErrorMsg().toString()); Long endTime = System.currentTimeMillis(); - log.info("批量收货耗时:{}ms", endTime - statrTime); + log.info("批量收货耗时:{}ms", endTime - startTime); - return ResponseDTOUtils.buildResponseDTO(joiner); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } /** @@ -242,14 +232,14 @@ public class ReceiveService { */ @Transactional(rollbackFor = Exception.class) public ResponseDTO batchReturn(BatchReturnForm batchReturnForm) { - Long statrTime = System.currentTimeMillis(); + Long startTime = System.currentTimeMillis(); List tasks = taskQueryService.queryByTaskIds(batchReturnForm.getTaskIds()); if (CollectionUtils.isEmpty(tasks)) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } //消息提示 - JoinerResult joiner = JoinerResult.createJoiner(); + JoinerResult resultMsg = JoinerResult.createJoiner(); //查询Task任务关联的所以入库明细 List asnDetailIds = tasks.stream().map(TaskEntity::getAsnDetailId).collect(Collectors.toList()); @@ -288,7 +278,7 @@ public class ReceiveService { } //生成库存日志 - joiner.getSussMsg().add(item.getItemCode() + "退货成功"); + resultMsg.getSussMsg().add(item.getItemCode() + "退货成功"); } //批量操作 returnUpdateOrInsert(updateToAsnDetail, deleteToTask, updateToInventory, deleteToInventory); @@ -297,12 +287,12 @@ public class ReceiveService { asnDetailService.refreshAsn(batchReturnForm.getAsnId()); //操作日志 - dataTracerService.addTrace(batchReturnForm.getAsnId(), DataTracerTypeEnum.ASN, "批量退货:" + joiner.getSussMsg().toString()); + dataTracerService.addTrace(batchReturnForm.getAsnId(), DataTracerTypeEnum.ASN, "批量退货:" + resultMsg.getSussMsg().toString()); Long endTime = System.currentTimeMillis(); - log.info("批量退货耗时:{}ms", endTime - statrTime); + log.info("批量退货耗时:{}ms", endTime - startTime); - return ResponseDTOUtils.buildResponseDTO(joiner); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } /** diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asn/service/AsnService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asn/service/AsnService.java index 789b1b9..53d9013 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asn/service/AsnService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asn/service/AsnService.java @@ -9,29 +9,18 @@ import net.lab1024.sa.admin.module.business.wms.receive.asn.constant.AsnOrderSta import net.lab1024.sa.admin.module.business.wms.receive.asn.dao.AsnDao; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.entity.AsnEntity; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.AsnAddForm; -import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.AsnQueryForm; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.AsnUpdateForm; -import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.vo.AsnVO; import net.lab1024.sa.admin.module.business.wms.receive.asn.manager.AsnManager; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.entity.AsnDetailEntity; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.manager.AsnDetailManager; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.service.AsnDetailQueryService; -import net.lab1024.sa.admin.module.business.wms.receive.asn.constant.AsnOrderStatusEnum; -import net.lab1024.sa.admin.module.business.wms.receive.asn.dao.AsnDao; -import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.entity.AsnEntity; -import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.form.AsnUpdateForm; -import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.service.AsnDetailQueryService; import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; +import net.lab1024.sa.admin.util.ResponseDTOUtil; import net.lab1024.sa.base.common.code.UserErrorCode; import net.lab1024.sa.base.common.exception.BusinessException; import net.lab1024.sa.base.common.util.SmartBeanUtil; -import net.lab1024.sa.base.common.util.SmartPageUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; -import net.lab1024.sa.base.common.domain.PageResult; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; -import net.lab1024.sa.base.module.support.datatracer.domain.form.DataTracerForm; import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; import net.lab1024.sa.base.module.support.serialnumber.constant.SerialNumberIdEnum; import net.lab1024.sa.base.module.support.serialnumber.service.SerialNumberService; @@ -127,7 +116,7 @@ public class AsnService { if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } - JoinerResult joiner = JoinerResult.createJoiner(); + JoinerResult resultMsg = JoinerResult.createJoiner(); //查询批量订单 List asnList = asnQueryService.queryAsnList(idList); @@ -147,17 +136,17 @@ public class AsnService { if (CollectionUtils.isNotEmpty(createAsnList)) { Set asnCodes = createAsnList.stream().map(AsnEntity::getAsnNumber).collect(Collectors.toSet()); asnManager.removeBatchByIds(createAsnList); - joiner.getSussMsg().add(asnCodes + "订单删除成功"); + resultMsg.getSussMsg().add(asnCodes + "订单删除成功"); } //非已创建的订单不允许删除 List noCreateAsnList = partitionedAsnList.get(false); if (CollectionUtils.isNotEmpty(noCreateAsnList)) { Set asnCodes = noCreateAsnList.stream().map(AsnEntity::getAsnNumber).collect(Collectors.toSet()); - joiner.getErrorMsg().add(asnCodes + "订单不允许删除"); + resultMsg.getErrorMsg().add(asnCodes + "订单不允许删除"); } - return ResponseDTOUtils.buildResponseDTO(joiner); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } /** diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asnDetail/service/AsnDetailService.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asnDetail/service/AsnDetailService.java index d19b0af..1ed2997 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asnDetail/service/AsnDetailService.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/wms/receive/asnDetail/service/AsnDetailService.java @@ -4,11 +4,9 @@ import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; -import net.lab1024.sa.admin.module.business.goods.domain.entity.GoodsEntity; import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; import net.lab1024.sa.admin.module.business.wms.base.item.domain.entity.ItemEntity; import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemQueryService; -import net.lab1024.sa.admin.module.business.wms.base.item.service.ItemService; import net.lab1024.sa.admin.module.business.wms.receive.asn.constant.AsnOrderStatusEnum; import net.lab1024.sa.admin.module.business.wms.receive.asn.dao.AsnDao; import net.lab1024.sa.admin.module.business.wms.receive.asn.domain.entity.AsnEntity; @@ -17,9 +15,8 @@ import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.entity. import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.form.AsnDetailAddForm; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.domain.form.AsnDetailUpdateForm; import net.lab1024.sa.admin.module.business.wms.receive.asnDetail.manager.AsnDetailManager; -import net.lab1024.sa.admin.module.business.wms.base.item.dao.ItemDao; import net.lab1024.sa.admin.util.JoinerResult; -import net.lab1024.sa.admin.util.ResponseDTOUtils; +import net.lab1024.sa.admin.util.ResponseDTOUtil; import net.lab1024.sa.base.common.code.UserErrorCode; import net.lab1024.sa.base.common.util.SmartBeanUtil; import net.lab1024.sa.base.common.domain.ResponseDTO; @@ -121,7 +118,7 @@ public class AsnDetailService { if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } - JoinerResult joiner = JoinerResult.createJoiner(); + JoinerResult resultMsg = JoinerResult.createJoiner(); List asnDetails = asnDetailQueryService.queryAsnDetailList(idList); List asnIds = asnDetails.stream().map(AsnDetailEntity::getAsnId).distinct().collect(Collectors.toList()); List itemIds = asnDetails.stream().map(AsnDetailEntity::getItemId).toList(); @@ -131,24 +128,24 @@ public class AsnDetailService { for (AsnDetailEntity asnDetail : asnDetails) { ItemEntity item = mapItem.get(asnDetail.getItemId()); if (asnDetail.getReceivedQuantity().compareTo(BigDecimal.ZERO) > 0) { - joiner.getErrorMsg().add(item.getItemCode() + "明细已收货"); + resultMsg.getErrorMsg().add(item.getItemCode() + "明细已收货"); continue; } toDeleteList.add(asnDetail.getAsnDetailId()); - joiner.getSussMsg().add(item.getItemCode() + "明细删除成功"); + resultMsg.getSussMsg().add(item.getItemCode() + "明细删除成功"); } if (CollectionUtils.isNotEmpty(toDeleteList)) { //批量删除 asnDetailManager.removeBatchByIds(toDeleteList); //操作记录 - dataTracerService.addTrace(asnIds.get(0), DataTracerTypeEnum.ASN, "批量删除:" + joiner.getSussMsg().toString()+ joiner.getErrorMsg().toString()); + dataTracerService.addTrace(asnIds.get(0), DataTracerTypeEnum.ASN, "批量删除:" + resultMsg.getSussMsg().toString()+ resultMsg.getErrorMsg().toString()); } //刷新出库单 asnIds.forEach(this::refreshAsn); - return ResponseDTOUtils.buildResponseDTO(joiner); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } /** @@ -162,26 +159,26 @@ public class AsnDetailService { if (null == asnDetailId) { return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg()); } - JoinerResult joiner = JoinerResult.createJoiner(); + JoinerResult resultMsg = JoinerResult.createJoiner(); AsnDetailEntity asnDetail = asnDetailDao.selectById(asnDetailId); ItemEntity item = itemDao.selectById(asnDetail.getItemId()); if (asnDetail.getReceivedQuantity().compareTo(BigDecimal.ZERO) > 0) { - joiner.getErrorMsg().add(item.getItemCode() + "明细已收货"); - return ResponseDTOUtils.buildResponseDTO(joiner); + resultMsg.getErrorMsg().add(item.getItemCode() + "明细已收货"); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } Long asnId = asnDetail.getAsnId(); asnDetailDao.deleteById(asnDetailId); - joiner.getSussMsg().add(item.getItemCode() + "删除成功"); + resultMsg.getSussMsg().add(item.getItemCode() + "删除成功"); //刷新出库单 refreshAsn(asnId); //操作记录 - dataTracerService.addTrace(asnId, DataTracerTypeEnum.ASN, "删除:" + joiner.getSussMsg().toString()+ joiner.getErrorMsg().toString()); + dataTracerService.addTrace(asnId, DataTracerTypeEnum.ASN, "删除:" + resultMsg.getSussMsg().toString()+ resultMsg.getErrorMsg().toString()); - return ResponseDTOUtils.buildResponseDTO(joiner); + return ResponseDTOUtil.buildResponseDTO(resultMsg); } public void refreshAsn(Long asnId) { diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtils.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtil.java similarity index 90% rename from nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtils.java rename to nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtil.java index bee850c..1f1334f 100644 --- a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtils.java +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/ResponseDTOUtil.java @@ -7,8 +7,8 @@ import org.apache.commons.collections4.CollectionUtils; import java.util.List; import java.util.function.Consumer; -public class ResponseDTOUtils { - private ResponseDTOUtils() { +public class ResponseDTOUtil { + private ResponseDTOUtil() { // 私有构造函数,防止实例化 } @@ -26,7 +26,7 @@ public class ResponseDTOUtils { if (joiner.getErrorMsg() != null) { jsonObject.put("error", joiner.getErrorMsg().toString()); } - return ResponseDTO.okMsg(jsonObject.toString()); + return ResponseDTO.ok(jsonObject.toString()); } /** @@ -37,7 +37,7 @@ public class ResponseDTOUtils { * @param updateBatchFunction 批量更新函数 * @param joiner Msg信息 */ - public static ResponseDTO buildResponseSussDTO( + public static ResponseDTO buildResponseDTO( List insertList, List updateList, Consumer> saveBatchFunction, diff --git a/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/TransactionCommitUtil.java b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/TransactionCommitUtil.java new file mode 100644 index 0000000..7c1bc05 --- /dev/null +++ b/nc_wms_java/sa-admin/src/main/java/net/lab1024/sa/admin/util/TransactionCommitUtil.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +@Slf4j +public class TransactionCommitUtil { + public static void executeAfterCommit(String operationDesc, Runnable operation) { + boolean inTransaction = TransactionSynchronizationManager.isSynchronizationActive(); + if (inTransaction) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + executeOperation(operationDesc, operation); + } + }); + } else { + executeOperation(operationDesc, operation); + } + } + + private static void executeOperation(String operationDesc, Runnable operation) { + try { + operation.run(); + } catch (Exception e) { + log.error("{}失败: {}", operationDesc, e.getMessage(), e); + } + } + +} diff --git a/nc_wms_java/sa-base/src/main/java/net/lab1024/sa/base/config/RedisConfig.java b/nc_wms_java/sa-base/src/main/java/net/lab1024/sa/base/config/RedisConfig.java index 5d1357c..ab9677a 100644 --- a/nc_wms_java/sa-base/src/main/java/net/lab1024/sa/base/config/RedisConfig.java +++ b/nc_wms_java/sa-base/src/main/java/net/lab1024/sa/base/config/RedisConfig.java @@ -33,7 +33,6 @@ public class RedisConfig { @Bean public RedisTemplate redisTemplate() { - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.registerModule(new JavaTimeModule()) .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false) @@ -45,7 +44,8 @@ public class RedisConfig { om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // enableDefaultTyping 官方已弃用 所以改为 activateDefaultTyping om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); - jackson2JsonRedisSerializer.setObjectMapper(om); + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(om,Object.class); + RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); diff --git a/nc_wms_java/solution.xml b/nc_wms_java/solution.xml new file mode 100644 index 0000000..52c78cb --- /dev/null +++ b/nc_wms_java/solution.xml @@ -0,0 +1,46 @@ + + + + + + + orders.id, + orders.order_number, + orders.status, + orders.create_time, + orders.updateInfo.operatorName, + orders.updateInfo.operateTime + + + + + + + + + + \ No newline at end of file