春风项目四线(合箱线、总装线)
wujian
2024-03-16 059083082a6d284821b70eb7bb6805763014c402
add PLC连接通信
add 扫码数据推送到前端
已修改12个文件
已添加4个文件
741 ■■■■■ 文件已修改
jcdm-admin/src/main/java/com/jcdm/MesApplication.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-framework/src/main/java/com/jcdm/framework/config/SecurityConfig.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/pom.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/controller/DaPassingStationCollectionController.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/mapper/DaPassingStationCollectionMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/service/IDaPassingStationCollectionService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/service/impl/DaPassingStationCollectionServiceImpl.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/plcserver/CustomRunner.java 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/plcserver/conf/OPCElement.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/plcserver/sub/OPCUaSubscription.java 136 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/websocket/SystemController.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/websocket/WebSocketConfig.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/java/com/jcdm/main/websocket/WebSocketServer.java 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-main/src/main/resources/mapper/da/passingStationCollection/DaPassingStationCollectionMapper.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-ui/src/utils/WebsocketTool.js 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-ui/src/views/main/kb/engineCheck/index.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jcdm-admin/src/main/java/com/jcdm/MesApplication.java
@@ -3,6 +3,8 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
 * å¯åŠ¨ç¨‹åº
@@ -11,6 +13,8 @@
 */
@EnableScheduling //定时任务
@ServletComponentScan //webSocket
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MesApplication
{
jcdm-framework/src/main/java/com/jcdm/framework/config/SecurityConfig.java
@@ -115,6 +115,7 @@
                // é™æ€èµ„源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                .antMatchers("/websocket/**").anonymous()
                // é™¤ä¸Šé¢å¤–的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
jcdm-main/pom.xml
@@ -80,6 +80,17 @@
            <artifactId>milo-spring-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.22</version>
        </dependency>
    </dependencies>
</project>
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/controller/DaPassingStationCollectionController.java
@@ -1,30 +1,24 @@
package com.jcdm.main.da.passingStationCollection.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.jcdm.common.core.domain.R;
import com.jcdm.common.utils.DateUtils;
import com.jcdm.main.bs.orderScheduling.domain.BsOrderScheduling;
import com.jcdm.main.da.passingStationCollection.domain.DaPassingStationCollection;
import com.jcdm.main.da.passingStationCollection.service.IDaPassingStationCollectionService;
import com.jcdm.main.da.passingStationCollection.vo.DaPassingStationVO;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jcdm.common.annotation.Log;
import com.jcdm.common.core.controller.BaseController;
import com.jcdm.common.core.domain.AjaxResult;
import com.jcdm.common.enums.BusinessType;
import com.jcdm.common.utils.poi.ExcelUtil;
import com.jcdm.common.core.domain.R;
import com.jcdm.common.core.page.TableDataInfo;
import com.jcdm.common.enums.BusinessType;
import com.jcdm.common.utils.DateUtils;
import com.jcdm.common.utils.poi.ExcelUtil;
import com.jcdm.main.da.passingStationCollection.domain.DaPassingStationCollection;
import com.jcdm.main.da.passingStationCollection.service.IDaPassingStationCollectionService;
import com.jcdm.main.da.passingStationCollection.service.impl.DaPassingStationCollectionServiceImpl;
import com.jcdm.main.da.passingStationCollection.vo.DaPassingStationVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * äº§å“è¿‡ç«™é‡‡é›†Controller
@@ -38,6 +32,9 @@
{
    @Autowired
    private IDaPassingStationCollectionService daPassingStationCollectionService;
    @Resource
    private DaPassingStationCollectionServiceImpl passingStationCollectionServiceImpl;
    /**
     * æŸ¥è¯¢äº§å“è¿‡ç«™é‡‡é›†åˆ—表
@@ -147,4 +144,14 @@
    {
        return toAjax(daPassingStationCollectionService.deleteDaPassingStationCollectionByIds(ids));
    }
    //设置定时十秒一次
//    @Scheduled(cron = "0/10 * * * * ?")
//    @PostMapping("/send")
//    public String sendMessage(String message) throws Exception {
//        if (StringUtils.isEmpty(message)){
//            message = "TESTMESSAGE";
//        }
//        return passingStationCollectionServiceImpl.sendMessage(message);
//    }
}
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/mapper/DaPassingStationCollectionMapper.java
@@ -4,6 +4,7 @@
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * äº§å“è¿‡ç«™é‡‡é›†Mapper接口
@@ -62,4 +63,6 @@
     * @return ç»“æžœ
     */
    public int deleteDaPassingStationCollectionByIds(Long[] ids);
    public String SelectSN(Map<String, Object> map);
}
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/service/IDaPassingStationCollectionService.java
@@ -79,5 +79,5 @@
     * @param SNcode äº§å“SN
     * @return ç»“æžœ
     */
    public String SelectSN(String SNcode);
    public String SelectSN(String SNcode,String node);
}
jcdm-main/src/main/java/com/jcdm/main/da/passingStationCollection/service/impl/DaPassingStationCollectionServiceImpl.java
@@ -1,15 +1,7 @@
package com.jcdm.main.da.passingStationCollection.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil;
import com.jcdm.common.constant.Constants;
import com.alibaba.fastjson2.JSONObject;
import com.jcdm.common.utils.DateUtils;
import com.jcdm.common.utils.StringUtils;
import com.jcdm.main.bs.orderScheduling.domain.BsOrderScheduling;
@@ -21,9 +13,17 @@
import com.jcdm.main.da.passingStationCollection.vo.DaPassingStationVO;
import com.jcdm.main.rm.repairRecord.domain.RmRepairRecord;
import com.jcdm.main.rm.repairRecord.mapper.RmRepairRecordMapper;
import com.jcdm.main.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
 * äº§å“è¿‡ç«™é‡‡é›†Service业务层处理
