SpringBoot+RXTXcomm实现Java串口通信 读取串口数据以及发送数据

news2024/9/21 22:41:27

记录一下使用SpringBoot+RXTXcomm实现Java串口通信,使用Java语言开发串口,对串口进行读写操作。
RXTXcomm.jar这个包支持的系统较多,但是更新太慢,在win系统下使用没有问题,但是在centos的工控机系统里使用读取和发送有问题,至今没能解决,报错的日志也记录一下


serial port com start success
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f5e636f75da, pid=18871, tid=0x00007f5e635ee700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [librxtxSerial.so+0x75da]  Java_gnu_io_RXTXPort_nativeDrain+0xea
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/hs_err_pid18871.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
已放弃
[root@localhost home]# 
Java HotSpot(TM) Server VM warning: You have loaded library /home/jdk18/jre/lib/i386/librxtxSerial.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c <libfile>', or link it with '-z noexecstack'.
java.lang.UnsatisfiedLinkError: /home/jdk18/jre/lib/i386/librxtxSerial.so: /home/jdk18/jre/lib/i386/librxtxSerial.so: 错误 ELF 类: ELFCLASS64 (Possible cause: architecture word width mismatch) thrown while loading gnu.io.RXTXCommDriver
15:33:11.580 spring-boot-logging [main] INFO  o.s.b.a.l.ConditionEvaluationReportLoggingListener - 

19:26:03.323 spring-boot-logging [main] INFO  c.z.d.serialport.SerialPortManager - open serial port success:/dev/ttyS1
serial port com start success
19:26:15.326 spring-boot-logging [Thread-5] INFO  c.z.data.serialport.SerialPortThread - stepCount--200
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007ffa604a7733, pid=17020, tid=0x00007ffa6019e700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [librxtxSerial.so+0x7733]  Java_gnu_io_RXTXPort_nativeDrain+0xc3
#
# Core dump written. Default location: /usr/local/core or core.17020
#
# An error report file with more information is saved as:
# /usr/local/hs_err_pid17020.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
已放弃(吐核)


因此如果要使用RXTXcomm.jar这个串口包,建议在win系统下使用更好一些,其他系统使用可能出现莫名其妙的问题,如果非要在linux(centos)系统使用,推荐使用jSerialComm.jar

<dependency>
    <groupId>com.fazecast</groupId>
    <artifactId>jSerialComm</artifactId>
    <version>2.9.2</version>
</dependency>

这里记录使用SpringBoot加RXTXcomm在win10系统下的使用
mfz-rxtx-2.2-20081207-win-x64的下载地址

http://fizzed.com/oss/rxtx-for-java

myw
根据自己的系统选择对应的下载包
myw
myw
从readme.txt得知编译的环境特别旧了,将来的使用定然是越来越少

win-x86, win-x64, ia64
-----------------------------------------------
Built using Microsoft Visual C++ 2008 - not MinGW. The
x86 and x64 versions are native and do not rely on
any other non-standard windows libraries.  Just drop
in the compiled .dlls that are specific to the version
of Java you run. If you installed the 64-bit version
of the JDK, then install the x64 build.

I've tested the x86 and x64 version with Windows 2008,
2003, and Vista SP1.


linux-i386 & linux-x86_64
-----------------------------------------------
Built using CentOS 5.2 and gcc 4.1.2.

Just drop in the compiled .dlls that are specific to
the version of Java you run. If you installed the 64-bit
version of the JDK, then install the x64 build.

I've tested the x86 and x64 versions with x86 and x64
versions of CentOS 5.0 and 5.2.

myw
根据文档,先将rxtxSerial.dll和rxtxParallel.dll放在指定的目录内
我自己电脑的JAVA_HOME
myw
那么文件存放位置
myw
至于 RXTXcomm.jar包不放在文档里的位置,放在具体的项目内引用(根据个人喜好来,我直接按照文档的方式去放,发现不起作用)

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>boot.example.mfz.rxtx</groupId>
    <artifactId>boot-example-serial-port-mfz-rxtx-2.0.5</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-example-serial-port-mfz-rxtx-2.0.5</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>gnu.io</groupId>
            <artifactId>RXTXcomm</artifactId>
            <version>2.2</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/jar/RXTXcomm.jar</systemPath>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.example.BootRXTXApplication</mainClass>
                    <includeSystemScope>true</includeSystemScope><!--外部进行打包-->
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

这里有个点儿

<systemPath>${project.basedir}/libs/jar/RXTXcomm.jar</systemPath>

myw
BootRXTXApplication.java

package com.example;


import com.example.serialport.SerialPortManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.List;


