设计模式
约 11208 字大约 37 分钟
2026-04-04
设计模式
工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单工厂模式

优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
package com.servlet.utils;
import java.lang.reflect.InvocationTargetException;
/**
* @author 涂鏊飞tu_aofei@163.com
* @description: 工厂模式工具类 设计模式:简单工厂模式
* @create 2021-10-08 9:49
*/
public class FactoryUtils {
public static <T> T createInstance(String className) {
T instance = null;
try {
instance = (T) Class.forName(className).getDeclaredConstructor().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return instance;
}
}
private DepartmentDao departmentDao;
public DepartmentServiceImpl() {
departmentDao = FactoryUtils.createInstance(DepartmentDaoImpl.class.getName());
}
//-----------------------------------------------------------------------------------------------
private EmployeeDao employeeDao;
public EmployeeServiceImpl() {
employeeDao = FactoryUtils.createInstance(EmployeeDaoImpl.class.getName());
}抽象工厂模式
优点: 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点: 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
https://www.runoob.com/design-pattern/abstract-factory-pattern.html
单例模式

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
懒汉式,线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}懒汉式,线程安全(加锁就好了)
public class Singleton {
private static Singleton instance = null;
/**
* 私有构造方法,防止被实例化
*/
private Singleton(){}
/**
* 静态get方法
*/
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}懒汉式,双重DCL(通过双检锁做两次判断)
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全的创建实例
synchronized (Singleton.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}懒汉式,加上volatile修饰Singleton
public class Singleton {
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全的创建实例
synchronized (Singleton.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}懒汉式,volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,通过静态内部类
public class Singleton {
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/* 此处使用一个内部类来维护单例 */
private static class SingletonFactory {
private static Singleton instance = new Singleton();
}
/* 获取实例 */
public static Singleton getInstance() {
return SingletonFactory.instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return getInstance();
}
}public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// 单例模式(懒汉式,非线程安全)+简单工厂模式
public class DepartmentServiceImpl implements DepartmentService {
private DepartmentDao departmentDao;
private static DepartmentServiceImpl departmentService;
private DepartmentServiceImpl() {
departmentDao = FactoryUtils.createInstance(DepartmentDaoImpl.class.getName());
}
public static DepartmentServiceImpl getDepartmentServiceInstance() {
if (departmentService == null) {
departmentService = new DepartmentServiceImpl();
}
return departmentService;
}
public class FactoryUtils {
public static <T> T createInstance(String className) {
T instance = null;
try {
Constructor constructor = Class.forName(className).getDeclaredConstructor();
constructor.setAccessible(true);
instance = (T) constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}懒汉式,线程安全
优点:第一次调用才初始化,避免内存浪费。 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}饿汉式
优点:没有加锁,执行效率会提高。 缺点:类加载时就初始化,浪费内存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}代理模式
设计模式---代理模式 - Dan_Go - 博客园 (cnblogs.com)
静态代理
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。 缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
package com.proxy;
public interface BuyCar {
void buyCar();
}
package com.proxy;
public interface BuyHouse {
void buyHouse();
}
package com.proxy.impl;
import com.proxy.BuyHouse;
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHouse() {
System.out.println("我要买房");
}
}
package com.proxy.impl;
import com.proxy.BuyCar;
public class BuyCarImpl implements BuyCar {
@Override
public void buyCar() {
System.out.println("我要买车");
}
}
package com.proxy.proxy;
import com.proxy.BuyCar;
public class BuyCarProxy implements BuyCar {
private BuyCar buyCar;
public BuyCarProxy(final BuyCar buyCar) {
this.buyCar = buyCar;
}
@Override
public void buyCar() {
System.out.println("买车前准备...");
buyCar.buyCar();
System.out.println("买车后准备...");
}
}
package com.proxy.proxy;
import com.proxy.BuyHouse;
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHouse() {
System.out.println("买房前准备...");
buyHouse.buyHouse();
System.out.println("买房后装修...");
}
}
package com.proxy.test;
import com.proxy.BuyCar;
import com.proxy.BuyHouse;
import com.proxy.impl.BuyCarImpl;
import com.proxy.impl.BuyHouseImpl;
import com.proxy.proxy.BuyCarProxy;
import com.proxy.proxy.BuyHouseProxy;
public class Test1 {
public static void main(String[] args) {
BuyCar buyCar = new BuyCarImpl();
buyCar.buyCar();
BuyCarProxy buyCarProxy = new BuyCarProxy(buyCar);
buyCarProxy.buyCar();
BuyHouse buyHouse = new BuyHouseImpl();
buyHouse.buyHouse();
BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
buyHouseProxy.buyHouse();
}
}动态代理
package com.proxy.proxy;
import com.proxy.dao.BuyHouseDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BuyDynamicProxy implements InvocationHandler {
private Object dao;
public BuyDynamicProxy(Object dao) {
this.dao = dao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("之前准备...");
// dao:业务对象,args:方法所需参数
Object result = method.invoke(dao, args);
System.out.println("之后处理...");
return result;
}
}
package com.proxy.test;
import com.proxy.dao.BuyCarDao;
import com.proxy.dao.BuyHouseDao;
import com.proxy.dao.impl.BuyCarDaoImpl;
import com.proxy.dao.impl.BuyHouseDaoImpl;
import com.proxy.proxy.BuyDynamicProxy;
import java.lang.reflect.Proxy;
public class Test2 {
public static void main(String[] args) {
BuyCarDao buyCarDao = new BuyCarDaoImpl();
// 指定当前目标对象使用的类加载器,获取加载器的方法是固定的
ClassLoader classLoader = BuyCarDao.class.getClassLoader();
// 目标对象实现的接口的类型,使用泛型方式确认类型
Class[] classes = {BuyCarDao.class};
// 执行目标对象的方法时,会触发事件处理器的方法
BuyDynamicProxy buyDynamicProxy = new BuyDynamicProxy(buyCarDao);
BuyCarDao buyCarProxy= (BuyCarDao) Proxy.newProxyInstance(classLoader,classes,buyDynamicProxy);
buyCarProxy.buyCar();
BuyHouseDao buyHouseDao=new BuyHouseDaoImpl();
BuyHouseDao buyHouseProxy = (BuyHouseDao) Proxy.newProxyInstance(BuyHouseDao.class.getClassLoader(), new Class[]{BuyHouseDao.class}, new BuyDynamicProxy(buyHouseDao));
buyHouseProxy.buyHouse();
}
}策略模式
https://juejin.cn/post/7023351087230877704
接口
public interface SecurityEventMonitorExtInterface {
/**
* 是否满足条件
* @return
*/
boolean whetherMeetConditions(SecurityEventMonitorServiceRequest request, SecurityEventMonitorServiceResponse response);
} public static SecurityEventMonitorExtInterface getSecurityEventExt(String sceneCode) {
if (WsdStringUtils.isEmpty(sceneCode)) {
return null;
}
//根据场景编码获取对应的扩展实例配置
switch (sceneCode) {
case "AFCJ035":
return SecurityEventExtJbTsm.getInstance();
case "AFCJ002":
return SecurityEventExtWgDh.getInstance();
default:
break;
}
return null;
}
SecurityEventMonitorExtInterface securityEventExt = SecurityEventMonitorUtils.getSecurityEventExt(sceneCode);
if (securityEventExt != null) {
boolean allowGeneration = securityEventExt.whetherMeetConditions(request, response);
if (!allowGeneration) {
genError(response, "安防场景不满足生成条件");
}
}实现类
public class SecurityEventExtJbTsm implements SecurityEventMonitorExtInterface {
private static SecurityEventExtJbTsm instance = null;
private SecurityEventExtJbTsm() {
}
/**
* 双重校验锁获取实例
* @return
*/
public static SecurityEventExtJbTsm getInstance() {
if (instance == null){
synchronized (SecurityEventExtJbTsm.class){
if (instance == null){
instance = new SecurityEventExtJbTsm();
}
}
}
return instance;
}
@Override
public boolean whetherMeetConditions(SecurityEventMonitorServiceRequest request, SecurityEventMonitorServiceResponse response) {
...
if (countBySql > 0){
return false;
}
return true;
}
}
return false;
}
}外观模式(门面模式)
聚合查询接口
/**
* 聚合查询接口
*/
@RestController
@RequestMapping("/search")
@Slf4j
public class SearchController {
@Resource
private SearchFacade searchFacade;
@PostMapping("/all")
public BaseResponse<SearchVo> searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {
SearchVo searchVo = searchFacade.searchAll(searchQueryRequest, httpServletRequest);
return ResultUtils.success(searchVo);
}
}SearchFacade
/**
* @author tuaofei
* @description 查询-门面模式
* @date 2024/11/29
*/
@Component
@Slf4j
public class SearchFacade {
@Resource
private DataSourceRegistry dataSourceRegistry;
@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {
SearchVo searchVo = new SearchVo();
if (searchQueryRequest == null) {
return searchVo;
}
String searchText = searchQueryRequest.getSearchText();
String searchType = searchQueryRequest.getSearchType();
int current = searchQueryRequest.getCurrent();
int pageSize = searchQueryRequest.getPageSize();
if (StringUtils.isBlank(searchType)) {
CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {
SearchDataSource postDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.POST.getValue());
Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);
return postVOPage;
}, threadPoolTaskExecutor);
CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {
SearchDataSource userDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.USER.getValue());
Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);
return userVOPage;
}, threadPoolTaskExecutor);
CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {
SearchDataSource imageDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.IMAGE.getValue());
Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);
return imagePage;
}, threadPoolTaskExecutor);
CompletableFuture<Page<FileVo>> fileTask = CompletableFuture.supplyAsync(() -> {
SearchDataSource fileDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.FILE.getValue());
Page<FileVo> filePage = fileDataSource.doSearch(searchText, current, pageSize);
return filePage;
}, threadPoolTaskExecutor);
CompletableFuture.allOf(postTask, userTask, imageTask, fileTask);
try {
Page<PostVO> postVOPage = postTask.get();
searchVo.setPostList(postVOPage.getRecords());
Page<UserVO> userVOPage = userTask.get();
searchVo.setUserList(userVOPage.getRecords());
Page<Image> imagePage = imageTask.get();
searchVo.setImageList(imagePage.getRecords());
Page<FileVo> fileVoPage = fileTask.get();
searchVo.setFileList(fileVoPage.getRecords());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} else {
SearchDataSource<?> dataSource = dataSourceRegistry.getDataSourceByType(searchType);
Page<?> page = dataSource.doSearch(searchText, current, pageSize);
List<?> records = page.getRecords();
searchVo.setDataList(records);
}
return searchVo;
}
}数据源
/**
* @author tuaofei
* @description TODO
* @date 2024/11/29
*/
@Component
public class DataSourceRegistry {
@Resource
private ImageDataSource imageDataSource;
@Resource
private PostDataSource postDataSource;
@Resource
private UserDataSource userDataSource;
@Resource
private FileDataSource fileDataSource;
private Map<String, SearchDataSource<T>> dataSourceMap;
/**
* 在依赖注入完成后,执行
*/
@PostConstruct
public void doInit() {
dataSourceMap = new HashMap() {{
put(SearchTypeEnum.POST.getValue(), postDataSource);
put(SearchTypeEnum.USER.getValue(), userDataSource);
put(SearchTypeEnum.IMAGE.getValue(), imageDataSource);
put(SearchTypeEnum.FILE.getValue(), fileDataSource);
}};
}
public SearchDataSource getDataSourceByType(String searchType) {
if (dataSourceMap == null) {
return null;
}
return dataSourceMap.get(searchType);
}
}文件数据源
/**
* @author tuaofei
* @description TODO
* @date 2024/12/6
*/
@Service
public class FileDataSource implements SearchDataSource<FileVo>{
@Resource
private FileService fileService;
@Override
public Page<FileVo> doSearch(String searchText, int current, int pageSize) {
FileQueryRequest fileQueryRequest = new FileQueryRequest();
fileQueryRequest.setSearchText(searchText);
fileQueryRequest.setCurrent(current);
fileQueryRequest.setPageSize(pageSize);
Page<FileVo> fileVoPage = fileService.searchFromEs(fileQueryRequest);
return fileVoPage;
}
}图片数据源
/**
* @author tuaofei
* @description TODO
* @date 2024/11/26
*/
@Service
public class ImageDataSource implements SearchDataSource<Image> {
@Resource
private ImageService imageService;
@Override
public Page<Image> doSearch(String searchText, int current, int pageSize) {
ImageQueryRequest imageQueryRequest = new ImageQueryRequest();
imageQueryRequest.setSearchText(searchText);
imageQueryRequest.setCurrent(current);
imageQueryRequest.setPageSize(pageSize);
Page<Image> imageByPage = imageService.getImageByPage(imageQueryRequest);
return imageByPage;
}
}文章帖子数据源
/**
* 帖子服务实现
*/
@Service
@Slf4j
public class PostDataSource implements SearchDataSource<PostVO> {
@Resource
private PostService postService;
@Override
public Page<PostVO> doSearch(String searchText, int current, int pageSize) {
PostQueryRequest postQueryRequest = new PostQueryRequest();
postQueryRequest.setSearchText(searchText);
postQueryRequest.setCurrent(current);
postQueryRequest.setPageSize(pageSize);
HttpServletRequest httpServletRequest = null;
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes != null) {
httpServletRequest = servletRequestAttributes.getRequest();
}
Page<Post> postPage = postService.searchFromEs(postQueryRequest);
Page<PostVO> postVOPage = postService.getPostVOPage(postPage, httpServletRequest);
return postVOPage;
}
}用户数据源
/**
* 用户服务实现
*/
@Service
@Slf4j
public class UserDataSource implements SearchDataSource<UserVO> {
@Resource
private UserService userService;
@Override
public Page<UserVO> doSearch(String searchText, int current, int pageSize) {
UserQueryRequest userQueryRequest = new UserQueryRequest();
userQueryRequest.setUserName(searchText);
Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);
return userVOPage;
}
}建造者模式
生成器
/**
* 辅料到货计划生成器
*
* @Author tuaofei
* @Date 2022/9/8 16:15
*/
public class FlDhPlanGenerator {
private FlDhPlanGeneratorContext context;
private FlxqjhDhjhServiceResponse response;
private FlxqjhDhjhServiceRequest request;
private static final Logger logger = LoggerFactory.getLogger(FlDhPlanGenerator.class);
/**
* 供应商信息
* key:辅料code,value:供应商信息
*/
private Map<String, List<FlDemandPlanningDto>> flDemandPlanDtosByVCodeMap = new HashMap<>();
/**
* 辅料到货计划
*/
private List<FlxqjhDhjhDetDto> dhjhDetDtos = new ArrayList<>();
/**
* 辅料到货计划,特殊类型的材料只显示需求量
*/
private List<FlxqjhDhjhDetDto> dhjhDetOnlyXqlDtos = new ArrayList<>();
/**
* 需要生成的到货计划供应商信息明细
*/
private List<FlxqjhDhjhDetDto> supplierLst = new ArrayList<>();
public FlDhPlanGenerator() {
}
public void setClient(FlxqjhDhjhServiceRequest request, FlxqjhDhjhServiceResponse response) {
this.response = response;
this.request = request;
}
/**
* 检查上下文对象
*
* @return
*/
private boolean checkProperties() {
if (response == null) {
response = new FlxqjhDhjhServiceResponse();
}
context = new FlDhPlanGeneratorContext(response);
context.initContext();
List<WsdServiceMessage> messageLst = context.getResponse().getMessages()
.stream().filter(item -> CoreMessageConstants.MSG_LOGIC_ERROR == item.getType())
.collect(Collectors.toList());
if (WsdCollectionUtils.isNotEmpty(messageLst)) {
return false;
}
return true;
}
public List<FlxqjhDhjhDetDto> generator() {
long startTime = System.currentTimeMillis();
logger.info("generator start!");
if (!checkProperties()) {
return new ArrayList<>();
}
long l = System.currentTimeMillis();
LoadInDesignationTypeXqlEveryDay();
loadXqlEveryDay();
logger.warn("根据送货批量计划到货量完成,执行时间{}ms", (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
logger.info("开始调整到货计划");
packSummary();
adjustDhDate();
logger.warn("根据仓库最大送货能力,调整到货计划,执行时间{}ms", (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
logger.info("开始分配供应商");
queryFlDemandPlan();
dealYxFlCode();
//此处合并同一类型烟箱,不能放在查询供应商之前,分配供应商会收集flCode,如果修改辅料code为成品牌号会查询不到采购订单
mergeSameTypeYx();
supplierLst = assignSuppliers(dhjhDetDtos);
if (WsdCollectionUtils.isEmpty(supplierLst)) {
logger.error("无供应商信息");
} else {
//根据辅料编码和日期,汇总送货量
Map<String, FlxqjhDhjhDetDto> mapResult = new HashMap<>();
for (FlxqjhDhjhDetDto dto : supplierLst) {
String flCode = dto.getFlCode();
String supplierCode = dto.getSupplierCode();
Date flDate = dto.getFlDate();
String flDateStr = WsdDateUtils.dateToStr(flDate, "yyyy-MM-dd");
String key = flCode + flDateStr + supplierCode;
if (mapResult.containsKey(key)) {
FlxqjhDhjhDetDto dhjhDetDto = mapResult.get(key);
dhjhDetDto.setAllocatedQty(WsdBigDecimalUtils.add(dhjhDetDto.getAllocatedQty(), dto.getAllocatedQty()));
} else {
mapResult.put(key, dto);
}
}
supplierLst.clear();
supplierLst.addAll(mapResult.values());
dhjhDetDtos.addAll(supplierLst);
}
logger.warn("分配供应商完成,执行时间{}ms", (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
logger.info("开始创建到货计划");
//把只展示需求量的到货计划加进来
dhjhDetDtos.addAll(dhjhDetOnlyXqlDtos);
//生成到货计划
String curYearMonth = context.getCurYearMonth();
//返回当前月的主单dto
FlxqjhDhjhDto createDto = createDhjh(curYearMonth, dhjhDetDtos);
logger.info("创建到货计划完成,执行时间{}ms", (System.currentTimeMillis() - l));
if (createDto != null) {
//查询生成的数据
FlxqjhDhjhServiceRequest queryRequest = new FlxqjhDhjhServiceRequest();
queryRequest.setClient(request.getClient());
queryRequest.setMethod("loadData");
FlxqjhDhjhDto queryObject = new FlxqjhDhjhDto();
queryObject.setMonth(createDto.getMonth());
queryObject.setVer(createDto.getVer());
queryRequest.setQueryObject(queryObject);
FlxqjhDhjhServiceResponse queryResponse = WsdCommonFun.commonExcuteXfire(queryRequest);
if (queryResponse.getResult()) {
response.setResultList(queryResponse.getResultList());
}
}
logger.warn("generator end,执行时间{}ms", (System.currentTimeMillis() - startTime));
WsdServiceUtils.genDefaultSuccussMsg(request, response);
return dhjhDetDtos;
}
/**
* 2.处理同一类型烟箱修改对应的flCode和flName为[成品牌号,成品牌号名称+烟箱]
* 例如:04181299M -> 81299黄鹤楼(硬红)M烟箱
* <p>
* 注意:烟箱特殊处理需求修改3个地方
* 1.dealYxFlCode 供应商处理
* 2.mergeSameTypeYx 辅料到货计划处理
* 3.setUom 查询辅料到货计划处理
*/
private void mergeSameTypeYx() {
Map<String, String> flCodeAndCpNameRelMap = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(context.getFlxqjhKccxDtos())) {
/**
* 根据辅料code对应成品牌号code和成品牌号名称,只查找包含烟箱的,一个辅料编码可能对应多个成品牌号,对应的成品牌号使用前5位统计为一类;
* 以辅料编号作为键,会重复,所以使用覆盖的方法,覆盖成品信息,只取成品名称的前5位
* 烟箱:辅料code查询到成品牌号,成品牌号的前5位作为同一类型烟箱处理!
*/
flCodeAndCpNameRelMap = context.getFlxqjhKccxDtos().stream()
.filter(item -> item.getD_name().contains("烟箱"))
.collect(Collectors.toMap(FlxqjhKccxDto::getD_code, item -> (item.getM_code().substring(0, 8) + "#" + item.getM_name().substring(0, 5) + "烟箱"), (o1, o2) -> o2));
}
//不在特殊类型中的到货计划
retSetDhjhFlCodeAndName(flCodeAndCpNameRelMap, dhjhDetDtos);
//在特殊类型中只显示需求量的到货计划
retSetDhjhFlCodeAndName(flCodeAndCpNameRelMap, dhjhDetOnlyXqlDtos);
}
/**
* 重新设置辅料需求计划的code和name
*/
private void retSetDhjhFlCodeAndName(Map<String, String> flCodeAndCpNameRelMap, List<FlxqjhDhjhDetDto> dhjhDetDtos) {
List<FlxqjhDhjhDetDto> yxLst = new ArrayList<>();
Iterator<FlxqjhDhjhDetDto> iterator = dhjhDetDtos.iterator();
while (iterator.hasNext()) {
FlxqjhDhjhDetDto dto = iterator.next();
String flCode = dto.getFlCode();
if (flCodeAndCpNameRelMap.keySet().contains(flCode)) {
FlxqjhDhjhDetDto newYxDetDto = new FlxqjhDhjhDetDto();
WsdBeanUtils.copyProperties(dto, newYxDetDto, true);
String cpCodeAndName = flCodeAndCpNameRelMap.get(flCode);
if (WsdStringUtils.isNotEmpty(cpCodeAndName)) {
String[] split = cpCodeAndName.split("#");
String cpCode = split[0];
String cpName = split[1];
//重新设置
newYxDetDto.setFlCode(cpCode);
newYxDetDto.setFlName(cpName);
yxLst.add(newYxDetDto);
iterator.remove();
}
}
}
dhjhDetDtos.addAll(yxLst);
}
/**
* 1.特殊处理烟箱,合并同一类型的烟箱的供应商信息
* <p>
* 注意:烟箱特殊处理需求修改3个地方
* 1.dealYxFlCode 供应商处理
* 2.mergeSameTypeYx 辅料到货计划处理
* 3.setUom 查询辅料到货计划处理
*/
private void dealYxFlCode() {
/**
* 烟箱:辅料code查询到成品牌号,成品牌号的前5位作为同一类型烟箱处理!
* 同一类型的烟箱特殊计算,同一类型的烟箱中的辅料直接匹配成品牌号
* 直接把烟箱的辅料code转换成成品牌号,后面分配时直接可以匹配到成品牌号
*/
//<key:辅料code,value:成品牌号code>
Map<String, String> flCodeAndCpNameRelMap = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(context.getFlxqjhKccxDtos())) {
//根据辅料code对应成品牌号code和成品牌号名称,只查找包含烟箱的
flCodeAndCpNameRelMap = context.getFlxqjhKccxDtos().stream()
.filter(item -> item.getD_name().contains("烟箱"))
.collect(Collectors.toMap(FlxqjhKccxDto::getD_code, item -> (item.getM_code().substring(0, 8) + "#" + item.getM_name().substring(0, 5) + "烟箱"), (o1, o2) -> o2));
}
//新的成品牌号对应的供应商
Map<String, List<FlDemandPlanningDto>> flDemandPlanCpMap = new HashMap<>();
Iterator<Map.Entry<String, List<FlDemandPlanningDto>>> iterator = flDemandPlanDtosByVCodeMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<FlDemandPlanningDto>> entry = iterator.next();
String flCode = entry.getKey();
List<FlDemandPlanningDto> flDemandPlanLst = entry.getValue();
//如果查询到对应关系,移除原供应商中的辅料数据
String cpCodeAndName = flCodeAndCpNameRelMap.get(flCode);
if (WsdStringUtils.isNotEmpty(cpCodeAndName)) {
String[] split = cpCodeAndName.split("#");
String cpCode = split[0];
String cpName = split[1];
if (WsdStringUtils.isNotEmpty(cpCode)) {
iterator.remove();
}
//添加要新增的成品牌号数据
List<FlDemandPlanningDto> list = flDemandPlanCpMap.get(cpCode);
if (WsdCollectionUtils.isEmpty(list)) {
flDemandPlanCpMap.put(cpCode, flDemandPlanLst);
} else {
list.addAll(flDemandPlanLst);
}
}
}
//重新设置同一类型的烟箱的供应商,以成品牌号作为key
flDemandPlanDtosByVCodeMap.putAll(flDemandPlanCpMap);
}
/**
* 创建到货计划
*
* @param month
* @param detDtos
* @return
*/
private FlxqjhDhjhDto createDhjh(String month, List<FlxqjhDhjhDetDto> detDtos) {
if (WsdCollectionUtils.isEmpty(detDtos)) {
return null;
}
//查询当月最大到货计划版本号
String maxVer = context.getFlxqjhDhjhDao().queryMaxVersion(month);
String newVer;
if (WsdStringUtils.isNotEmpty(maxVer)) {
newVer = String.valueOf(Integer.parseInt(maxVer) + 1);
} else {
newVer = month.replace("-", "") + "01";
}
List<FlxqjhDhjhDto> dtos = new ArrayList<>();
FlxqjhDhjhDto dto = new FlxqjhDhjhDto();
dtos.add(dto);
dto.setMonth(month);
dto.setVer(newVer);
dto.setFlStatus(STATUS_CREATE);
dto.setDetails(detDtos);
//查询辅料基础信息
Set<String> flCodes = new HashSet<>();
for (FlxqjhDhjhDetDto detDto : detDtos) {
flCodes.add(detDto.getFlCode());
}
Map<String, MaterielCompInfoDto> matMap = context.getFlxqjhKcyjDao().queryMatInfo(flCodes);
//补充烟箱信息,只有成品牌号名称的前8位,查询辅料名称,类型,单位
Set<String> cpCode8Set = flCodes.stream().filter(item -> item.length() == 8).collect(Collectors.toSet());
Map<String, List<FlxqjhDhjhMergeDto>> cpCode8Map = context.getFlxqjhDhjhDao().queryYxByBefore8Code(cpCode8Set);
for (FlxqjhDhjhDetDto detDto : detDtos) {
MaterielCompInfoDto matDto = matMap.get(detDto.getFlCode());
if (matDto == null) {
FlxqjhDhjhMergeDto mergeDto = cpCode8Map.get(detDto.getFlCode()).get(0);
detDto.setFlName(mergeDto.getCpName());
detDto.setFlType(mergeDto.getFlType());
detDto.setFlUom(mergeDto.getFlUom());
} else {
detDto.setFlName(matDto.getMaterielName());
detDto.setFlType(matDto.getMaterielType());
detDto.setFlUom(matDto.getBaseUom_uomName());
}
}
FlxqjhDhjhServiceRequest createRequest = new FlxqjhDhjhServiceRequest();
createRequest.setClient(request.getClient());
createRequest.setMethod("create");
createRequest.setRequestObjects(dtos);
context.getWsdBizService().service(createRequest);
return dto;
}
/**
* 因为库存需要加上到货量和要调整的量,所以按天来计算,每天的到货量
*/
private void calDhJh() {
Date curDate = context.getCurDate();
Date monthMaxDate = context.getMonthMaxDate();
Map<String, Map<String, BigDecimal>> matCodeXqFourMap = context.getMatCodeXqFourMap();
//需要更新的库存
Map<String, BigDecimal> mapFlQckc = context.getMapFlQckc();
//送货批量
Map<String, BigDecimal> mapFlShpl = context.getMapFlShpl();
//初期库存
Map<String, BigDecimal> mapFlkc = context.getMapFlkc();
//托盘转换系数
Map<String, BigDecimal> mapPackModulus = context.getMapPackModulus();
queryFlDemandPlan();
for (Date cur = curDate; cur.before(monthMaxDate); cur = WsdDateUtils.addDays(cur, 1)) {
String yearAndMonth = WsdDateUtils.dateToStr(cur, "yyyy-MM");
String day = WsdDateUtils.dateToStr(cur, "dd");
if ("0".equals(day.substring(0, 1))) {
day = day.substring(1);
}
String curDateStr = yearAndMonth + "-" + day;
Map<String, BigDecimal> mapFlQty = matCodeXqFourMap.get(curDateStr);
if (mapFlQty != null && mapFlQty.size() > 0) {
//存储当前的辅料到货计划
List<FlxqjhDhjhDetDto> curDhjhDetDtos = new ArrayList<>();
for (Map.Entry<String, BigDecimal> entry : mapFlQty.entrySet()) {
//第i天的各牌号的需求量
//辅料编码
String matCode = entry.getKey();
//第i天辅料的需求量
BigDecimal xql = entry.getValue();
//第i天辅料的库存
BigDecimal kc = mapFlQckc.get(matCode);
//辅料的送货批量
BigDecimal shpl = mapFlShpl.get(matCode);
kc = WsdBigDecimalUtils.subtract(kc, xql);
if (WsdBigDecimalUtils.lessThan(kc, BigDecimal.ZERO)) {
//需要第i天到货,增加一条到货计划明细
//一个送货批量不一定能满足需求,可能需要乘以倍数
int beishu = 0;
do {
kc = WsdBigDecimalUtils.add(kc, shpl);
beishu++;
}
while (WsdBigDecimalUtils.lessThan(kc, BigDecimal.ZERO));
//实际到货计划数量,今天这个辅料的到货量
BigDecimal actDhNum = WsdBigDecimalUtils.multiply(new BigDecimal(beishu), shpl);
//更新库存,初期库存-需求量,暂时不加到货量
mapFlQckc.put(matCode, kc);
FlxqjhDhjhDetDto dhjhDetDto = new FlxqjhDhjhDetDto();
dhjhDetDto.setFlCode(matCode);
dhjhDetDto.setQcInv(mapFlkc.containsKey(matCode) ? mapFlkc.get(matCode) : BigDecimal.ZERO);
dhjhDetDto.setShQty(actDhNum);
dhjhDetDto.setFlDate(cur);
curDhjhDetDtos.add(dhjhDetDto);
}
}
//上一步处理今天的辅料到货量
packSummaryOnlyOneDay(curDhjhDetDtos);
adjustDhDate();
dealYxFlCode();
//计算今天所有的辅料的到货量,更新库存:初期库存(原初期库存-需求量+)+到货量
for (FlxqjhDhjhDetDto dhjhDetDto : dhjhDetDtos) {
Date flDate = dhjhDetDto.getFlDate();
if (flDate.equals(cur)) {
BigDecimal kc = mapFlQckc.get(dhjhDetDto.getFlCode());
mapFlQckc.put(dhjhDetDto.getFlCode(), WsdBigDecimalUtils.add(kc, dhjhDetDto.getShQty()));
}
}
mergeSameTypeYx();
}
}
}
/**
* 计算一直到截至日的每天需求量、对比每天的需求量是否满足,不满足则当月+送货批量,一直迭代到截至日
*
* @return
*/
private boolean loadXqlEveryDay() {
Date curDate = context.getCurDate();
Date monthMaxDate = context.getMonthMaxDate();
Map<String, Map<String, BigDecimal>> matCodeXqMap = context.getMatCodeXqMap();
Map<String, Map<String, BigDecimal>> matCodeXqFourMap = context.getMatCodeXqFourMap();
Map<String, BigDecimal> mapFlQckc = context.getMapFlQckc();
Map<String, BigDecimal> mapFlShpl = context.getMapFlShpl();
Map<String, BigDecimal> mapFlkc = context.getMapFlkc();
//计算一直到截至日的每天需求量、对比每天的需求量是否满足,不满足则当月+送货批量,一直迭代到截至日
Map<String, BigDecimal> matCodeXqSumMap = context.getMatCodeXqSumMap();
for (Date cur = curDate; cur.before(monthMaxDate) || cur.compareTo(monthMaxDate) == 0; cur = WsdDateUtils.addDays(cur, 1)) {
String yearAndMonth = WsdDateUtils.dateToStr(cur, "yyyy-MM");
String day = WsdDateUtils.dateToStr(cur, "dd");
if ("0".equals(day.substring(0, 1))) {
day = day.substring(1);
}
String curDateStr = yearAndMonth + "-" + day;
//第i天的各辅料的4天需求量
Map<String, BigDecimal> curDayFlXqFourMap = matCodeXqFourMap.get(curDateStr);
//第i天的各辅料的需求量
Map<String, BigDecimal> curDayFlXqMap = matCodeXqMap.get(curDateStr);
if (curDayFlXqFourMap != null && !curDayFlXqFourMap.isEmpty()) {
for (Map.Entry<String, BigDecimal> entry : curDayFlXqFourMap.entrySet()) {
//第i天的各牌号的需求量
//辅料编码
String matCode = entry.getKey();
//第i天到截止日的总需求量
BigDecimal zxql = matCodeXqSumMap.get(matCode);
//第i天辅料的4天需求量
BigDecimal xql4 = entry.getValue();
//第i天辅料的需求量
BigDecimal xql = BigDecimal.ZERO;
if(curDayFlXqMap.containsKey(matCode)){
xql = curDayFlXqMap.get(matCode);
}
if(zxql == null || WsdBigDecimalUtils.lessOrEquals(zxql, BigDecimal.ZERO)){
continue;
}
//第i天辅料的库存
BigDecimal kc = mapFlkc.get(matCode);
//辅料的送货批量
BigDecimal shpl = mapFlShpl.get(matCode);
if (!mapFlShpl.containsKey(matCode)) {
genError(response, "辅料【" + matCode + "】没有设置送货批量,请维护!");
return false;
}
if (WsdBigDecimalUtils.lessOrEquals(shpl, BigDecimal.ZERO)) {
genError(response, "辅料【" + matCode + "】送货批量设置小于等于0,数据异常请检查!");
return false;
}
//当天到截止日的实际需求量
BigDecimal actZxql = WsdBigDecimalUtils.subtract(zxql, kc);
//第i天的库存<4天需求量并且当天到截止日的实际需求量>0,则安排送货
if (WsdBigDecimalUtils.lessThan(kc, xql4) && WsdBigDecimalUtils.greaterThan(actZxql, BigDecimal.ZERO)) {
//当天到截止日的实际需求量 < 送货批量,则按当天到截止日的实际需求量配送,否则按送货批量配送(只送一车)
if(WsdBigDecimalUtils.lessThan(actZxql, shpl)){
shpl = actZxql;
}
//需要第i天到货,增加一条到货计划明细
kc = WsdBigDecimalUtils.add(kc, shpl);
if(WsdBigDecimalUtils.lessThan(kc, BigDecimal.ZERO)){
System.out.println("辅料【"+matCode+"】第"+curDateStr+"日安排送货后,依旧不满足当日生产需求!");
}
BigDecimal actDhNum = shpl;
FlxqjhDhjhDetDto dhjhDetDto = new FlxqjhDhjhDetDto();
dhjhDetDto.setFlCode(matCode);
dhjhDetDto.setQcInv(mapFlQckc.getOrDefault(matCode, BigDecimal.ZERO));
dhjhDetDto.setShQty(actDhNum);
dhjhDetDto.setFlDate(cur);
dhjhDetDtos.add(dhjhDetDto);
mapFlkc.put(matCode, kc);
}
if(WsdBigDecimalUtils.lessThan(zxql, xql)){
throw new WsdBusinessException("辅料【"+matCode+"】第"+curDateStr+"日的总需求量小于当日需求量,数据异常,请检查!");
}
//更新第i+1天的库存(减去当日的需求量)
kc = WsdBigDecimalUtils.subtract(kc, xql);
mapFlkc.put(matCode, kc);
//更新第i天到截止日的总需求量(减去当日的需求量)
zxql = WsdBigDecimalUtils.subtract(zxql, xql);
matCodeXqSumMap.put(matCode, zxql);
}
}
}
return true;
}
/**
* 特殊处理的辅料转换为到货计划,只展示需求量即可
*/
private void LoadInDesignationTypeXqlEveryDay() {
Date curDate = context.getCurDate();
Date monthMaxDate = context.getMonthMaxDate();
Map<String, Map<String, BigDecimal>> matCodeXqInDesignationTypeMap = context.getMatCodeXqInDesignationTypeMap();
Map<String, BigDecimal> mapFlQckc = context.getMapFlQckc();
//计算一直到截至日的每天需求量、对比每天的需求量是否满足,不满足则当月+送货批量,一直迭代到截至日
for (Date cur = curDate; cur.before(monthMaxDate); cur = WsdDateUtils.addDays(cur, 1)) {
String yearAndMonth = WsdDateUtils.dateToStr(cur, "yyyy-MM");
String day = WsdDateUtils.dateToStr(cur, "dd");
if ("0".equals(day.substring(0, 1))) {
day = day.substring(1);
}
String curDateStr = yearAndMonth + "-" + day;
Map<String, BigDecimal> mapFlQty = matCodeXqInDesignationTypeMap.get(curDateStr);
if (mapFlQty != null && mapFlQty.size() > 0) {
for (Map.Entry<String, BigDecimal> entry : mapFlQty.entrySet()) {
//第i天的各牌号的需求量
//辅料编码
String matCode = entry.getKey();
//第i天辅料的需求量
BigDecimal xql = entry.getValue();
if (WsdBigDecimalUtils.greaterThan(xql, BigDecimal.ZERO)) {
//实际到货计划数量
BigDecimal actDhNum = xql;
FlxqjhDhjhDetDto dhjhDetDto = new FlxqjhDhjhDetDto();
dhjhDetDto.setFlCode(matCode);
dhjhDetDto.setQcInv(mapFlQckc.containsKey(matCode) ? mapFlQckc.get(matCode) : BigDecimal.ZERO);
dhjhDetDto.setShQty(actDhNum);
dhjhDetDto.setFlDate(cur);
dhjhDetOnlyXqlDtos.add(dhjhDetDto);
}
}
}
}
}
/**
* 计划到货量按托盘汇总
*/
private void packSummary() {
Map<String, BigDecimal> mapPackModulus = context.getMapPackModulus();
for (FlxqjhDhjhDetDto dto : dhjhDetDtos) {
BigDecimal shQty = dto.getShQty();
String flCode = dto.getFlCode();
BigDecimal zhQtyPack = mapPackModulus.get(flCode);
BigDecimal shQtyPack = BigDecimal.ZERO;
//没有托盘转换设置为0
if (zhQtyPack != null && WsdBigDecimalUtils.greaterThan(zhQtyPack, BigDecimal.ZERO)) {
shQtyPack = WsdBigDecimalUtils.divide(shQty, zhQtyPack).setScale(4, BigDecimal.ROUND_HALF_UP);
}
dto.setShQtyPack(shQtyPack);
}
}
/**
* 处理单天的辅料到货计划
*
* @param curDhjhDetDtos
*/
private void packSummaryOnlyOneDay(List<FlxqjhDhjhDetDto> curDhjhDetDtos) {
Map<String, BigDecimal> mapPackModulus = context.getMapPackModulus();
for (FlxqjhDhjhDetDto dto : curDhjhDetDtos) {
BigDecimal shQty = dto.getShQty();
String flCode = dto.getFlCode();
BigDecimal zhQtyPack = mapPackModulus.get(flCode);
BigDecimal shQtyPack = BigDecimal.ZERO;
//没有托盘转换设置为0
if (zhQtyPack != null && WsdBigDecimalUtils.greaterThan(zhQtyPack, BigDecimal.ZERO)) {
shQtyPack = WsdBigDecimalUtils.divide(shQty, zhQtyPack).setScale(4, BigDecimal.ROUND_HALF_UP);
}
dto.setShQtyPack(shQtyPack);
}
}
/**
* 根据仓库最大作业能力调整到货计划
*/
private void adjustDhDate() {
//分组根据日期 <日期,flCode,6000,"total",单日总送货量> 主单位
Map<Date, Map<String, FlxqjhDhjhDetDto>> dhjhDetByDateMap = dhjhDetDtos.stream().collect(Collectors.groupingBy(FlxqjhDhjhDetDto::getFlDate, Collectors.toMap(FlxqjhDhjhDetDto::getFlCode, item -> item)));
for (Map.Entry<Date, Map<String, FlxqjhDhjhDetDto>> entry : dhjhDetByDateMap.entrySet()) {
Map<String, FlxqjhDhjhDetDto> map = entry.getValue();
BigDecimal total = map.entrySet().stream().map(item -> item.getValue().getShQtyPack()).reduce(BigDecimal.ZERO, BigDecimal::add);
FlxqjhDhjhDetDto totalDto = new FlxqjhDhjhDetDto();
totalDto.setShQtyPack(total);
map.put("total", totalDto);
}
//超出仓库最大作业能力的调整送货日期
Map<String, Date> adjustShQtyDateMap = buildAdjustDhDateMap(dhjhDetByDateMap, context.getMaxAbilityPack());
//dhjhDetDtos 重新设置日期
for (FlxqjhDhjhDetDto dto : dhjhDetDtos) {
String flCode = dto.getFlCode();
Date date = adjustShQtyDateMap.get(flCode+WsdDateUtils.dateToStr(dto.getFlDate(), WsdDateUtils.DATE_FORMAT_SHORT));
if (date != null) {
dto.setFlDate(date);
}
}
}
/**
* 构建需要重新调整的辅料到货日期
*
* @param dhjhDetByDateMap 辅料的到货信息,根据日期分组
* @param maxAbilityPack 最大作业能力
* @return
*/
private Map<String, Date> buildAdjustDhDateMap(Map<Date, Map<String, FlxqjhDhjhDetDto>> dhjhDetByDateMap, BigDecimal maxAbilityPack) {
Map<String, Date> adjustShQtyDateMap = new HashMap<>();
for (Map.Entry<Date, Map<String, FlxqjhDhjhDetDto>> entry : dhjhDetByDateMap.entrySet()) {
Date day = entry.getKey();
Map<String, FlxqjhDhjhDetDto> value = entry.getValue();
FlxqjhDhjhDetDto total = value.get("total");
//如果单日总到货量超出仓库最大作业能力
if (WsdBigDecimalUtils.greaterThan(total.getShQtyPack(), maxAbilityPack)) {
//超出托盘数
BigDecimal exceedShQtyPack = WsdBigDecimalUtils.subtract(total.getShQtyPack(), maxAbilityPack);
String minShQtyFlCode = "";
BigDecimal tempMix = BigDecimal.ZERO;
for (Map.Entry<String, FlxqjhDhjhDetDto> dtoEntry : value.entrySet()) {
BigDecimal mixQty = BigDecimal.ZERO;
String flCode = dtoEntry.getKey();
if (!"total".equals(flCode)) {
FlxqjhDhjhDetDto shQtyPack = dtoEntry.getValue();
//等于0没有意义
if (!WsdBigDecimalUtils.equals(shQtyPack.getShQtyPack(), BigDecimal.ZERO)) {
//每个辅料的送货量-超出托盘数,值最小的安排后一天到货.考虑没有托盘转换单位的辅料,值为0,移动了也没有影响
//没有考虑如果移动了还是超出最大作业能力
mixQty = WsdBigDecimalUtils.subtract(shQtyPack.getShQtyPack(), exceedShQtyPack);
//取大于0的辅料
if (WsdBigDecimalUtils.greaterThan(tempMix, mixQty)) {
tempMix = mixQty;
minShQtyFlCode = flCode;
}
}
}
}
//设置需要移动的到货信息
int dayNum = 1;
Date nextDay = WsdDateUtils.addDays(day, dayNum);
//判断下一天是否超负荷
Map<String, FlxqjhDhjhDetDto> nextValue = dhjhDetByDateMap.get(nextDay);
BigDecimal nextShQtyPack = BigDecimal.ZERO;
if (nextValue != null) {
FlxqjhDhjhDetDto nextTotal = nextValue.get("total");
nextShQtyPack = WsdBigDecimalUtils.add(nextTotal.getShQtyPack(), tempMix);
}
if (WsdBigDecimalUtils.greaterThan(nextShQtyPack, maxAbilityPack)) {
BigDecimal preShQtyPack = BigDecimal.ZERO;
//判断上一天是否超负荷
do {
dayNum -= 1;
//取反操作
if (dayNum >= 0) {
dayNum = -1;
}
Date preDay = WsdDateUtils.addDays(day, dayNum);
Map<String, FlxqjhDhjhDetDto> preValue = dhjhDetByDateMap.get(preDay);
BigDecimal preTotalShQtyPack = BigDecimal.ZERO;
//可能推到开始测算日期之前,没有数据
if (preValue != null) {
FlxqjhDhjhDetDto preTotal = preValue.get("total");
preTotalShQtyPack = preTotal.getShQtyPack();
}
preShQtyPack = WsdBigDecimalUtils.add(preTotalShQtyPack, tempMix);
} while (WsdBigDecimalUtils.greaterThan(preShQtyPack, maxAbilityPack));
}
//收集需要重新设置的辅料
nextDay = WsdDateUtils.addDays(day, dayNum);
adjustShQtyDateMap.put(minShQtyFlCode+WsdDateUtils.dateToStr(day, WsdDateUtils.DATE_FORMAT_SHORT), nextDay);
//删除原有的到货信息
//value.remove(minShQtyFlCode);
}
}
return adjustShQtyDateMap;
}
/**
* 分配供应商
*
* @return
*/
private List<FlxqjhDhjhDetDto> assignSuppliers(List<FlxqjhDhjhDetDto> dhjhDetDtos) {
List<FlxqjhDhjhDetDto> supplierLst = new ArrayList<>();
if (WsdCollectionUtils.isNotEmpty(dhjhDetDtos)) {
List<FlxqjhDhjhDetDto> dhjhDetByDaySortLst = dhjhDetDtos.stream()
.sorted(Comparator.comparing(FlxqjhDhjhDetDto::getFlDate)).collect(Collectors.toList());
List<FlxqjhDhjhDetDto> createSupplierLst = new ArrayList<>();
//知道每个辅料每天的到货量,按顺序减供应商的数量,减到0为止
for (FlxqjhDhjhDetDto flxqDto : dhjhDetByDaySortLst) {
//当前辅料的需求量
BigDecimal shQty = flxqDto.getShQty();
String flCode = flxqDto.getFlCode();
Date flDate = flxqDto.getFlDate();
List<FlDemandPlanningDto> flDemandPlanDtos = flDemandPlanDtosByVCodeMap.get(flCode);
//当前辅料对应的供应商信息<key:辅料编码+供应商code>
Map<String, BigDecimal> supplierMap = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(flDemandPlanDtos)) {
for (FlDemandPlanningDto flDemandPlanDto : flDemandPlanDtos) {
BigDecimal d_ddwdhsl = flDemandPlanDto.getD_ddwdhsl();
//防止供应商数据,未到货数量为0的情况出现
if (WsdBigDecimalUtils.equals(d_ddwdhsl, BigDecimal.ZERO)) {
continue;
}
//需求量为0,不用再计算
if (WsdBigDecimalUtils.equals(shQty, BigDecimal.ZERO)) {
break;
}
/**
* <= 0 6000-12000 6000-6000 只安排一个供应商,分配的送货量=需求量
* > 0 6000-1090 安排多个供应商,分配的送货量 = 供应商未到货数量
*/
BigDecimal laveQty = BigDecimal.ZERO;
laveQty = WsdBigDecimalUtils.subtract(shQty, d_ddwdhsl);
//物料编码+供应商编码+供应商名称+基本单位+采购订单编号(区分同一个供应商,同一个辅料,属于不同的采购订单)
//针对烟箱时,flcode为成品牌号前8位,具体的供应商信息位实际的辅料code,为了使parentcode一致
String key = flCode + "#" + flDemandPlanDto.getV_gys() + "#" + flDemandPlanDto.getO_gysmc() + "#" + flDemandPlanDto.getO_jbdw() + "#" + flDemandPlanDto.getV_cgdd();
if (WsdBigDecimalUtils.lessOrEquals(laveQty, BigDecimal.ZERO)) {
//需求量<未到货数量,则一个供应商可以满足
supplierMap.put(key, shQty);
//供应商未到货数量重新设置(需要减去需求量)
if (WsdBigDecimalUtils.lessThan(laveQty, BigDecimal.ZERO)) {
flDemandPlanDto.setD_ddwdhsl(WsdBigDecimalUtils.subtract(d_ddwdhsl, shQty));
} else {
flDemandPlanDto.setD_ddwdhsl(shQty);
}
//重新设置需求量
shQty = BigDecimal.ZERO;
} else {
//需求量>未到货数量,则一个供应商无法满足,需要安排其他供应商送货
supplierMap.put(key, d_ddwdhsl);
flDemandPlanDto.setD_ddwdhsl(BigDecimal.ZERO);
//重新设置需求量
shQty = laveQty;
}
}
}
for (Map.Entry<String, BigDecimal> supplier : supplierMap.entrySet()) {
String[] split = supplier.getKey().split("#");
BigDecimal allocatedQty = supplier.getValue();
String createFlCode = split[0];
String createSupplierCode = split[1];
String createSupplierName = split[2];
String createFlUom = split[3];
FlxqjhDhjhDetDto createSupplier = new FlxqjhDhjhDetDto();
createSupplier.setFlCode(createFlCode);
createSupplier.setSupplierCode(createSupplierCode);
createSupplier.setSupplierName(createSupplierName);
createSupplier.setFlUom(createFlUom);
createSupplier.setFlDate(flDate);
createSupplier.setAllocatedQty(allocatedQty);
createSupplierLst.add(createSupplier);
}
}
if (WsdCollectionUtils.isNotEmpty(dhjhDetDtos)) {
List<FlxqjhDhjhDetDto> adjustAfterFlxqjhDhjhDetDtos = resetSupplier(createSupplierLst, dhjhDetDtos);
if (WsdCollectionUtils.isNotEmpty(adjustAfterFlxqjhDhjhDetDtos)) {
supplierLst.addAll(adjustAfterFlxqjhDhjhDetDtos);
}else{
supplierLst.addAll(createSupplierLst);
}
}
}
return supplierLst;
}
/**
* 重新调整到货计划
* A 订单未到货数量 200
* B 订单未到货数量 100
* <p>
* 到货量 220 80
* 供应商 A 200 B 80
* B 20
* 小于到货量220的一半,需要调整导最近的送货计划,即下一天
* -------------------------------------------------
* <p>
* C 订单未到货数量 120
* D 订单未到货数量 180
* <p>
* 到货量 100 200
* 供应商 C 100 C 20
* D 180
* 小于到货量200的一半,需要调整导最近的送货计划,即上一天
* <p>
* 调整截至条件,供应商送货计划小于【到货量/2】,查询前后两条查询不到送货计划,则不做调整
* 到货量 51840
* S1 5880
* S2 55220
*
* @param createSupplierLst 需要生成的新供应商送货计划
* @param dhjhDetDtos 需求计划
*/
private List<FlxqjhDhjhDetDto> resetSupplier(List<FlxqjhDhjhDetDto> createSupplierLst, List<FlxqjhDhjhDetDto> dhjhDetDtos) {
List<FlxqjhDhjhDetDto> newCreateSupplierLst = new ArrayList<>();
//每天需求计划(key:辅料编码+日期,value:到货量)
Map<String, BigDecimal> dhjhDetByDaySortCopyMap;
//供应商送货计划(key:辅料编码和供应商编码,value:送货计划)
Map<String, List<FlxqjhDhjhDetDto>> createSupplierByDateAndFlCodeMap;
//需要调整的供应商送货计划(key:日期+辅料编码+供应商编码,value:供应商送货计划)
Map<String, List<FlxqjhDhjhDetDto>> adjustAllocatedQtyMap = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(dhjhDetDtos) && WsdCollectionUtils.isNotEmpty(createSupplierLst)) {
dhjhDetByDaySortCopyMap = dhjhDetDtos.stream().collect(
Collectors.toMap(
item -> WsdDateUtils.dateToStr(item.getFlDate(), "yyyy-MM-dd") + "#" + item.getFlCode(),
FlxqjhDhjhDetDto::getShQty,
WsdBigDecimalUtils::add
)
);
createSupplierByDateAndFlCodeMap = createSupplierLst.stream().collect(
Collectors.groupingBy(item -> item.getFlCode() + "#" + item.getSupplierCode()));
//按照辅料编码和供应商编码找到唯一的供应商数据,从小到大的日期向后调整
for (Map.Entry<String, List<FlxqjhDhjhDetDto>> entry : createSupplierByDateAndFlCodeMap.entrySet()) {
String flCodeAndSupplierCode = entry.getKey();
List<FlxqjhDhjhDetDto> createSupplierDtos = entry.getValue();
//根据日期升序
createSupplierDtos.sort(Comparator.comparing(FlxqjhDhjhDetDto::getFlDate));
//存储前一天需要移动的送货量
Map<String, List<FlxqjhDhjhDetDto>> beforeAllocatedQtyMap = new HashMap<>();
//根据日期汇总信息,需要按日期排序
TreeMap<String, List<FlxqjhDhjhDetDto>> createSupplierDtosMap = createSupplierDtos.stream().collect(
Collectors.groupingBy(
item -> WsdDateUtils.dateToStr(item.getFlDate(), WsdDateUtils.DATE_FORMAT_SHORT),
TreeMap::new,
Collectors.toList()
)
);
for (Map.Entry<String, List<FlxqjhDhjhDetDto>> listEntry : createSupplierDtosMap.entrySet()) {
String curDateStr = listEntry.getKey();
List<FlxqjhDhjhDetDto> listEntryValue = listEntry.getValue();
if (WsdCollectionUtils.isNotEmpty(listEntryValue)) {
//除了送货量需要求和,其他数据都是相同的
FlxqjhDhjhDetDto supplierDto = listEntryValue.get(0);
BigDecimal allocatedQtyTotal = listEntryValue.stream().map(FlxqjhDhjhDetDto::getAllocatedQty).reduce(BigDecimal.ZERO, WsdBigDecimalUtils::add);
Date flDate = supplierDto.getFlDate();
String key = curDateStr + "#" + flCodeAndSupplierCode.split("#")[0];
Date beforeDate = WsdDateUtils.addDays(flDate, -1);
String beforeDateStr = WsdDateUtils.dateToStr(beforeDate, WsdDateUtils.DATE_FORMAT_SHORT);
Date afterDate = WsdDateUtils.addDays(flDate, 1);
String afterDateStr = WsdDateUtils.dateToStr(afterDate, WsdDateUtils.DATE_FORMAT_SHORT);
//当天的应到货量
BigDecimal curXqNum = dhjhDetByDaySortCopyMap.get(key);
BigDecimal halfCurXqNum = WsdBigDecimalUtils.divide(curXqNum, new BigDecimal(2));
//加上前一天移过来的送货量
List<FlxqjhDhjhDetDto> beforeDtos = beforeAllocatedQtyMap.get(curDateStr);
if (WsdCollectionUtils.isNotEmpty(beforeDtos)) {
BigDecimal beforeAllocatedQty = beforeDtos.stream().map(FlxqjhDhjhDetDto::getAllocatedQty).reduce(BigDecimal.ZERO, WsdBigDecimalUtils::add);
if (WsdBigDecimalUtils.greaterThan(beforeAllocatedQty, BigDecimal.ZERO)) {
allocatedQtyTotal = WsdBigDecimalUtils.add(beforeAllocatedQty, allocatedQtyTotal);
}
}
// 送货量小于到货量的一半
// 清空当天的送货计划,记录需要移动的送货计划,存在map集合中
// 判断后一天是否存在送货计划
// 1.存在:记录后一天的送货计划(包含前一天、当天的送货计划),不加上后一天的计划(当循环到后一天时,会包含在前一天的计划中)
// 2.不存在:像调整的集合插入送货计划(包含前一天、当天的送货计划)
// 送货量大于到货量的一半
// 记录今天的送货计划(包含前一天、当天的送货计划)
//查询后一天的数据,存在向后移动,不存在向前移动
List<FlxqjhDhjhDetDto> afterSupplierDtos = createSupplierDtosMap.get(afterDateStr);
List<FlxqjhDhjhDetDto> add = new ArrayList<>();
add.addAll(listEntryValue);
add.addAll(beforeDtos == null ? new ArrayList<>() : beforeDtos);
if (WsdBigDecimalUtils.greaterThan(allocatedQtyTotal, BigDecimal.ZERO) && WsdBigDecimalUtils.lessThan(allocatedQtyTotal, halfCurXqNum)) {
//考虑边界情况,判断后一天是否有送货计划,没有就加到前一天
adjustAllocatedQtyMap.put(curDateStr + "#" + flCodeAndSupplierCode, new ArrayList<>());
if (WsdCollectionUtils.isNotEmpty(afterSupplierDtos)) {
//往后移
adjustAllocatedQtyMap.put(afterDateStr + "#" + flCodeAndSupplierCode, add);
beforeAllocatedQtyMap.put(afterDateStr, add);
} else {
//往前移
adjustAllocatedQtyMap.put(beforeDateStr + "#" + flCodeAndSupplierCode, add);
}
} else {
//如果送货量>到货量的一半,并且存在昨天要向后调整的数据
adjustAllocatedQtyMap.put(curDateStr + "#" + flCodeAndSupplierCode, add);
}
}
}
}
}
for (Map.Entry<String, List<FlxqjhDhjhDetDto>> entry : adjustAllocatedQtyMap.entrySet()) {
String dateStr = entry.getKey().split("#")[0];
List<FlxqjhDhjhDetDto> dtos = entry.getValue();
if (dtos != null && !dtos.isEmpty()) {
for (FlxqjhDhjhDetDto flxqjhDhjhDetDto : dtos) {
flxqjhDhjhDetDto.setFlDate(WsdDateUtils.strToDate(dateStr, WsdDateUtils.DATE_FORMAT_SHORT));
newCreateSupplierLst.add(flxqjhDhjhDetDto);
}
}
}
return newCreateSupplierLst;
}
/**
* 查询当前辅料在当前日期前后两天是否存在送货计划,找到送货量最小的一个,返回它的日期;
*
* @param dhjhDetByDaySortCopyMap 到货量,可通过日期和flcode获取
* @param supplierDtos
* @param beforeDay 前一天
* @param afterDay 后一天
* @param flCode 辅料code
* @param supplierCode 当前供应商
* @return
*/
private Date queryTwoDayExistSupplierShPlan(Map<String, BigDecimal> dhjhDetByDaySortCopyMap, List<FlxqjhDhjhDetDto> supplierDtos, Date beforeDay, Date afterDay, String flCode, String supplierCode) {
Date adjustDate = null;
if (WsdCollectionUtils.isNotEmpty(supplierDtos)) {
String beforeDayStr = WsdDateUtils.dateToStr(beforeDay, WsdDateUtils.DATE_FORMAT_SHORT);
String afterDayStr = WsdDateUtils.dateToStr(afterDay, WsdDateUtils.DATE_FORMAT_SHORT);
List<FlxqjhDhjhDetDto> beforeSupplierLst = supplierDtos.stream()
.filter(item -> beforeDayStr.equals(WsdDateUtils.dateToStr(item.getFlDate(), WsdDateUtils.DATE_FORMAT_SHORT)) && supplierCode.equals(item.getSupplierCode()))
.collect(Collectors.toList());
List<FlxqjhDhjhDetDto> afterSupplierLst = supplierDtos.stream()
.filter(item -> afterDayStr.equals(WsdDateUtils.dateToStr(item.getFlDate(), WsdDateUtils.DATE_FORMAT_SHORT)) && supplierCode.equals(item.getSupplierCode()))
.collect(Collectors.toList());
//前后2天都有,判断哪个的送货量最小
if (WsdCollectionUtils.isNotEmpty(beforeSupplierLst) && WsdCollectionUtils.isNotEmpty(afterSupplierLst)) {
BigDecimal beforeNum = BigDecimal.ZERO;
BigDecimal afterNum = BigDecimal.ZERO;
for (FlxqjhDhjhDetDto dto : beforeSupplierLst) {
beforeNum = WsdBigDecimalUtils.add(dto.getAllocatedQty(), beforeNum);
}
for (FlxqjhDhjhDetDto dto : afterSupplierLst) {
afterNum = WsdBigDecimalUtils.add(dto.getAllocatedQty(), afterNum);
}
if (WsdBigDecimalUtils.greaterThan(beforeNum, afterNum)) {
adjustDate = beforeDay;
} else {
adjustDate = afterDay;
}
} else if (WsdCollectionUtils.isNotEmpty(beforeSupplierLst)) {
//前一天有
BigDecimal beforeNum = BigDecimal.ZERO;
for (FlxqjhDhjhDetDto dto : beforeSupplierLst) {
beforeNum = WsdBigDecimalUtils.add(dto.getAllocatedQty(), beforeNum);
}
adjustDate = beforeDay;
} else if (WsdCollectionUtils.isNotEmpty(afterSupplierLst)) {
//后一天有
BigDecimal afterNum = BigDecimal.ZERO;
for (FlxqjhDhjhDetDto dto : afterSupplierLst) {
afterNum = WsdBigDecimalUtils.add(dto.getAllocatedQty(), afterNum);
}
adjustDate = afterDay;
}
}
return adjustDate;
}
/**
* 判断供应商到货计划是否存在指定牌号的记录
*
* @param detLst
* @param flCode
* @return
*/
private boolean whetherExistSupplier(List<FlxqjhDhjhDetDto> detLst, String flCode) {
boolean flag = false;
if (WsdCollectionUtils.isNotEmpty(detLst)) {
List<FlxqjhDhjhDetDto> collect = detLst.stream().filter(item -> flCode.equals(item.getFlCode())).collect(Collectors.toList());
if (collect != null && collect.size() > 0) {
flag = true;
}
}
return flag;
}
/**
* 查询供应商信息
*/
private void queryFlDemandPlan() {
if (WsdCollectionUtils.isNotEmpty(dhjhDetDtos)) {
Set<String> flCodeLst = dhjhDetDtos.stream().map(item -> item.getFlCode()).collect(Collectors.toSet());
WsdCriteria criteria = new WsdCriteria();
criteria.add(WsdRestrictions.gt("d_ddwdhsl", BigDecimal.ZERO));
criteria.add(WsdRestrictions.in("v_code", flCodeLst.toArray()));
List<FlDemandPlanningEntity> flDemandPlanPos = context.getWsdToolDao().list(FlDemandPlanningEntity.class, criteria);
List<FlDemandPlanningDto> flDemandPlanDtos = (List<FlDemandPlanningDto>) Po2DtoCopyTool.po2dto(flDemandPlanPos);
//根据辅料编号分组
flDemandPlanDtosByVCodeMap = flDemandPlanDtos.stream().collect(Collectors.groupingBy(item -> item.getV_code()));
for (Map.Entry<String, List<FlDemandPlanningDto>> entry : flDemandPlanDtosByVCodeMap.entrySet()) {
List<FlDemandPlanningDto> pos = entry.getValue();
//排序:订单发布时间【i_cgddfbrq】,计划到货时间【i_jhdhsj】
pos.sort(((o1, o2) -> {
if (o1.getI_cgddfbrq().equals(o2.getI_cgddfbrq())) {
return o1.getI_jhdhsj().compareTo(o2.getI_jhdhsj());
}
return o1.getI_cgddfbrq().compareTo(o2.getI_cgddfbrq());
}));
}
}
}
/**
* 设置所有到货量
*/
private void setShQtyAll(FlxqjhDhjhMergeDto mergeDto, BigDecimal uom) {
if (WsdBigDecimalUtils.equals(uom, BigDecimal.ZERO)) {
//全部设置为0
mergeDto.setCommonShQty(BigDecimal.ZERO);
} else {
for (int i = 1; i <= 31 ; i++) {
mergeDto.setCommonShQty(i, WsdBigDecimalUtils.divide(mergeDto.getCommonShQty(i), uom, 4));
}
for (int i = 101; i <= 131 ; i++) {
mergeDto.setCommonShQty(i, WsdBigDecimalUtils.divide(mergeDto.getCommonShQty(i), uom, 4));
}
}
}
private void genError(FlxqjhDhjhServiceResponse response, String msg) {
response.addMessage(new WsdServiceMessage(msg, CoreMessageConstants.MSG_LOGIC_ERROR, FlxqjhDhjhServiceRequest.class.getName()));
}
}生成器上下文对象
/**
* 辅料到货计划的生成器上下文对象
*
* @Author tuaofei
* @Date 2022/9/8 16:15
*/
public class FlDhPlanGeneratorContext {
private static final Logger logger = LoggerFactory.getLogger(FlDhPlanGeneratorContext.class);
private final PlaFlxqjhDao plaFlxqjhDao = WsdBeanFactory.getBeanById("plaFlxqjhDao", PlaFlxqjhDao.class);
private final WsdBizService wsdBizService = WsdBeanFactory.getBeanById("wsdBizService", WsdBizService.class);
private final FlxqjhDhjhDao flxqjhDhjhDao = WsdBeanFactory.getBeanById("flxqjhDhjhDao", FlxqjhDhjhDao.class);
private final FlxqjhShplDao flxqjhShplDao = WsdBeanFactory.getBeanById("flxqjhShplDao", FlxqjhShplDao.class);
private final FlxqjhKcyjDao flxqjhKcyjDao = WsdBeanFactory.getBeanById("flxqjhKcyjDao", FlxqjhKcyjDao.class);
private final FlxqjhKccxDao flxqjhKccxDao = WsdBeanFactory.getBeanById("flxqjhKccxDao", FlxqjhKccxDao.class);
private final FlxqjhDhjhService flxqjhDhjhService = WsdBeanFactory.getBeanById("flxqjhDhjhService", FlxqjhDhjhService.class);
private final ThreadPoolTaskExecutor defaultExecutor = (ThreadPoolTaskExecutor) BeanFactory.lookup("DefaultExecutor");
private final int jobSize = 5;
private final CountDownLatch countDownLatch = new CountDownLatch(jobSize);
private FlxqjhDhjhServiceResponse response;
/**
* 当前日期(忽略天数)
*/
private Date curDate = WsdDateUtils.date2SimpleDate(wsdToolDao.getDBDate());
/**
* 辅料需求计划测算的最后一天日期
*/
private Date monthMaxDate;
/**
* 当前年月
*/
private String curYearMonth;
/**
* 下月日期(忽略天数)
*/
private Date nextDate;
/**
* 下月年月
*/
private String nextYearMonth;
/**
* 需求计划月份和版本
* key:年月,value:版本号
*/
Map<String, String> monthAndVerMap = new HashMap<>();
/**
* 辅料需求计划,每天的需求量
* key:年月日,value:<key:辅料code,value:需求量>
*/
Map<String, Map<String, BigDecimal>> matCodeXqMap = new HashMap<>();
/**
* 辅料需求计划,到截止日的总需求量
* key:辅料code,value:需求量
*/
Map<String, BigDecimal> matCodeXqSumMap = new HashMap<>();
/**
* 辅料需求计划,4天的需求量
* key:年月日,value:<key:辅料code,value:需求量>
*/
Map<String, Map<String, BigDecimal>> matCodeXqFourMap = new HashMap<>();
/**
* 辅料需求计划;不需要进行计算到货计划的辅料,只展示需求量
* key:年月日,value:<key:辅料code,value:需求量>
*/
Map<String, Map<String, BigDecimal>> matCodeXqInDesignationTypeMap = new HashMap<>();
/**
* 当天的初期库存
* key:辅料code,value:库存(高架库+配盘库)
*/
private Map<String, BigDecimal> mapFlkc = new HashMap<>();
/**
* 初期库存副本
*/
Map<String, BigDecimal> mapFlQckc = new HashMap<>();
/**
* 送货批量
* key:辅料code,value:送货批量
*/
private Map<String, BigDecimal> mapFlShpl = flxqjhShplDao.queryNewFlNum();
/**
* 仓库最大作业能力,"Max"
* key:Max,vaue:值
*/
private final BigDecimal maxAbilityPack = BigDecimal.ZERO;
/**
* 辅料托盘转换系数
* key:辅料code,value:系数
*/
private Map<String, BigDecimal> mapPackModulus = new HashMap<>();
/**
* 辅料信息对应的成品信息
* m_Code:辅料code
* m_Name:辅料名称
* maxVer:最大版本号
* d_Code:成品code
* d_Name:成品名称
* d_Type:类型code
* cname : 类型name
*/
private List<FlxqjhKccxDto> flxqjhKccxDtos = flxqjhKccxDao.queryMatCodeAndFlBomRel(new FlxqjhKccxDto());
public FlDhPlanGeneratorContext() {
}
public FlDhPlanGeneratorContext(FlxqjhDhjhServiceResponse response) {
this.response = response;
}
/**
* 初始化上下文
*/
protected void initContext() {
loadDateInfo();
loadFlxqjhVersionAndMonth();
defaultExecutor.execute(() -> {
try {
loadFlXqJh();
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
defaultExecutor.execute(() -> {
try {
loadFlKc();
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
defaultExecutor.execute(() -> {
try {
loadFlMaxAbility();
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
defaultExecutor.execute(() -> {
try {
loadPackConvert();
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
defaultExecutor.execute(() -> {
try {
generatorPurChaseOrder();
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
checkNotInDesignationType();
calFourXqNum();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 拿辅料需求计划的辅料与(送货批量和托盘转换的信息)对比,查询不在指定类型下的辅料是否存在对应信息
*/
private void checkNotInDesignationType() {
FlFilterCodeUtils.getFlFilterCodeNoShow();
Set<String> allCpName = FlFilterCodeUtils.getAllCpName();
Set<String> notInDesignationTypeMatCodeSet = new HashSet<>();
Set<String> notFlShplSet = new HashSet<>();
Set<String> notPackModulusSet = new HashSet<>();
Map<String, String> matCodeAndCpNameMap = new HashMap<>();
if (matCodeXqMap != null && matCodeXqMap.size() > 0) {
if (WsdCollectionUtils.isNotEmpty(flxqjhKccxDtos)) {
//辅料code和成品名称的对应关系;注意:Collectors.toMap不允许key和value为空!,https://blog.csdn.net/weixin_40493969/article/details/108690223
matCodeAndCpNameMap = flxqjhKccxDtos.stream()
.collect(Collectors.toMap(item -> Optional.ofNullable(item.getD_code()).orElse(""),
item -> Optional.ofNullable(item.getCnName()).orElse(""),
(o1, o2) -> o2));
//方法2
/*flxqjhKccxDtos.stream()
.collect(HashMap::new, (m, item) -> m.put(item.getD_code(), item.getCnName()), HashMap::putAll);*/
}
//删除map里面的map中的元素
Set<String> delMatCodeSet = new HashSet<>();
for (Map.Entry<String, Map<String, BigDecimal>> entry : matCodeXqMap.entrySet()) {
Iterator<Map.Entry<String, BigDecimal>> iterator = entry.getValue().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, BigDecimal> next = iterator.next();
String matCode = next.getKey();
if (!allCpName.contains(matCodeAndCpNameMap.get(matCode))) {
BigDecimal shPlNum = mapFlShpl.get(matCode);
BigDecimal packModulusNum = mapPackModulus.get(matCode);
if (WsdBigDecimalUtils.lessOrEquals(shPlNum, BigDecimal.ZERO) && WsdBigDecimalUtils.lessOrEquals(packModulusNum, BigDecimal.ZERO)) {
notInDesignationTypeMatCodeSet.add(matCode);
}else if(WsdBigDecimalUtils.lessOrEquals(shPlNum, BigDecimal.ZERO)){
notFlShplSet.add(matCode);
}else if(WsdBigDecimalUtils.lessOrEquals(packModulusNum, BigDecimal.ZERO)){
notPackModulusSet.add(matCode);
}
} else {
//删除不需要计算的辅料
Map<String, BigDecimal> map = matCodeXqInDesignationTypeMap.get(entry.getKey());
if (map == null) {
map = new HashMap<>();
}
map.put(matCode, next.getValue());
matCodeXqInDesignationTypeMap.put(entry.getKey(), map);
//需要从原需求计划内删除
delMatCodeSet.add(matCode);
iterator.remove();
}
}
}
}
if (WsdCollectionUtils.isNotEmpty(notInDesignationTypeMatCodeSet)) {
StringBuilder builder = new StringBuilder();
builder.append("请维护以下辅料的送货批量和托盘转换信息:<br/>");
if (WsdCollectionUtils.isNotEmpty(notInDesignationTypeMatCodeSet)){
for (String s : notInDesignationTypeMatCodeSet) {
builder.append(s).append("<br/>");
}
}
if (WsdCollectionUtils.isNotEmpty(notFlShplSet)){
builder.append("<br/>请维护以下辅料的送货批量信息:<br/>");
for (String s : notFlShplSet) {
builder.append(s).append("<br/>");
}
}
if (WsdCollectionUtils.isNotEmpty(notPackModulusSet)){
builder.append("<br/>请维护以下辅料的托盘转换信息:<br/>");
for (String s : notPackModulusSet) {
builder.append(s).append("<br/>");
}
}
genError(response, builder.toString());
}
}
/**
* 加载日期信息
*/
private void loadDateInfo() {
logger.info("开始加载日期信息");
curYearMonth = WsdDateUtils.dateToStr(curDate, "yyyy-MM");
nextDate = WsdDateUtils.addMonths(curDate, 1);
nextYearMonth = WsdDateUtils.dateToStr(nextDate, "yyyy-MM");
Calendar c = Calendar.getInstance();
c.setTime(curDate);
//当月最后一天
int curMonthLMaxDayNum = c.getActualMaximum(Calendar.DAY_OF_MONTH);
String startTime = curYearMonth + "-" + curMonthLMaxDayNum;
monthMaxDate = WsdDateUtils.strToDate(startTime, WsdDateUtils.DATE_FORMAT_SHORT);
logger.info("结束加载日期信息{}", toString());
}
/**
* 查询辅料需求计划月份和版本
*/
private void loadFlxqjhVersionAndMonth() {
monthAndVerMap = plaFlxqjhDao.queryFlxqjhVersionAndMonth(curDate);
logger.info("辅料需求计划月份和版本 --> {}", monthAndVerMap.toString());
}
/**
* 查询辅料需求计划
*/
private void loadFlXqJh() {
long l = System.currentTimeMillis();
logger.info("开始生成本月需求计划");
//获取最新的辅料需求计划(主单位)
Map<String, Map<String, BigDecimal>> matCodeXqCurMonthMap = queryFlXqjh(curYearMonth, monthAndVerMap);
matCodeXqMap.putAll(matCodeXqCurMonthMap);
//下个月需求计划版本
String nextVer = monthAndVerMap.get(nextYearMonth);
Calendar c = Calendar.getInstance();
//查询下月的需求计划
if (WsdStringUtils.isNotEmpty(nextVer)) {
logger.info("开始生成下月需求计划");
Map<String, Map<String, BigDecimal>> matCodeXqNextMonthMap = queryFlXqjh(nextYearMonth, monthAndVerMap);
matCodeXqMap.putAll(matCodeXqNextMonthMap);
//查询到下月的辅料需求计划,测算截止日修改为下月的最后一天
c.setTime(nextDate);
int nextMonthLMaxDayNum = c.getActualMaximum(Calendar.DAY_OF_MONTH);
String endTime = nextYearMonth + "-" + nextMonthLMaxDayNum;
monthMaxDate = WsdDateUtils.strToDate(endTime, WsdDateUtils.DATE_FORMAT_SHORT);
}
//计算各个辅料的总需求量(起始日到截止日(如有下月需求计划,则计算到下个月需求计划最后一天))
for (Map.Entry<String, Map<String, BigDecimal>> entry : matCodeXqMap.entrySet()) {
String dateStr = entry.getKey(); //yyyy-MM-d
Date dateTmp = WsdDateUtils.strToDate(dateStr, "yyyy-MM-d");
Map<String, BigDecimal> value = entry.getValue();
if(curDate.getTime() <= dateTmp.getTime() && dateTmp.getTime() <= monthMaxDate.getTime()){
for (Map.Entry<String, BigDecimal> entry2 : value.entrySet()) {
BigDecimal sum = matCodeXqSumMap.get(entry2.getKey());
if (sum == null) {
sum = BigDecimal.ZERO;
}
sum = WsdBigDecimalUtils.add(sum, entry2.getValue());
matCodeXqSumMap.put(entry2.getKey(), sum);
}
}
}
logger.warn("结束生成需求计划,执行时间{}ms", (System.currentTimeMillis() - l));
}
/**
* 统计辅料4天需求量
* 此函数需要在删除指定类型的辅料后统计checkNotInDesignationType
*/
private void calFourXqNum() {
String DATE_FORMAT_SHORT_DAY = "yyyy-MM-d";
if (matCodeXqMap != null && matCodeXqMap.size() > 0) {
//统计所有需求,4天的需求量,重新累加;加3天分类查询map内有没有需求,有就加上
int bzDay = 4;
WsdCriteria wc = new WsdCriteria();
wc.add(WsdRestrictions.eq("codeClassCode", "FLDHJH_KCBZ"));
wc.add(WsdRestrictions.eq("code", "ASS_DAY"));
List<CodeEntity> dayPos = wsdToolDao.list(CodeEntity.class, wc);
if(WsdCollectionUtils.isNotEmpty(dayPos) && WsdStringUtils.isNotBlank(dayPos.get(0).getAttr1())){
bzDay = Integer.parseInt(dayPos.get(0).getAttr1());
}
Date tmpDate = curDate;
while (tmpDate.getTime() <= monthMaxDate.getTime()) {
String dayStr1 = WsdDateUtils.dateToStr(tmpDate, DATE_FORMAT_SHORT_DAY);
Date day1 = WsdDateUtils.strToDate(dayStr1, WsdDateUtils.DATE_FORMAT_SHORT);
List<Map<String, BigDecimal>> dayMapList = new ArrayList<>();
for (int i = 0; i < bzDay; i++) {
Date dayTmp = WsdDateUtils.addDays(day1, i);
String dateStrKeyTmp = WsdDateUtils.dateToStr(dayTmp, DATE_FORMAT_SHORT_DAY);
Map<String, BigDecimal> dayTmpMap = matCodeXqMap.get(dateStrKeyTmp) != null ? matCodeXqMap.get(dateStrKeyTmp) : new HashMap<>();
dayMapList.add(dayTmpMap);
}
Map<String, BigDecimal> map = new HashMap<>();
//4天有需求的辅料
Set<String> day4MatCodeSet = new HashSet<>();
for (Map<String, BigDecimal> itemMap : dayMapList) {
for (Map.Entry<String, BigDecimal> entry : itemMap.entrySet()) {
String flCode = entry.getKey();
day4MatCodeSet.add(flCode);
}
}
for (String flCode : day4MatCodeSet) {
BigDecimal dayXqlNum = BigDecimal.ZERO;
for (Map<String, BigDecimal> entry : dayMapList) {
BigDecimal dayXqlNumTmp = entry.get(flCode);
dayXqlNum = WsdBigDecimalUtils.add(dayXqlNum, dayXqlNumTmp);
}
map.put(flCode, dayXqlNum);
}
matCodeXqFourMap.put(dayStr1, map);
tmpDate = WsdDateUtils.addDays(tmpDate, 1);
}
}
}
/**
* 查询辅料当天的库存
*/
private void loadFlKc() {
logger.info("开始查询{}库存", WsdDateUtils.dateToStr(curDate, WsdDateUtils.DATE_FORMAT_SHORT));
queryFlkc(curDate);
//库存预警,同一类型烟箱下的库存求和,重新覆盖库存
Map<String, Set<String>> notRepeatCpNameAndFlCodeMap = flxqjhDhjhDao.queryCpNameAndFlCodeRel(curYearMonth, monthAndVerMap.get(curYearMonth));
for (Set<String> flCodeSet : notRepeatCpNameAndFlCodeMap.values()) {
BigDecimal sumQty = BigDecimal.ZERO;
for (String flcode : flCodeSet) {
sumQty = WsdBigDecimalUtils.add(sumQty, mapFlkc.get(flcode));
}
for (String flcode : flCodeSet) {
mapFlkc.put(flcode, sumQty);
}
}
mapFlQckc = new HashMap<>(mapFlkc);
logger.info("结束查询库存");
}
/**
* 查询辅料需求计划
*
* @param curMonth 当前月
* @param monthAndVerMap 当月的辅料需求计划月份和版本
* @return
*/
public Map<String, Map<String, BigDecimal>> queryFlXqjh(String curMonth, Map<String, String> monthAndVerMap) {
PlaFlxqjhServiceRequest req = new PlaFlxqjhServiceRequest();
PlaFlxqjhDto queryDto = new PlaFlxqjhDto();
queryDto.setRemark("1");
queryDto.setDept("WZ");
queryDto.setUomType("main");
queryDto.setMonth(curMonth);
queryDto.setVersion(monthAndVerMap.get(curMonth));
queryDto.setDjjh(true);
req.setQueryObject(queryDto);
req.setClient(WsdWhmesSettings.getDefaultBizClient());
req.setMethod("loadData");
PlaFlxqjhServiceResponse resp = (PlaFlxqjhServiceResponse) wsdBizService.service(req);
Map<String, Map<String, Object>> resultMap = resp.getResultMap();
List<Map<String, Object>> matCodeMap = resultMap.values().stream().filter(item -> item.get("parentMatCode") == null).collect(Collectors.toList());
//根据日期汇总,辅料的需求量,(判断前两位是否为数子;转成数字,1-31)
Map<String, Map<String, BigDecimal>> matCodeXqMap = new HashMap<>();
for (Map<String, Object> map : matCodeMap) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (key.matches("[0-9]+")) {
//转换为日期
String monthAndDay = curMonth + "-" + key;
Map<String, BigDecimal> matCodeXqInnerMap = matCodeXqMap.get(monthAndDay);
if (matCodeXqInnerMap == null) {
matCodeXqInnerMap = new HashMap<>();
}
//每天的辅料需求量只有一个
String matCode = (String) map.get("matCode");
BigDecimal qty = (BigDecimal) entry.getValue();
matCodeXqInnerMap.put(matCode, qty);
matCodeXqMap.put(monthAndDay, matCodeXqInnerMap);
}
}
}
return matCodeXqMap;
}
/**
* 查询当日期初库存,即上一天的库存结余
*
* @param workDate
* @return
*/
private void queryFlkc(Date workDate) {
Date yesterday = WsdDateUtils.addDays(workDate, -1);
FlxqjhKccxDto dto = new FlxqjhKccxDto();
dto.setIV_BUDATE(WsdDateUtils.dateToStr(yesterday, WsdDateUtils.DATE_FORMAT_SHORT));
FlxqjhKccxServiceRequest request = new FlxqjhKccxServiceRequest();
request.setClient(WsdServiceUtils.getDefaultClient());
request.setMethod("loadMainReport");
request.setQueryObject(dto);
FlxqjhKccxServiceResponse response = WsdCommonFun.commonExcuteXfire(request);
List<FlxqjhKccxDto> kcDtos = response.getResponseObjects();
//key:日期,value:牌号
Map<String,String> kcIsZeroMap = new HashMap<>();
Set<String> kcIsZeroSet = new HashSet<>();
//当天无库存的牌号
Map<String, BigDecimal> mapEmptyFlkc = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(kcDtos)) {
for (FlxqjhKccxDto kcDto : kcDtos) {
String flCode = kcDto.getMATNR();
BigDecimal gjkInv = kcDto.getGjk();
BigDecimal pskInv = kcDto.getPpk();
BigDecimal sumInv = WsdBigDecimalUtils.add(gjkInv, pskInv);
if (WsdBigDecimalUtils.equals(sumInv,BigDecimal.ZERO)){
kcIsZeroSet.add(flCode);
mapEmptyFlkc.put(flCode, sumInv);
}else{
mapFlkc.put(flCode, sumInv);
}
}
//某个材料高架库和配盘库的库存为0,向前查询该辅料的库存;单独查询高架库和配盘库的库存,找到库存不为0的数据,再查询库存
if(WsdCollectionUtils.isNotEmpty(kcIsZeroSet)){
FlxqjhKccxDto queryDto = new FlxqjhKccxDto();
queryDto.setMatCodeList(new ArrayList<>(kcIsZeroSet));
queryDto.setStockType("01");
queryDto.setIV_BUDATE(WsdDateUtils.dateToStr(yesterday,WsdDateUtils.DATE_FORMAT_SHORT));
List<FlxqjhKccxDto> gjkList = flxqjhKccxDao.queryMatCodeAtTheEarliestKcDate(queryDto);
queryDto.setStockType("02");
List<FlxqjhKccxDto> ppkList = flxqjhKccxDao.queryMatCodeAtTheEarliestKcDate(queryDto);
Map<String, List<FlxqjhKccxDto>> gjkMap = new HashMap<>();
Map<String, List<FlxqjhKccxDto>> ppkMap = new HashMap<>();
if (WsdCollectionUtils.isNotEmpty(gjkList)){
gjkMap = gjkList.stream().collect(Collectors.groupingBy(FlxqjhKccxDto::getMATNR));
}
if (WsdCollectionUtils.isNotEmpty(ppkList)){
ppkMap = ppkList.stream().collect(Collectors.groupingBy(FlxqjhKccxDto::getMATNR));
}
List<String> emptyMatQuerySet = new ArrayList<>();
for (Map.Entry<String, BigDecimal> entry : mapEmptyFlkc.entrySet()) {
String flCode = entry.getKey();
List<FlxqjhKccxDto> gjk = gjkMap.get(flCode);
List<FlxqjhKccxDto> ppk = ppkMap.get(flCode);
if (WsdCollectionUtils.isNotEmpty(gjk)){
gjk.sort(Comparator.comparing(o -> WsdDateUtils.strToDate(o.getIV_BUDATE(), WsdDateUtils.DATE_FORMAT_SHORT)));
}
if (WsdCollectionUtils.isNotEmpty(ppk)){
ppk.sort(Comparator.comparing(o -> WsdDateUtils.strToDate(o.getIV_BUDATE(), WsdDateUtils.DATE_FORMAT_SHORT)));
}
if (WsdCollectionUtils.isNotEmpty(gjk) && WsdCollectionUtils.isNotEmpty(ppk)){
FlxqjhKccxDto gjkDto = gjk.get(gjk.size() - 1);
FlxqjhKccxDto ppkDto = ppk.get(ppk.size() - 1);
String gjkDateStr = gjkDto.getIV_BUDATE();
String ppkDateStr = ppkDto.getIV_BUDATE();
Date gjkDate = WsdDateUtils.strToDate(gjkDateStr, WsdDateUtils.DATE_FORMAT_SHORT);
Date ppkDate = WsdDateUtils.strToDate(ppkDateStr, WsdDateUtils.DATE_FORMAT_SHORT);
if (gjkDate.after(ppkDate)){
emptyMatQuerySet.add(flCode + "@@" + gjkDateStr);
}else if(gjkDate.before(ppkDate)){
emptyMatQuerySet.add(flCode + "@@" + ppkDateStr);
}else{
//随便选个日期都一样
emptyMatQuerySet.add(flCode + "@@" + gjkDateStr);
}
}
if (WsdCollectionUtils.isNotEmpty(gjk) && WsdCollectionUtils.isEmpty(ppk)){
FlxqjhKccxDto gjkDto = gjk.get(gjk.size() - 1);
String gjkDateStr = gjkDto.getIV_BUDATE();
emptyMatQuerySet.add(flCode + "@@" + gjkDateStr);
}
if (WsdCollectionUtils.isEmpty(gjk) && WsdCollectionUtils.isNotEmpty(ppk)){
FlxqjhKccxDto ppkDto = ppk.get(ppk.size() - 1);
String ppkDateStr = ppkDto.getIV_BUDATE();
emptyMatQuerySet.add(flCode + "@@" + ppkDateStr);
}
}
if (WsdCollectionUtils.isNotEmpty(emptyMatQuerySet)){
queryDto = new FlxqjhKccxDto();
queryDto.setMatCodeList(new ArrayList<>(emptyMatQuerySet));
List<FlxqjhKccxDto> kc = flxqjhKccxDao.queryMatCodeKcByDate(queryDto);
if (WsdCollectionUtils.isNotEmpty(kc)){
Map<String, FlxqjhKccxDto> kcMap = kc.stream().collect(Collectors.toMap(FlxqjhKccxDto::getMATNR, item -> item));
for (Map.Entry<String, BigDecimal> entry : mapEmptyFlkc.entrySet()) {
String flCode = entry.getKey();
FlxqjhKccxDto kccxDto = kcMap.get(flCode);
if (kccxDto != null){
BigDecimal kcInv = kccxDto.getZQMKC();
mapFlkc.put(flCode, kcInv);
}
}
}
}
}
}
}
/**
* 查询仓库最大作业能力
*/
private void loadFlMaxAbility() {
Map<String, BigDecimal> mapFlMaxAbility = new HashMap<>();
List<CodeEntity> codePos = wsdToolDao.listByProperty(CodeEntity.class, "codeClass.classCode", "FLXQJH_CKZYNL");
List<CodeDto> codeDtos = (List<CodeDto>) Po2DtoCopyTool.po2dto(codePos);
for (CodeDto dto : codeDtos) {
String code = dto.getCode();
String cnName = dto.getCnName();
mapFlMaxAbility.put(code, new BigDecimal(cnName).setScale(4, BigDecimal.ROUND_HALF_UP));
}
//单日仓库最大作业能力
BigDecimal maxAbilityPack = mapFlMaxAbility.get("Max");
if (maxAbilityPack == null && WsdBigDecimalUtils.lessOrEquals(maxAbilityPack, BigDecimal.ZERO)) {
genError(response, "单日仓库最大作业能力没有设置或小于等于0,数据异常请检查!");
return;
}
logger.info("单日仓库最大作业能力:{}", mapFlMaxAbility);
}
private void genError(FlxqjhDhjhServiceResponse response, String msg) {
response.addMessage(new WsdServiceMessage(msg, CoreMessageConstants.MSG_LOGIC_ERROR, FlxqjhDhjhServiceRequest.class.getName()));
}
/**
* 获取辅料的托盘转换系数
*/
private void loadPackConvert() {
logger.info("开始查询辅料托盘转换系数");
List<FlShUnitPackConversionEntity> conversionPos = wsdToolDao.list(FlShUnitPackConversionEntity.class, new WsdCriteria().add(WsdRestrictions.isNotNull("orgCode")).add(WsdRestrictions.isNotNull("orgSign")));
List<FlShUnitPackConversionDto> list = (List<FlShUnitPackConversionDto>) Po2DtoCopyTool.po2dto(conversionPos);
if (WsdCollectionUtils.isNotEmpty(list)) {
mapPackModulus = list.stream()
.collect(Collectors.toMap(item -> item.getFlCode(), item -> item.getZhQty() == null ? BigDecimal.ZERO : item.getZhQty()));
}
logger.info("结束查询辅料托盘转换系数");
}
/**
* 触发【采购执行跟踪报表】生成
*/
private void generatorPurChaseOrder() {
logger.info("开始生成采购执行跟踪报表");
FlDemandPlanningServiceRequest flDemandPlanningServiceRequest = new FlDemandPlanningServiceRequest();
FlDemandPlanningDto planningDto = new FlDemandPlanningDto();
flDemandPlanningServiceRequest.setQueryObject(planningDto);
flDemandPlanningServiceRequest.setClient(WsdWhmesSettings.getDefaultBizClient());
flDemandPlanningServiceRequest.setMethod("saveData");
WsdServiceResponse wsdServiceResponse = WsdCommonFun.commonExcuteXfire(flDemandPlanningServiceRequest);
boolean result = wsdServiceResponse.getResult();
if (!result) {
logger.info("生成采购执行跟踪报表失败!{}", wsdServiceResponse.getMessages());
}
logger.info("生成采购执行跟踪报表完成!");
}
public FlxqjhDhjhServiceResponse getResponse() {
return response;
}
public Date getCurDate() {
return curDate;
}
public Date getMonthMaxDate() {
return monthMaxDate;
}
public String getCurYearMonth() {
return curYearMonth;
}
public Date getNextDate() {
return nextDate;
}
public Map<String, Map<String, BigDecimal>> getMatCodeXqMap() {
return matCodeXqMap;
}
public Map<String, BigDecimal> getMatCodeXqSumMap() {
return matCodeXqSumMap;
}
public Map<String, BigDecimal> getMapFlkc() {
return mapFlkc;
}
public Map<String, BigDecimal> getMapFlQckc() {
return mapFlQckc;
}
public Map<String, BigDecimal> getMapFlShpl() {
return mapFlShpl;
}
public BigDecimal getMaxAbilityPack() {
return maxAbilityPack;
}
public Map<String, BigDecimal> getMapPackModulus() {
return mapPackModulus;
}
public FlxqjhDhjhDao getFlxqjhDhjhDao() {
return flxqjhDhjhDao;
}
public FlxqjhKcyjDao getFlxqjhKcyjDao() {
return flxqjhKcyjDao;
}
public WsdToolDao getWsdToolDao() {
return wsdToolDao;
}
public WsdBizService getWsdBizService() {
return wsdBizService;
}
public CountDownLatch getCountDownLatch() {
return countDownLatch;
}
public List<FlxqjhKccxDto> getFlxqjhKccxDtos() {
return flxqjhKccxDtos;
}
public FlxqjhKccxDao getFlxqjhKccxDao() {
return flxqjhKccxDao;
}
public FlxqjhDhjhService getFlxqjhDhjhService() {
return flxqjhDhjhService;
}
public static Logger getLogger() {
return logger;
}
public Map<String, Map<String, BigDecimal>> getMatCodeXqFourMap() {
return matCodeXqFourMap;
}
public Map<String, Map<String, BigDecimal>> getMatCodeXqInDesignationTypeMap() {
return matCodeXqInDesignationTypeMap;
}
@Override
public String toString() {
return "FlDhPlanGeneratorContext{" +
"curDate=" + curDate +
", 辅料需求计划测算的最后一天日期=" + monthMaxDate +
", curYearMonth='" + curYearMonth + '\'' +
", nextDate=" + nextDate +
", nextYearMonth='" + nextYearMonth + '\'' +
", 需求计划月份和版本=" + monthAndVerMap +
", 仓库最大作业能力=" + maxAbilityPack +
", 辅料托盘转换系数=" + mapPackModulus +
'}';
}
}构建
FlDhPlanGenerator generator = new FlDhPlanGenerator();
generator.setClient(request, response);
generator.generator();适配器模式
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
void specificRequest() {
System.out.println("Called specificRequest from Adaptee");
}
}
// 适配器类
class Adapter implements Target {
private final Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端
public class Main {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
adapter.request(); // Output: Called specificRequest from Adaptee
}
}装饰器模式

// 组件接口
interface Component {
void operation();
}
// 具体组件
class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
// 装饰器抽象类
abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorA added behavior");
}
}
// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorB added behavior");
}
}
// 客户端
public class Main {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation();
// Output:
// ConcreteComponent operation
// ConcreteDecoratorA added behavior
// ConcreteDecoratorB added behavior
}
}模板模式

// 抽象类
abstract class DataProcessor {
// 模板方法
public final void process() {
readData();
processData();
writeData();
}
protected abstract void readData(); // 读取数据
protected abstract void processData(); // 处理数据
protected void writeData() { // 写入数据
System.out.println("Writing data to output.");
}
}
// 具体实现类A
class CSVDataProcessor extends DataProcessor {
@Override
protected void readData() {
System.out.println("Reading data from CSV file.");
}
@Override
protected void processData() {
System.out.println("Processing CSV data.");
}
}
// 具体实现类B
class JSONDataProcessor extends DataProcessor {
@Override
protected void readData() {
System.out.println("Reading data from JSON file.");
}
@Override
protected void processData() {
System.out.println("Processing JSON data.");
}
}
// 客户端
public class Main {
public static void main(String[] args) {
DataProcessor csvProcessor = new CSVDataProcessor();
csvProcessor.process();
DataProcessor jsonProcessor = new JSONDataProcessor();
jsonProcessor.process();
}
}责任链模式

// 处理器接口
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(String request);
}
// 具体处理器A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
if ("A".equals(request)) {
System.out.println("ConcreteHandlerA handled request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("No handler for request: " + request);
}
}
}
// 具体处理器B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
if ("B".equals(request)) {
System.out.println("ConcreteHandlerB handled request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("No handler for request: " + request);
}
}
}
// 客户端
public class Main {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
handlerA.handleRequest("A"); // Output: ConcreteHandlerA handled request: A
handlerA.handleRequest("B"); // Output: ConcreteHandlerB handled request: B
handlerA.handleRequest("C"); // Output: No handler for request: C
}
}贡献者
更新日志
fb8bc-更新为vuepress于