@@ -223,19 +223,32 @@
        }
    }
    @Override
    public String SelectSN(String SNcode){
        return "1";
    public String SelectSN(String SNcode,String node) {
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("SNcode",SNcode);
            params.put("node",node);
            params.put("Success","");
            daPassingStationCollectionMapper.SelectSN(params);
            return (String)params.get("Success");
        } catch (Exception e) {
            return "数据查询失败!";
        }
    }
//        --订单排产
//        select * from bs_order_scheduling where engine_no='2V91Y-F RA182118'
//
//        --工艺路线子表信息
//        select * from bs_technology_route_child_info where route_code='H_191S'
//
//        --返修数据
//        select * from rm_repair_record where box_code='2V91Y-F RA182118'
//
//        --过站采集
//        select * from da_passing_station_collection --where sfc_code='2V91Y-F RA182118'
    public String sendMessage(String message) throws Exception{
        Map<String,Object> map = new HashMap<>();
        // èŽ·å–当前日期和时间
        LocalDateTime nowDateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(dateTimeFormatter.format(nowDateTime));
        map.put("server_time",dateTimeFormatter.format(nowDateTime));
        map.put("server_code","200");
        map.put("server_message",message);
        JSONObject jsonObject =  new JSONObject(map);
        WebSocketServer.sendAllMessage(jsonObject.toString());
        return jsonObject.toString();
    }
}
jcdm-main/src/main/java/com/jcdm/main/plcserver/CustomRunner.java
@@ -2,8 +2,10 @@
import com.jcdm.main.da.collectionParamConf.service.IDaCollectionParamConfService;
import com.jcdm.main.da.opcuaconfig.domain.DaOpcuaConfig;
import com.jcdm.main.da.opcuaconfig.service.IDaOpcuaConfigService;
import com.jcdm.main.da.paramCollection.service.IDaParamCollectionService;
import com.jcdm.main.plcserver.conf.OPCElement;
import com.jcdm.main.da.passingStationCollection.service.impl.DaPassingStationCollectionServiceImpl;
import com.jcdm.main.plcserver.sub.OPCUaSubscription;
import com.kangaroohy.milo.service.MiloService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -11,8 +13,9 @@
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class CustomRunner implements ApplicationRunner {
@@ -26,28 +29,46 @@
    @Autowired
    public IDaParamCollectionService daParamCollectionService;
    @Resource
    private DaPassingStationCollectionServiceImpl passingStationCollectionServiceImpl;
    @Resource
    private IDaOpcuaConfigService iDaOpcuaConfigService;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<DaOpcuaConfig> lists = getSubList();
        List<String> collect = lists.stream().map(DaOpcuaConfig::getNode).collect(Collectors.toList());
        OPCUaSubscription opcUaSubscription = new OPCUaSubscription(
                miloService,
                collectionParamConfService,
                daParamCollectionService);
                daParamCollectionService
        ,passingStationCollectionServiceImpl,
                lists);
        List<String> lists = getSubList();
        miloService.subscriptionFromOpcUa(lists,opcUaSubscription);
        miloService.subscriptionFromOpcUa(collect,opcUaSubscription);
    }
    /**
     * è®¢é˜…内容
     */
    public List<String> getSubList(){
        List<String> lists = new ArrayList<>();
        lists.add(OPCElement.OP010_SaveRequest);//请求保存
        lists.add(OPCElement.OP010_CodeCheck);//请求检索条码
        lists.add(OPCElement.OP020_SaveRequest);//请求保存
        return lists;
    public List<DaOpcuaConfig> getSubList(){
        DaOpcuaConfig config = new DaOpcuaConfig();
        List<DaOpcuaConfig> list = iDaOpcuaConfigService.selectDaOpcuaConfigList(config);
//        List<String> lists = new ArrayList<>();
//        if (CollUtil.isNotEmpty(list)){
//            lists = list.stream().map(DaOpcuaConfig::getNode).distinct().collect(Collectors.toList());
//        }
//        List<String> lists = new ArrayList<>();
////        lists.add(OPCElement.OP010_SaveRequest);//请求保存
////        lists.add(OPCElement.OP010_CodeCheck);//请求检索条码
////        lists.add(OPCElement.OP020_SaveRequest);//请求保存
//        lists.add(OPCElement.OP120_SaveRequestLast);//请求保存
//        lists.add(OPCElement.OP120_ZZ_CODE_CHECK);//请求保存
        return list;
    }
}
jcdm-main/src/main/java/com/jcdm/main/plcserver/conf/OPCElement.java
@@ -20,9 +20,17 @@
     * OP100
     */
    private static final String OP020_ITEM = "OP.OP100.";//
    private static final String OP120_ITEM_HX = "CFL4HX.OP120.";//
    private static final String OP120_ITEM_ZZ = "CFL4ZZ.OP120.";//
    public static final String OP020_SaveRequest = OP020_ITEM + "SaveRequest";//请求保存
    public static final String OP120_SaveRequestLast = OP120_ITEM_HX + "SaveRequestLast";//请求保存
    public static final String OP020_MesSaveFeed = OP020_ITEM + "MesSaveFeed";//Mes保存完成
    public static final String OP120_ZZ_CODE_CHECK = OP120_ITEM_ZZ + "CodeCheck";//请求保存
    public static final String SN_CHECK = "SNRetrieval";
    public static final String SAVE_DATA = "saveData";
}
jcdm-main/src/main/java/com/jcdm/main/plcserver/sub/OPCUaSubscription.java
@@ -3,20 +3,27 @@
import com.jcdm.main.da.collectionParamConf.domain.DaCollectionParamConf;
import com.jcdm.main.da.collectionParamConf.service.IDaCollectionParamConfService;
import com.jcdm.main.da.opcuaconfig.domain.DaOpcuaConfig;
import com.jcdm.main.da.paramCollection.domain.DaParamCollection;
import com.jcdm.main.da.paramCollection.service.IDaParamCollectionService;
import com.jcdm.main.da.passingStationCollection.domain.DaPassingStationCollection;
import com.jcdm.main.da.passingStationCollection.service.impl.DaPassingStationCollectionServiceImpl;
import com.jcdm.main.plcserver.conf.OPCElement;
import com.kangaroohy.milo.model.ReadWriteEntity;
import com.kangaroohy.milo.runner.subscription.SubscriptionCallback;
import com.kangaroohy.milo.service.MiloService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.text.Format;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Component
public class OPCUaSubscription implements SubscriptionCallback {
@@ -26,12 +33,23 @@
    public IDaParamCollectionService daParamCollectionService;
    public DaPassingStationCollectionServiceImpl passingStationCollectionServiceImpl;
    public List<DaOpcuaConfig> lists;
    public static final HashMap<String,Integer> map = new HashMap<>();
    public OPCUaSubscription(MiloService miloService,
                             IDaCollectionParamConfService collectionParamConfService,
                             IDaParamCollectionService daParamCollectionService) {
                             IDaParamCollectionService daParamCollectionService,
                             DaPassingStationCollectionServiceImpl passingStationCollectionServiceImpl,
                             List<DaOpcuaConfig> lists) {
        OPCUaSubscription.miloService = miloService;
        this.collectionParamConfService = collectionParamConfService;
        this.daParamCollectionService = daParamCollectionService;
        this.passingStationCollectionServiceImpl = passingStationCollectionServiceImpl;
        this.lists = lists;
    }
@@ -41,20 +59,82 @@
        String ecpStr = "";//异常记录标记
        try {
            if(null != value) {
                //1、检索SN号
                //2、过站参数采集
                //3、扫码枪数据回传
                List<String> collect1 = lists.stream().filter(x -> OPCElement.SN_CHECK.equals(x.getrFunction()))
                        .map(DaOpcuaConfig::getNode).collect(Collectors.toList());
                List<String> collect2 = lists.stream().filter(x -> OPCElement.SAVE_DATA.equals(x.getrFunction()))
                        .map(DaOpcuaConfig::getNode).collect(Collectors.toList());
                if (collect1.contains(identifier)){
                    //sn
                    this.SNRetrieval(identifier,value.toString());
                    if (identifier.equals(OPCElement.OP120_ZZ_CODE_CHECK) && "1".equals(value.toString())){
                        //总装上线扫码传输数据
                        log.info("-------监听到,{}的扫码枪扫码的CODE_CHECK的信号",identifier);
                        Integer i = map.getOrDefault(identifier + "的扫码枪扫码的CODE_CHECK的信号",0);
                        if (0==i){
                            map.put(identifier + "的扫码枪扫码的CODE_CHECK的信号",i+1);
                        }
                        String[] parts = OPCElement.OP120_ZZ_CODE_CHECK.split("[.]");
                        Object SNCodeObject = miloService.readFromOpcUa(parts[0] + "." + parts[1] + ".Code1").getValue();
                        if (null != SNCodeObject){
                            String SNCode = SNCodeObject.toString();
                            passingStationCollectionServiceImpl.sendMessage(SNCode);
                        }
                    }
                }
                else if (collect2.contains(identifier)){
                    //save
                    this.SaveData(identifier);
                    //返回plc保存成功
                    String[] parts = identifier.split("[.]");
                    if (parts.length==3){
                        if ("SaveRequest".equals(parts[2])){
                            ReadWriteEntity entity = new ReadWriteEntity(parts[0] + "." + parts[1] + ".SaveFeed", 1);
                            log.info("-------监听到,{}的saveRequest的信号",identifier);
                            Integer i = map.getOrDefault(identifier + "的saveRequest的信号",0);
                            if (0==i){
                                map.put(identifier + "的saveRequest的信号",i+1);
                            }
//                            miloService.writeToOpcByte(entity);
                        }else if ("SaveRequestLast".equals(parts[2])){
                            ReadWriteEntity entity = new ReadWriteEntity(parts[0] + "." + parts[1] + ".SaveFeedLast", 1);
                            log.info("-------监听到,{}的SaveRequestLast的信号",identifier);
                            Integer i = map.getOrDefault(identifier + "的SaveRequestLast的信号",0);
                            if (0==i){
                                map.put(identifier + "的SaveRequestLast的信号",i+1);
                            }
//                            miloService.writeToOpcByte(entity);
                        }
                    }
                }
                //OP010保存请求
                if (identifier.equals(OPCElement.OP010_SaveRequest) && "1".equals(value.toString())) {
                    //1、更新工单数据
                    //2、保存过站采集数据
                    //3、保存参数采集数据
                    ReadWriteEntity entity = new ReadWriteEntity(OPCElement.OP010_MesSaveFeed, 1);
                    miloService.writeToOpcByte(entity);
                }
                //OP010请求检索条码
                else if (identifier.equals(OPCElement.OP010_CodeCheck) && "1".equals(value.toString())) {
                    ReadWriteEntity entity = new ReadWriteEntity(OPCElement.OP010_MesCodeCheckFeed, 1);
                    miloService.writeToOpcByte(entity);
                }
//                if (identifier.equals(OPCElement.OP120_SaveRequestLast) && "1".equals(value.toString())) {
//                    this.SaveData(OPCElement.OP120_SaveRequestLast);
//                    //1、更新工单数据
//                    //2、保存过站采集数据
//                    //3、保存参数采集数据
//                    ReadWriteEntity entity = new ReadWriteEntity(OPCElement.OP010_MesSaveFeed, 1);
//                    miloService.writeToOpcByte(entity);
//                }
//                else if (identifier.equals(OPCElement.OP120_ZZ_CODE_CHECK) && "1".equals(value.toString())){
//                    //总装上线扫码传输数据
//                    String[] parts = OPCElement.OP120_ZZ_CODE_CHECK.split("[.]");
//                    Object SNCodeObject = miloService.readFromOpcUa(parts[0] + "." + parts[1] + ".Code1").getValue();
//                    if (null != SNCodeObject){
//                        String SNCode = SNCodeObject.toString();
//                        passingStationCollectionServiceImpl.sendMessage(SNCode);
//                    }
//                }
//                //OP010请求检索条码
//                else if (identifier.equals(OPCElement.OP010_CodeCheck) && "1".equals(value.toString())) {
//                    ReadWriteEntity entity = new ReadWriteEntity(OPCElement.OP010_MesCodeCheckFeed, 1);
//                    miloService.writeToOpcByte(entity);
//                }
            }
@@ -69,8 +149,34 @@
        }
    }
    public void SNRetrieval(String Node, String value) throws Exception {
        String[] parts = Node.split("[.]");
        if(value.equals("1")) {
            //SN号检索
            Object SNCodeObject = miloService.readFromOpcUa(parts[0] + "." + parts[1] + ".Code").getValue();
            if(null != SNCodeObject) {
                String SNCode=SNCodeObject.toString();
                String a=passingStationCollectionServiceImpl.SelectSN(SNCode,parts[1]);
                // 1:OK可生产 2:NG不可生产 3:NG可返工 4:PC检索失败(无记录)5:PC检索失败(软件)
                ReadWriteEntity entity = new ReadWriteEntity(parts[0]+"."+parts[1]+".CodeCheckFeed", a);
                log.info("-------监听到,{}的CodeCheck的信号",Node);
                Integer i = map.getOrDefault(Node + "的CodeCheck的信号",0);
                if (0==i){
                    map.put(Node + "的CodeCheck的信号",i+1);
                }
//                miloService.writeToOpcByte(entity);
                DaPassingStationCollection PassingStationCollection=new DaPassingStationCollection();
                PassingStationCollection.setSfcCode(SNCode);
                PassingStationCollection.setLocationCode(parts[1]);
                PassingStationCollection.setInboundTime(new Date());
                passingStationCollectionServiceImpl.insertDaPassingStationCollection(PassingStationCollection);
            }
        }
    }
    public void SaveData(String Node) throws Exception {
        /*String[] parts = Node.split("[.]");
        String[] parts = Node.split("[.]");
        Object SNCodeObject = miloService.readFromOpcUa(parts[0] + "." + parts[1] + ".Code1").getValue();
        if(null != SNCodeObject)
@@ -108,6 +214,6 @@
                }
                daParamCollectionService.saveBeachDaParamCollection(daParamCollectionlist);
            }
        }*/
        }
    }
}
jcdm-main/src/main/java/com/jcdm/main/websocket/SystemController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package com.jcdm.main.websocket;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {
    //页面请求
    @GetMapping("/index/{userId}")
    public ModelAndView socket(@PathVariable String userId) {
        ModelAndView mav = new ModelAndView("/socket1");
        mav.addObject("userId", userId);
        return mav;
    }
    //推送数据接口
    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public Map pushToWeb(@PathVariable String cid, String message) {
        Map<String,Object> result = new HashMap<>();
        try {
            WebSocketServer.sendInfo(message, cid);
            result.put("code", cid);
            result.put("msg", message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}
jcdm-main/src/main/java/com/jcdm/main/websocket/WebSocketConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.jcdm.main.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
jcdm-main/src/main/java/com/jcdm/main/websocket/WebSocketServer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,158 @@
package com.jcdm.main.websocket;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Service
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
    static Log log = LogFactory.get(WebSocketServer.class);
    /**
     * é™æ€å˜é‡ï¼Œç”¨æ¥è®°å½•å½“前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**
     * ä¸ŽæŸä¸ªå®¢æˆ·ç«¯çš„连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * æŽ¥æ”¶userId
     */
    private String userId = "";
    /**
     * è¿žæŽ¥å»ºç«‹æˆåŠŸè°ƒç”¨çš„方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
            //加入set中
        } else {
            webSocketMap.put(userId, this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }
        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常!!!!!!");
        }
    }
    /**
     * è¿žæŽ¥å…³é—­è°ƒç”¨çš„方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }
    /**
     * æ”¶åˆ°å®¢æˆ·ç«¯æ¶ˆæ¯åŽè°ƒç”¨çš„方法
     *
     * @param message å®¢æˆ·ç«¯å‘送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + userId + ",报文:" + message);
        //可以群发消息
        //消息保存到数据库、redis
        if (! StringUtils.isEmpty(message)) {
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }
    /**
     * å®žçŽ°æœåŠ¡å™¨ä¸»åŠ¨æŽ¨é€
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    /**
     * å®žçŽ°æœåŠ¡å™¨ä¸»åŠ¨æŽ¨é€
     */
    public static void sendAllMessage(String message) throws IOException {
        log.info("发送消息:" + message);
        ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
        for (String userId : userIds) {
            WebSocketServer webSocketServer = webSocketMap.get(userId);
            webSocketServer.session.getBasicRemote().sendText(message);
            System.out.println("webSocket实现服务器主动推送成功userIds====" + userIds);
        }
    }
    /**
     * å‘送自定义消息
     */
    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
        log.info("发送消息到:" + userId + ",报文:" + message);
        if (!StringUtils.isEmpty(message) && webSocketMap.containsKey(userId)) {
            webSocketMap.get(userId).sendMessage(message);
        } else {
            log.error("用户" + userId + ",不在线!");
        }
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}
jcdm-main/src/main/resources/mapper/da/passingStationCollection/DaPassingStationCollectionMapper.xml
@@ -150,4 +150,14 @@
            #{id}
        </foreach>
    </delete>
    <select id="SelectSN" parameterType="java.util.Map" statementType="CALLABLE" resultType="java.lang.String">
        {
            call SNRetrieval(
                #{SN_CODE,mode=IN,jdbcType=VARCHAR},
                #{Node,mode=IN,jdbcType=VARCHAR},
                #{Success,mode=OUT,jdbcType=VARCHAR}
                 )
            }
    </select>
</mapper>
jcdm-ui/src/utils/WebsocketTool.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
//需求:在JavaScript中实现WebSocket连接失败后3分钟内尝试重连3次的功能,你可以设置一个重连策略,
//     åŒ…括重连的间隔时间、尝试次数以及总时间限制。
/**
 * @param {string} url  Url to connect
 * @param {number} maxReconnectAttempts Maximum number of times
 * @param {number} reconnect Timeout
 * @param {number} reconnectTimeout Timeout
 *
 */
class WebSocketReconnect {
  constructor(url, maxReconnectAttempts = 3, reconnectInterval = 20000, maxReconnectTime = 180000) {
    this.url = url
    this.maxReconnectAttempts = maxReconnectAttempts
    this.reconnectInterval = reconnectInterval
    this.maxReconnectTime = maxReconnectTime
    this.reconnectCount = 0
    this.reconnectTimeout = null
    this.startTime = null
    this.socket = null
    this.connect()
  }
  //连接操作
  connect() {
    console.log('connecting...')
    this.socket = new WebSocket(this.url)
    //连接成功建立的回调方法
    this.socket.OnOpen = () => {
      console.log('WebSocket Connection Opened!')
      this.clearReconnectTimeout()
      this.reconnectCount = 0
    }
    //连接关闭的回调方法
    this.socket.OnClose = (event) => {
      console.log('WebSocket Connection Closed:', event)
      this.handleClose()
    }
    //连接发生错误的回调方法
    this.socket.OnError = (error) => {
      console.error('WebSocket Connection Error:', error)
      this.handleClose() //重连
    }
  }
  //断线重连操作
  handleClose() {
    if (this.reconnectCount < this.maxReconnectAttempts && (this.startTime === null ||
      Date.now() - this.startTime < this.maxReconnectTime)) {
      this.reconnectCount++
      console.log(`正在尝试重连 (${this.reconnectCount}/${this.maxReconnectAttempts})次...`)
      this.reconnectTimeout = setTimeout(() => {
        this.connect()
      }, this.reconnectInterval)
      if (this.startTime === null) {
        this.startTime = Date.now()
      }
    } else {
      console.log('超过最大重连次数或重连时间超时,已放弃连接!Max reconnect attempts reached or exceeded max reconnect time. Giving up.')
      this.reconnectCount = 0 // é‡ç½®è¿žæŽ¥æ¬¡æ•°0
      this.startTime = null // é‡ç½®å¼€å§‹æ—¶é—´
    }
  }
  //清除重连定时器
  clearReconnectTimeout() {
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout)
      this.reconnectTimeout = null
    }
  }
  //关闭连接
  close() {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.close()
    }
    this.clearReconnectTimeout()
    this.reconnectCount = 0
    this.startTime = null
  }
}
// WebSocketReconnect ç±»å°è£…了WebSocket的连接、重连逻辑。
// maxReconnectAttempts æ˜¯æœ€å¤§é‡è¿žå°è¯•æ¬¡æ•°ã€‚
// reconnectInterval æ˜¯æ¯æ¬¡é‡è¿žå°è¯•ä¹‹é—´çš„间隔时间。
// maxReconnectTime æ˜¯æ€»çš„重连时间限制,超过这个时间后不再尝试重连。
// reconnectCount ç”¨äºŽè®°å½•å·²ç»å°è¯•çš„重连次数。
// startTime ç”¨äºŽè®°å½•å¼€å§‹é‡è¿žçš„时间。
// connect æ–¹æ³•ç”¨äºŽå»ºç«‹WebSocket连接,并设置相应的事件监听器。
// handleClose æ–¹æ³•åœ¨WebSocket连接关闭或发生错误时被调用,根据条件决定是否尝试重连。
// clearReconnectTimeout æ–¹æ³•ç”¨äºŽæ¸…除之前设置的重连定时器。
// close æ–¹æ³•ç”¨äºŽå…³é—­WebSocket连接,并清除重连相关的状态。
// ä½¿ç”¨ç¤ºä¾‹
// const webSocketReconnect = new WebSocketReconnect('ws://your-websocket-url')
// å½“不再需要WebSocket连接时,可以调用close方法
// webSocketReconnect.close();
export default WebSocketReconnect
jcdm-ui/src/views/main/kb/engineCheck/index.vue
@@ -44,7 +44,7 @@
         <el-row :gutter="10" class="mb8" type="flex" justify="center"  style="text-align: center">
           <el-col :span="1.5">
             <el-button plain  :disabled="buttondisabled" type="primary" style="width:400px;height:160px" v-hasPermi="['bs:formula:add']" @click="forceOnline">
             <el-button plain  :disabled="buttondisabled" type="primary" style="width:400px;height:160px" v-hasPermi="['bs:formula:add']">
               <span   class="el-icon-thumb"   style="font-size:40px;color:black"></span>
               <span style="font-size:45px;color:black"><strong>强制上线</strong></span>
             </el-button>