@SpringBootApplication
@EnableScheduling
@EnableAsync
public class BootRXTXApplication implements CommandLineRunner {

    private final Logger log =  LoggerFactory.getLogger(this.getClass());

    public static void main(String[] args) throws IOException {
        SpringApplication.run(BootRXTXApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        try{
            List<String> portList = SerialPortManager.getSerialPortList();
            if(!portList.isEmpty()){
                log.info(portList.toString());
                SerialPortManager.connectSerialPort();
            }
        } catch (Exception e){
            log.error("获取串口信息失败");
        }

    }

    @PreDestroy
    public void destroy() {
        SerialPortManager.closeSerialPort();
        System.exit(0);
    }



}

测试往串口发数据
SerialPortSendController.java

package com.example.controller;

import com.example.serialport.ConvertHexStrAndStrUtils;
import com.example.serialport.SerialPortManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
public class SerialPortSendController {

    //  http://localhost:8781/sendTest?message=mywmyyhtw

    @GetMapping(value = "/sendTest")
    @ResponseBody
    public String sendStringTopic(@RequestParam(name="message",required = true) String message) throws Exception {
        SerialPortManager.sendSerialPortData(ConvertHexStrAndStrUtils.strToHexStr(message));
        return "success";
    }

}

字符串以及16进制以及字节之间的转换工具类ConvertHexStrAndStrUtils.java

package com.example.serialport;

import java.nio.charset.StandardCharsets;

public class ConvertHexStrAndStrUtils {

    private static final char[] HEXES = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String bytesToHexStr(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        StringBuilder hex = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            hex.append(HEXES[(b >> 4) & 0x0F]);
            hex.append(HEXES[b & 0x0F]);
        }
        return hex.toString().toUpperCase();
    }