@@ -77,6 +77,41 @@
import { listOrderScheduling, getOrderScheduling, delOrderScheduling, addOrderScheduling, updateOrderScheduling } from "@/api/main/bs/orderScheduling/orderScheduling";
import { listPassingStationCollection, getPassingStationCollection, delPassingStationCollection, addPassingStationCollection, updatePassingStationCollection } from "@/api/main/da/passingStationCollection/passingStationCollection";
import {listLineInfo} from "@/api/main/bs/lineInfo/lineInfo";
import WebSocketReconnect from "@/utils/WebsocketTool";
// let websocket = null
// //判断当前浏览器是否支持WebSocket
// if ('WebSocket' in window) {
//   //连接WebSocket节点
//   websocket = new WebSocketReconnect('ws://127.0.0.1:8086/websocket/111122')
// } else {
//   alert('浏览器不支持webSocket')
// }
// //接收到消息的回调方法
// websocket.socket.onmessage = function (event) {
//   let data = event.data
//   console.log('后端传递的数据:' + data)
//   if (data != null && data !== ''){
//     this.result = JSON.parse(data)
//     console.log('this.result',this.result)
//     // this.form.engineNo = this.result.server_message
//     this.transEngineNo = this.result.server_message
//     console.log('this.transEngineNo11111111111',this.transEngineNo)
//   }
//
// }
// //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
// window.onbeforeunload = function () {
//   websocket.close()
// }
// //关闭连接
// function closeWebSocket() {
//   websocket.close()
// }
// //发送消息
// function send() {
//   websocket.socket.send({ kk: 123 })
// }
export default {
  components: { },
@@ -84,11 +119,15 @@
  props: [],
  data() {
    return {
      websocket: null,
      result: {},
      transEngineNo: '',
      options: [],
      total: 0,
      engineCheckList:[],
      showFlag:false,
      buttondisabled:true,
      mess:'',
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        pageNum: 1,
@@ -115,10 +154,57 @@
    };
  },
  computed: {},
  watch: {},
  watch: {
    // transEngineNo:{
    //   handler(newVal,oldVal) {
    //     console.log('newVal',newVal)
    //     console.log('oldVal',oldVal)
    //     this.form.engineNo = newVal
    //     console.log('11111111111111')
    //     console.log('this.form.engineNo',this.form.engineNo)
    //   },
    //   immediate:true
    // }
  },
  created() {},
  mounted() {},
  mounted() {
    this.initWebSocket()
  },
  methods: {
    initWebSocket: function (){
      //判断当前浏览器是否支持WebSocket
      if ('WebSocket' in window) {
        //连接WebSocket节点
        this.websocket = new WebSocketReconnect('ws://127.0.0.1:8086/websocket/111122')
        //接收到消息的回调方法
        this.websocket.socket.onmessage = (event) => {
          let data = event.data
          console.log('后端传递的数据:' + data)
          if (data != null && data !== ''){
            this.result = JSON.parse(data)
            console.log('this.result',this.result)
            this.form.engineNo = this.result.server_message
            // this.transEngineNo = this.result.server_message
            console.log('this.transEngineNo11111111111',this.transEngineNo)
          }
        }
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function () {
          this.websocket.close()
        }
//关闭连接
        function closeWebSocket() {
          this.websocket.close()
        }
//发送消息
        function send() {
          this.websocket.socket.send({ kk: 123 })
        }
      } else {
        alert('浏览器不支持webSocket')
      }
    },
    reset() {
      this.form = {
        engineNo:null,