    public static byte[] hexStrToBytes(String hex) {
        if (hex == null || hex.length() == 0) {
            return null;
        }
        char[] hexChars = hex.toCharArray();
        byte[] bytes = new byte[hexChars.length / 2];   // 如果 hex 中的字符不是偶数个, 则忽略最后一个
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
        }
        return bytes;
    }

    public static String strToHexStr(String str) {
        StringBuilder sb = new StringBuilder();
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(HEXES[bit]);
            bit = bs[i] & 0x0f;
            sb.append(HEXES[bit]);
        }
        return sb.toString().trim();
    }

    public static String hexStrToStr(String hexStr) {
        //能被16整除,肯定可以被2整除
        byte[] array = new byte[hexStr.length() / 2];
        try {
            for (int i = 0; i < array.length; i++) {
                array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
            }
            hexStr = new String(array, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return hexStr;
    }

}

串口工具类 我这里默认写死COM1 波特率9600
SerialPortManager.java

package com.example.serialport;

import gnu.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.TooManyListenersException;
import java.util.concurrent.TimeUnit;

public class SerialPortManager {

    private static final Logger log =  LoggerFactory.getLogger(SerialPortManager.class);

    public static String SERIAL_PORT_NUMBER = "COM1";

    public static final int SERIAL_BAUD_RATE = 9600;

    public static volatile long SERIAL_CALLBACK_TIME = System.currentTimeMillis()/1000;

    public static volatile boolean SERIAL_PORT_STATE = false;

    public static volatile SerialPort SERIAL_PORT_OBJECT = null;

    //  获得系统可用的端口名称列表
    @SuppressWarnings("unchecked")
    public static List<String> getSerialPortList() {
        List<String> systemPorts = new ArrayList<>();
        //获得系统可用的端口
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
        while (portList.hasMoreElements()) {
            String portName = portList.nextElement().getName();//获得端口的名字
            systemPorts.add(portName);
        }
        return systemPorts;
    }

    public static void connectSerialPort(){
        try {
            closeSerialPort();
            TimeUnit.MILLISECONDS.sleep(4000);
            if(openSerialPort()){
                System.out.println("serial port com start success");
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    //  打开串口  设置中断和监听事件
    public static boolean openSerialPort() {
        try {
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(SERIAL_PORT_NUMBER);
            CommPort commPort = portIdentifier.open(SERIAL_PORT_NUMBER, 3000);
            if(commPort == null){return false;}
            //判断是不是串口
            if (commPort instanceof SerialPort) {
                SerialPort serialPort = (SerialPort) commPort;
                //设置串口参数(波特率,数据位8,停止位1,校验位无)
                serialPort.setSerialPortParams(SERIAL_BAUD_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                // 当有数据到达时唤醒数据接收线程
                serialPort.notifyOnDataAvailable(true);
                // 当串口连接中断时唤醒中断线程
                serialPort.notifyOnBreakInterrupt(true);
                serialPort.notifyOnCarrierDetect(true);
                serialPort.notifyOnDSR(true);
                // 添加串口监听事件
                serialPort.addEventListener(new SerialPortListener(new SerialPortCallback()));
                SerialPortManager.SERIAL_PORT_OBJECT = serialPort;
                SerialPortManager.SERIAL_PORT_STATE = true;
                log.info("open serial port success:" + SERIAL_PORT_NUMBER);
                return true;
            } else {
                //是其他类型的端口
                throw new NoSuchPortException();
            }
        } catch (NoSuchPortException e) {
            log.error("not find serial port:" + e.getMessage());
        } catch (PortInUseException e) {
            log.error("the serial port used:" + e.getMessage());
        } catch (UnsupportedCommOperationException e) {
            log.error("open others serial port:" + e.getMessage());
        } catch (TooManyListenersException e) {
            log.error("the more listener this serial port:"+ e.getMessage());
        }

        return false;
    }

    //  关闭串口
    public static void closeSerialPort() {
        SERIAL_PORT_STATE = false;
        if (SERIAL_PORT_OBJECT != null) {
            SERIAL_PORT_OBJECT.close();
            SERIAL_PORT_OBJECT = null;
            log.info("serial port close");
        }
    }

    //  向串口发送数据
    public static void sendSerialPortData(String data) {
        OutputStream outputStream = null;
        try {
            outputStream = SERIAL_PORT_OBJECT.getOutputStream();
            outputStream.write(ConvertHexStrAndStrUtils.hexStrToBytes(data));
            outputStream.flush();
            log.info("send data success:"+data);
        } catch (IOException e) {
            log.error("read data exception:"+e.getMessage());
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                log.error("read data inputStream close error:"+ e.getMessage());
            }
        }
    }

    //  从串口读取数据
    public static byte[] readSerialPortData() {
        InputStream in = null;
        byte[] bytes = {};
        try {
            TimeUnit.MILLISECONDS.sleep(200);
            in = SERIAL_PORT_OBJECT.getInputStream();
            byte[] readBuffer = new byte[1];
            int bytesNum = in.read(readBuffer);
            while (bytesNum > 0) {
                bytes = concat(bytes, readBuffer);
                bytesNum = in.read(readBuffer);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }


    public static byte[] concat(byte[] firstArray, byte[] secondArray) {
        if (firstArray == null || secondArray == null) {
            return null;
        }
        byte[] bytes = new byte[firstArray.length + secondArray.length];
        System.arraycopy(firstArray, 0, bytes, 0, firstArray.length);
        System.arraycopy(secondArray, 0, bytes, firstArray.length, secondArray.length);
        return bytes;
    }

}

SerialPortListener.java

package com.example.serialport;

import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SerialPortListener implements SerialPortEventListener {

    private final Logger log =  LoggerFactory.getLogger(this.getClass());

    private final SerialPortCallback serialPortCallback;

    public SerialPortListener(SerialPortCallback serialPortCallback) {
        this.serialPortCallback = serialPortCallback;
    }

    public void serialEvent(SerialPortEvent serialPortEvent) {
        log.warn("SerialPortTestListener:"+serialPortEvent.getEventType());
        SerialPortManager.SERIAL_CALLBACK_TIME = System.currentTimeMillis()/1000;
        if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            if (serialPortCallback != null) {
                serialPortCallback.dataAvailable();
            }
        }

    }




}

从串口接收数据的SerialPortCallback.java

package com.example.serialport;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SerialPortCallback {

    private final Logger log =  LoggerFactory.getLogger(this.getClass());

    public void dataAvailable() {
        try {
            //throw new Exception();
            byte[] data = SerialPortManager.readSerialPortData();
            String s = ConvertHexStrAndStrUtils.bytesToHexStr(data);
            log.info("rev--data:"+s);
        } catch (Exception e) {
            log.error(e.toString());
        }
    }



}

定时器SerialPortTimer.java

package com.example.serialport;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;


@Service
public class SerialPortTimer {


    @Async
    @Scheduled(cron = "0 0/5 * * * ?")
    public void timeSerialPortScheduled() throws IOException, InterruptedException {
        long now = System.currentTimeMillis();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd:HH:mm:ss");
        System.out.println("timeSerialPortScheduled--"+format.format(now));
        long interval = 2 * 60 * 60;
        long rebootInterval = 24 * 60 * 60;
        long difference =  now/1000 - SerialPortManager.SERIAL_CALLBACK_TIME;

        // 当2个小时内收不到串口数据重启串口
        if(difference > interval){
            SerialPortManager.connectSerialPort();
        }

        //  当24小时内都还是收不到串口数据重启系统
        if(difference > rebootInterval){
            try {
                String osName = System.getProperty("os.name");
                if(osName.startsWith("Windows")) {
                    Runtime.getRuntime().exec("shutdown -r -t 0 -f");
                } else if(osName.startsWith("Linux")){
                    Runtime.getRuntime().exec("reboot");
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }

}

代码结构

│  pom.xml
│  
├─doc
│  │  mfz-rxtx-2.2-20081207-win-x64.zip
│  │  mfz-rxtx-2.2-20081207-win-x86.zip
│  │  
│  └─mfz-rxtx-2.2-20081207-win-x64
│          BuildProperties.txt
│          Install.txt
│          Readme.txt
│          ReleaseNotes.txt
│          RXTXcomm.jar
│          rxtxParallel.dll
│          rxtxSerial.dll
│          
├─libs
│  └─jar
│          jna.jar
│          RXTXcomm.jar
│          
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─example
│  │  │          │  BootRXTXApplication.java
│  │  │          │  
│  │  │          ├─controller
│  │  │          │      SerialPortSendController.java
│  │  │          │      
│  │  │          └─serialport
│  │  │                  ConvertHexStrAndStrUtils.java
│  │  │                  SerialPortCallback.java
│  │  │                  SerialPortListener.java
│  │  │                  SerialPortManager.java
│  │  │                  SerialPortTimer.java
│  │  │                  
│  │  └─resources
│  │          application.properties
│  │          logback-spring.xml
│  │          
│  └─test
│      └─java
│          └─com
│              └─example
│                      BootRXTXApplicationTest.java
│            

接收数据测试 通过com2 向 com1发送数据 那么就算SpringBoot串口接收数据
myw
可以看到控制台有打印数据
myw
发送数据测试

http://localhost:8781/sendTest?message=mywmyyhtw

可以看到控制台
myw
对应的接收端
myw

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/509131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vmstat 粗查系统判断瓶颈

vmstat 1 5 每 1 秒显示一次 &#xff0c; 一共显示 5 次后结束 memory 内存 swap 虚拟磁盘&#xff0c;交换分区 io 磁盘 system 系统进程 rrun 多少个进程在跑&#xff0c;包括在排队等待cpu处理的进程b block 多少个进程处于卡死状态。 除CPU外的资源如网络、…

视频播放方案

video插件播放m3u8格式视频(存原生) 这里使用原生的javascript实现m3u8格式视频播放。 使用了包括video.min.js库和HLS插件。 1-基础使用 <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>Video.js HLS Example</title…

MYSQL高级语句

实验用表 create table location (Region char(20),Store_Name char(20)); insert into location values(East,Boston); insert into location values(East,New York); insert into location values(West,Los Angeles); insert into location values(West,Houston); location…

如何解决请求参数为JSON时,采用IO流读取,只能请求一次的问题?

如何解决请求参数为JSON时&#xff0c;采用IO流读取&#xff0c;只能请求一次的问题&#xff1f; 一、错误演示1. 创建项目&#xff0c;添加所需依赖2. 配置redis环境3. 写一个简单的测试请求4. 写一个拦截器&#xff0c;拦截请求5. WebConfig 注册拦截器6. 测试请求 二、问题解…

vue问题

一、路由 hash模式&#xff08;location.hash hashchange 事件&#xff09; hash 模式的实现方式就是通过监听 URL 中的 hash 部分的变化&#xff0c;触发haschange事件&#xff0c;页面做出不同的响应。但是 hash 模式下&#xff0c;URL 中会带有 #&#xff0c;不太美观。 h…

【多线程初阶三】简单了解wait和notify方法~

目录 &#x1f31f;1、wait() &#x1f31f;2、notify() &#x1f31f;1、wait() &#xff08;1&#xff09;wait()方法与notify()方法都是Object类中的方法。 &#xff08;2&#xff09;wait()是让线程等待一段时间&#xff0c;死等——>状态WAITING:没有时间限制的等待.…

MySQL 高级(进阶) SQL 语句一

一、高级SQL语句&#xff08;进阶查询&#xff09; 先准备2个表 一个location表&#xff1a; use kgc; create table location (Region char(20),Store_Name char(20)); insert into location values(East,Boston); insert into location values(East,New York); insert int…

如何判断CRM软件的好坏?2023年CRM系统排行榜前三名是什么?

CRM客户管理系统经过20余年的发展&#xff0c;收获了越来越多企业的认可&#xff0c;成为企业数字化转型必不可少的一环。很多企业都有上线CRM软件的计划&#xff0c;但精准的找到一款适合自身的产品十分不易&#xff0c;今天我们就来盘点2023年CRM软件排行榜。 一、CRM的含义…

Intellij中使用Spotless 格式化代码

Spotless简介 在一些大型项目或开源项目&#xff0c;由于开发人员太多&#xff0c;导致各个代码格式不统一。会让整体项目的代码可读性变差。统一代码格式使用maven中的Spotless插件就是不错的选择。 Spotless 是一个代码格式化工具&#xff0c;它有以下功能&#xff1a; 支…

300. 最长递增子序列

300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子…

tp6 对接阿里云短信

1、获取AccessKey ID,AccessKey Secret&#xff0c;第一次会提示需要创建 2、添加签名 3、创建模板 composer版本太老了&#xff0c;可能会导致下载失败&#xff0c;建议升级下版本 官方提供的最新依赖版本&#xff0c;我的会报错&#xff0c;下载不了&#xff0c;提示用2.0.…

Android Studio 下真机调试

文章目录 一、开启真机调试二、断开真机调试 一、开启真机调试 准备USB调试线&#xff0c;一端插在电脑USB接口上&#xff0c;另一端插在手机充电口上。 下面以自己的手机&#xff08;huawei nova 5 &#xff09;为例&#xff1a;点击手机界面上的设置应用。 然后往下找到 【关…

经典神经网络(1)LeNet及其在Fashion-MNIST数据集上的应用

经典神经网络(1)LeNet 1、卷积神经网络LeNet 之前对于Fashion-MNIST服装分类数据集&#xff0c;为了能够应⽤softmax回归和多层感知机&#xff0c;我们⾸先将每个大小为28 28的图像展平为⼀个784维的固定⻓度的⼀维向量&#xff0c;然后⽤全连接层对其进⾏处理&#xff0c;此…

函数式接口的介绍和使用(FunctionInterface)——Consumer,Supplier,Predicate、Function

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法&#xff0c;但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。 函数式接口都添加了 FunctionalInterface 注解&#xff0c;这个是jdk1.8才引进的。例如 因为函数式接口里面只是…

【C++】| 01——泛型编程 | 模板

系列文章目录 【C】| 01——泛型编程 | 模板 文章目录 1. 认识泛型编程2. 函数模板1.1 函数模板的语法1.1.1 定义模板1.1.2 应用模板实现函数1.1.3 使用模板函数(实例化)1.1.3.1 隐式使用(实例化)1.1.3.2 显式使用(实例化)1.1.3.3 使用函数模板的注意事项(实例化) 2. 类模板2.…

第1章 Nginx简介

基于 Nginx版本 1.14.2 &#xff0c;Tomcat版本 9.0.0 演示 第1章 Nginx简介 1.1 Nginx发展介绍 Nginx &#xff08;engine x&#xff09; 是一个高性能的Web服务器和反向代理服务器&#xff0c;也可以作为邮件代理服务器。 Nginx 特点是占有内存少&#xff0c;并发处理能力…

南京邮电大学数据库实验二(DBMS的数据库保护)

文章目录 一、实验目的和要求二、实验环境(实验设备)三、实验原理及内容(1) DBMS的数据库保护功能(2) 安全控制中的访问控制机制(3) 事务的提交与回滚(4) 并发控制的锁机制 三、实验内容1.以root账户登录数据库管理系统&#xff0c;创建用户U1和U2&#xff0c;密码自定。2.创建…

Redis 入门教程(简单全面版)

1 安装&#xff1a; 1.1 生产环境安装 注意&#xff1a; 1、如果安装过程有问题可以参考源代码中的 README.md 文件 2、如果服务器只安装一个 redis 通常选择 /usr/local/redis 作为安装目录&#xff0c;如果安装多台则建议带上 服务名称 区分&#xff08;建议带上 服务名称 区…

jvm-狂神课程

一、JVM JVM就是Java虚拟机&#xff0c;Java虚拟机就是JVM 1. JVM位置 1、Java程序&#xff08;跑的环境是在jvm&#xff08;虚拟机&#xff09;跑的&#xff0c;也可以说是在jre上跑的&#xff09;java运行是需要在特定的环境的也就是这个jre这种。 2、jvm&#xff08;也就是…

别不信:这些细节关乎你的物联网设备的命运!

《高并发系统实战派》-- 值得拥有 一、设备接入层网络协议的意义 随着物联网的发展&#xff0c;越来越多的设备需要接入云平台进行远程监控和管理。设备接入层网络协议起到了承担设备接入网络的功能&#xff0c;为物联网平台提供了数据交互的基础。设备接入层网络协议对于物联…