扩展项目
This commit is contained in:
parent
d6844f19bd
commit
6b7e0bfa33
|
|
@ -0,0 +1,73 @@
|
|||
<?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">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>modbus-server</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Ailibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
<!-- Ruoyi Common Swagger -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-swagger</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.50.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.sarnath.modbusserver;
|
||||
|
||||
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
|
||||
import com.sarnath.modbusserver.dtuutils.DTUServer;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.cloud.client.SpringCloudApplication;
|
||||
|
||||
@EnableCustomSwagger2
|
||||
@SpringCloudApplication
|
||||
public class SarnathModbusServerApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(SarnathModbusServerApplication.class, args);
|
||||
|
||||
|
||||
new Thread(()->{
|
||||
DTUServer.Start();
|
||||
}).start();
|
||||
System.out.println("(♥◠‿◠)ノ゙ Modbus服务端模块启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
"____.___._________ \n" +
|
||||
"\\__ | |\\_ ___ \\ \n" +
|
||||
" / | |/ \\ \\/ \n" +
|
||||
" \\____ |\\ \\____\n" +
|
||||
" / ______| \\______ /\n" +
|
||||
" \\/ \\/ ");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
package com.sarnath.modbusserver.dtuutils;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 数字转字节数组工具类
|
||||
*/
|
||||
public class BitConverter {
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的布尔值
|
||||
* @param data 一个布尔值
|
||||
* @return 长度为 1 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(boolean data) {
|
||||
byte[] bytes = new byte[1];
|
||||
bytes[0] = (byte) (data ? 1 : 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 16 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 2 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(short data) {
|
||||
byte[] bytes = new byte[2];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data & 0xff00) >> 8);
|
||||
} else {
|
||||
bytes[1] = (byte) (data & 0xff);
|
||||
bytes[0] = (byte) ((data & 0xff00) >> 8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 Unicode 字符值
|
||||
* @param data 要转换的字符
|
||||
* @return 长度为 2 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(char data) {
|
||||
byte[] bytes = new byte[2];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data);
|
||||
bytes[1] = (byte) (data >> 8);
|
||||
} else {
|
||||
bytes[1] = (byte) (data);
|
||||
bytes[0] = (byte) (data >> 8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 32 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 4 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(int data) {
|
||||
byte[] bytes = new byte[4];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data & 0xff00) >> 8);
|
||||
bytes[2] = (byte) ((data & 0xff0000) >> 16);
|
||||
bytes[3] = (byte) ((data & 0xff000000) >> 24);
|
||||
} else {
|
||||
bytes[3] = (byte) (data & 0xff);
|
||||
bytes[2] = (byte) ((data & 0xff00) >> 8);
|
||||
bytes[1] = (byte) ((data & 0xff0000) >> 16);
|
||||
bytes[0] = (byte) ((data & 0xff000000) >> 24);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 64 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 8 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(long data) {
|
||||
byte[] bytes = new byte[8];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data >> 8) & 0xff);
|
||||
bytes[2] = (byte) ((data >> 16) & 0xff);
|
||||
bytes[3] = (byte) ((data >> 24) & 0xff);
|
||||
bytes[4] = (byte) ((data >> 32) & 0xff);
|
||||
bytes[5] = (byte) ((data >> 40) & 0xff);
|
||||
bytes[6] = (byte) ((data >> 48) & 0xff);
|
||||
bytes[7] = (byte) ((data >> 56) & 0xff);
|
||||
} else {
|
||||
bytes[7] = (byte) (data & 0xff);
|
||||
bytes[6] = (byte) ((data >> 8) & 0xff);
|
||||
bytes[5] = (byte) ((data >> 16) & 0xff);
|
||||
bytes[4] = (byte) ((data >> 24) & 0xff);
|
||||
bytes[3] = (byte) ((data >> 32) & 0xff);
|
||||
bytes[2] = (byte) ((data >> 40) & 0xff);
|
||||
bytes[1] = (byte) ((data >> 48) & 0xff);
|
||||
bytes[0] = (byte) ((data >> 56) & 0xff);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的单精度浮点值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 4 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(float data) {
|
||||
return getBytes(Float.floatToIntBits(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的双精度浮点值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 8 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(double data) {
|
||||
return getBytes(Double.doubleToLongBits(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定字符串中的所有字符编码为一个字节序列
|
||||
* @param data 包含要编码的字符的字符串
|
||||
* @return 一个字节数组,包含对指定的字符集进行编码的结果
|
||||
*/
|
||||
public static byte[] getBytes(String data) {
|
||||
return data.getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定字符串中的所有字符编码为一个字节序列
|
||||
* @param data 包含要编码的字符的字符串
|
||||
* @param charsetName 字符集编码
|
||||
* @return 一个字节数组,包含对指定的字符集进行编码的结果
|
||||
*/
|
||||
public static byte[] getBytes(String data, String charsetName) {
|
||||
return data.getBytes(Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的布尔值
|
||||
* @param bytes 字节数组
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean toBoolean(byte[] bytes) {
|
||||
return bytes[0] == 0 ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的一个字节转换来的布尔值
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean toBoolean(byte[] bytes, int startIndex) {
|
||||
return toBoolean(copyFrom(bytes, startIndex, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 16 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由两个字节构成的 16 位有符号整数
|
||||
*/
|
||||
public static short toShort(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
|
||||
} else {
|
||||
return (short) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 无符号short整数转换为2字节的byte数组
|
||||
*
|
||||
* @param s
|
||||
* short整数
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] unsignedShortToByte2(int s) {
|
||||
byte[] targets = new byte[2];
|
||||
targets[0] = (byte) (s >> 8 & 0xFF);
|
||||
targets[1] = (byte) (s & 0xFF);
|
||||
return targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换为无符号short整数
|
||||
*
|
||||
* @param bytes
|
||||
* byte数组
|
||||
* @return short整数
|
||||
*/
|
||||
public static int byte2ToUnsignedShort(byte[] bytes) {
|
||||
return byte2ToUnsignedShort(bytes, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换为无符号short整数
|
||||
*
|
||||
* @param bytes
|
||||
* byte数组
|
||||
* @param off
|
||||
* 开始位置
|
||||
* @return short整数
|
||||
*/
|
||||
public static int byte2ToUnsignedShort(byte[] bytes, int off) {
|
||||
int high = bytes[off];
|
||||
int low = bytes[off + 1];
|
||||
return (high << 8 & 0xFF00) | (low & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的两个字节转换来的 16 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由两个字节构成的 16 位有符号整数
|
||||
*/
|
||||
public static short toShort(byte[] bytes, int startIndex) {
|
||||
return toShort(copyFrom(bytes, startIndex, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 Unicode 字符
|
||||
* @param bytes 字节数组
|
||||
* @return 由两个字节构成的字符
|
||||
*/
|
||||
public static char toChar(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
|
||||
} else {
|
||||
return (char) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的两个字节转换来的 Unicode 字符
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由两个字节构成的字符
|
||||
*/
|
||||
public static char toChar(byte[] bytes, int startIndex) {
|
||||
return toChar(copyFrom(bytes, startIndex, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 32 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由四个字节构成的 32 位有符号整数
|
||||
*/
|
||||
public static int toInt(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (0xff & bytes[0])
|
||||
| (0xff00 & (bytes[1] << 8))
|
||||
| (0xff0000 & (bytes[2] << 16))
|
||||
| (0xff000000 & (bytes[3] << 24));
|
||||
} else {
|
||||
return (0xff & bytes[3])
|
||||
| (0xff00 & (bytes[2] << 8))
|
||||
| (0xff0000 & (bytes[1] << 16))
|
||||
| (0xff000000 & (bytes[0] << 24));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的四个字节转换来的 32 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由四个字节构成的 32 位有符号整数
|
||||
*/
|
||||
public static int toInt(byte[] bytes, int startIndex) {
|
||||
return toInt(copyFrom(bytes, startIndex, 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 64 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由八个字节构成的 64 位有符号整数
|
||||
*/
|
||||
public static long toLong(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (0xffL & (long) bytes[0])
|
||||
| (0xff00L & ((long) bytes[1] << 8))
|
||||
| (0xff0000L & ((long) bytes[2] << 16))
|
||||
| (0xff000000L & ((long) bytes[3] << 24))
|
||||
| (0xff00000000L & ((long) bytes[4] << 32))
|
||||
| (0xff0000000000L & ((long) bytes[5] << 40))
|
||||
| (0xff000000000000L & ((long) bytes[6] << 48))
|
||||
| (0xff00000000000000L & ((long) bytes[7] << 56));
|
||||
} else {
|
||||
return (0xffL & (long) bytes[7])
|
||||
| (0xff00L & ((long) bytes[6] << 8))
|
||||
| (0xff0000L & ((long) bytes[5] << 16))
|
||||
| (0xff000000L & ((long) bytes[4] << 24))
|
||||
| (0xff00000000L & ((long) bytes[3] << 32))
|
||||
| (0xff0000000000L & ((long) bytes[2] << 40))
|
||||
| (0xff000000000000L & ((long) bytes[1] << 48))
|
||||
| (0xff00000000000000L & ((long) bytes[0] << 56));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的八个字节转换来的 64 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由八个字节构成的 64 位有符号整数
|
||||
*/
|
||||
public static long toLong(byte[] bytes, int startIndex) {
|
||||
return toLong(copyFrom(bytes, startIndex, 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的单精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @return 由四个字节构成的单精度浮点数
|
||||
*/
|
||||
public static float toFloat(byte[] bytes) {
|
||||
return Float.intBitsToFloat(toInt(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的四个字节转换来的单精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由四个字节构成的单精度浮点数
|
||||
*/
|
||||
public static float toFloat(byte[] bytes, int startIndex) {
|
||||
return Float.intBitsToFloat(toInt(copyFrom(bytes, startIndex, 4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的双精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @return 由八个字节构成的双精度浮点数
|
||||
*/
|
||||
public static double toDouble(byte[] bytes) {
|
||||
return Double.longBitsToDouble(toLong(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的八个字节转换来的双精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由八个字节构成的双精度浮点数
|
||||
*/
|
||||
public static double toDouble(byte[] bytes, int startIndex) {
|
||||
return Double.longBitsToDouble(toLong(copyFrom(bytes, startIndex, 8)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的字符串
|
||||
* @param bytes 字节数组
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String toString(byte[] bytes) {
|
||||
return new String(bytes, Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的字符串
|
||||
* @param bytes 字节数组
|
||||
* @param charsetName 字符集编码
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String toString(byte[] bytes, String charsetName) {
|
||||
return new String(bytes, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字符串表示形式返回字节数组的内容
|
||||
* @param bytes 字节数组
|
||||
* @return 字符串形式的 <tt>bytes</tt>
|
||||
*/
|
||||
public static String toHexString(byte[] bytes) {
|
||||
if (bytes == null)
|
||||
return "null";
|
||||
int iMax = bytes.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(String.format("%02x", bytes[i] & 0xFF));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* 数组拷贝。
|
||||
* @param src 字节数组。
|
||||
* @param off 起始下标。
|
||||
* @param len 拷贝长度。
|
||||
* @return 指定长度的字节数组。
|
||||
*/
|
||||
public static byte[] copyFrom(byte[] src, int off, int len) {
|
||||
// return Arrays.copyOfRange(src, off, off + len);
|
||||
byte[] bits = new byte[len];
|
||||
for (int i = off, j = 0; i < src.length && j < len; i++, j++) {
|
||||
bits[j] = src[i];
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 CPU Endian 是否为 Little
|
||||
* @return 判断结果
|
||||
*/
|
||||
private static boolean isLittleEndian() {
|
||||
return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.sarnath.modbusserver.dtuutils;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
|
||||
public class DTUServer {
|
||||
|
||||
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
|
||||
public static void Start()
|
||||
{
|
||||
//主工作线程组,设置为1个线程
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
//工作线程组,默认为内核数*2的线程数
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_BACKLOG, 100)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(new LoggingHandler(LogLevel.INFO));
|
||||
p.addLast(new DTUServerHandler());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Start the server.
|
||||
ChannelFuture f = b.bind(PORT).sync();
|
||||
// Wait until the server socket is closed.
|
||||
f.channel().closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// Shut down all event loops to terminate all threads.
|
||||
bossGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package com.sarnath.modbusserver.dtuutils;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class DTUServerHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DTUServerHandler.class);
|
||||
|
||||
private byte[] cBuf = new byte[0];
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
InetSocketAddress ipSocket = (InetSocketAddress )ctx.channel().remoteAddress();
|
||||
String addr = ipSocket.getAddress().getHostAddress();
|
||||
int port = ipSocket.getPort();
|
||||
LOG.info("通道读取,对方位于" + addr + ":" + port);
|
||||
ByteBuf buffer = (ByteBuf)msg;
|
||||
if (buffer != null)
|
||||
{
|
||||
//string msg = BitConverter.ToString(buffer.Array);
|
||||
//LogUtil.Info(msg);
|
||||
// 读取长度
|
||||
int len = buffer.readableBytes();
|
||||
byte[] curBuf = new byte[len];
|
||||
buffer.readBytes(curBuf,0,len);
|
||||
//System.arraycopy(buffer.array(), buffer.arrayOffset(), curBuf, 0, len);
|
||||
String tempMsg = BitConverter.toHexString(curBuf);
|
||||
LOG.info("xxxxxxxxx:"+tempMsg);
|
||||
//
|
||||
Unpacking(curBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归处理当前包
|
||||
/// </summary>
|
||||
/// <param name="curBuf"></param>
|
||||
private void Unpacking(byte[] curBuf)
|
||||
{
|
||||
// 读取长度
|
||||
int len = curBuf.length;
|
||||
// 定义拼接数据包
|
||||
byte[] revBuf = new byte[len + cBuf.length];
|
||||
// 拼接 缓存数据包
|
||||
System.arraycopy(cBuf, 0, revBuf, 0, cBuf.length);
|
||||
// 拼接 新接收数据包
|
||||
System.arraycopy(curBuf, 0, revBuf, cBuf.length, len);
|
||||
// 使用完重置缓存包
|
||||
cBuf = new byte[0];
|
||||
// 包长判断
|
||||
if (len >= 4)
|
||||
{
|
||||
String tempMsg = BitConverter.toHexString(revBuf);
|
||||
LOG.info("xxxxxxxxx:"+tempMsg);
|
||||
|
||||
String tempMsg2 = BitConverter.toHexString(BitConverter.copyFrom(revBuf, 2, 2));
|
||||
LOG.info("xxxxxxxxx2:"+tempMsg2);
|
||||
LOG.info("xxxxxxxxx2:"+BitConverter.toHexString(BitConverter.getBytes((short) 6)));
|
||||
//2 3 位为整包长度
|
||||
short packageLen = BitConverter.toShort(BitConverter.copyFrom(revBuf, 2, 2));
|
||||
LOG.info("packageLen:"+packageLen);
|
||||
if (packageLen==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (packageLen > revBuf.length)
|
||||
{
|
||||
// 缓存断包 等待下一个数据包
|
||||
LOG.info("缓存断包!");
|
||||
cBuf = revBuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 根据长度 拆包
|
||||
byte[] comBuf = new byte[packageLen];
|
||||
System.arraycopy(revBuf, 0, comBuf, 0, packageLen);
|
||||
// 业务处理
|
||||
DoSomeThing(comBuf);
|
||||
//// 重置缓存包
|
||||
//cBuf = new byte[0];
|
||||
int remLen = revBuf.length - packageLen;
|
||||
if (remLen>0)
|
||||
{
|
||||
LOG.info("粘包处理!");
|
||||
// 重置当前处理包
|
||||
curBuf = new byte[remLen];
|
||||
System.arraycopy(revBuf, packageLen, curBuf, 0, remLen);
|
||||
// 递归处理剩余数据包
|
||||
Unpacking(curBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 缓存断包 等待下一个数据包
|
||||
LOG.info("缓存断包!");
|
||||
cBuf = revBuf;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx) {
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
// Close the connection when an exception is raised.
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
private void DoSomeThing(byte[] comBuf)
|
||||
{
|
||||
String msg = BitConverter.toHexString(comBuf);
|
||||
LOG.info("DoSomeThing:"+msg);
|
||||
|
||||
//int dataLen = BitConverter.ToInt16(comBuf, 2) - 14;
|
||||
//byte[] DataByte = new byte[dataLen];
|
||||
//Array.ConstrainedCopy(comBuf, 14, DataByte, 0, dataLen);
|
||||
|
||||
//// 0 1 头
|
||||
//// 2 3 长度
|
||||
//// 4 5 厂站号
|
||||
//int stationId = BitConverter.ToInt16(comBuf, 4);
|
||||
//// 6 7 通道号
|
||||
//int channelId = BitConverter.ToInt16(comBuf, 6);
|
||||
//int startAddress = BitConverter.ToInt16(comBuf, 11);
|
||||
//int type = Convert.ToInt16(comBuf[9]);
|
||||
//LogUtil.Info("场站号:" + stationId.ToString() + ", 通道号:" + channelId.ToString() + ", 起始地址:" + startAddress+",type:"+ type);
|
||||
//LogUtil.Info(stationId+":"+string.Join("-", GetRaw(DataByte)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
_____ .______. _________
|
||||
/ \ ____ __| _/\_ |__ __ __ ______ / _____/ ______________ __ ___________
|
||||
/ \ / \ / _ \ / __ | | __ \| | \/ ___/ ______ \_____ \_/ __ \_ __ \ \/ // __ \_ __ \
|
||||
/ Y ( <_> ) /_/ | | \_\ \ | /\___ \ /_____/ / \ ___/| | \/\ /\ ___/| | \/
|
||||
\____|__ /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|
|
||||
\/ \/ \/ \/ \/ \/ \/
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8710
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: modbus-server
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="/home/ruoyi/logs/ruoyi-job" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />:ss} %-5level ${springAppName:-} %thread %logger %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
</configuration>
|
||||
27
pom.xml
27
pom.xml
|
|
@ -71,21 +71,21 @@
|
|||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- SpringBoot 监控客户端 -->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Mybatis 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${spring-boot.mybatis}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Swagger 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 公共资源池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
|
|
@ -160,49 +160,49 @@
|
|||
<artifactId>ruoyi-common-core</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 接口模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-swagger</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 安全模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 权限范围 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datascope</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 日志记录 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 缓存服务 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 系统接口 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-api-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
@ -213,11 +213,12 @@
|
|||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-api</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>modbus-server</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
@ -234,4 +235,4 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>ruoyi-api-system</artifactId>
|
||||
|
||||
<description>
|
||||
|
|
@ -16,13 +16,13 @@
|
|||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<!-- RuoYi Common Core-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,380 @@
|
|||
package com.ruoyi.common.core.utils;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 数字转字节数组工具类
|
||||
*/
|
||||
public class BitConverter {
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的布尔值
|
||||
* @param data 一个布尔值
|
||||
* @return 长度为 1 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(boolean data) {
|
||||
byte[] bytes = new byte[1];
|
||||
bytes[0] = (byte) (data ? 1 : 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 16 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 2 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(short data) {
|
||||
byte[] bytes = new byte[2];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data & 0xff00) >> 8);
|
||||
} else {
|
||||
bytes[1] = (byte) (data & 0xff);
|
||||
bytes[0] = (byte) ((data & 0xff00) >> 8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 Unicode 字符值
|
||||
* @param data 要转换的字符
|
||||
* @return 长度为 2 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(char data) {
|
||||
byte[] bytes = new byte[2];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data);
|
||||
bytes[1] = (byte) (data >> 8);
|
||||
} else {
|
||||
bytes[1] = (byte) (data);
|
||||
bytes[0] = (byte) (data >> 8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 32 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 4 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(int data) {
|
||||
byte[] bytes = new byte[4];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data & 0xff00) >> 8);
|
||||
bytes[2] = (byte) ((data & 0xff0000) >> 16);
|
||||
bytes[3] = (byte) ((data & 0xff000000) >> 24);
|
||||
} else {
|
||||
bytes[3] = (byte) (data & 0xff);
|
||||
bytes[2] = (byte) ((data & 0xff00) >> 8);
|
||||
bytes[1] = (byte) ((data & 0xff0000) >> 16);
|
||||
bytes[0] = (byte) ((data & 0xff000000) >> 24);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的 64 位有符号整数值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 8 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(long data) {
|
||||
byte[] bytes = new byte[8];
|
||||
if (isLittleEndian()) {
|
||||
bytes[0] = (byte) (data & 0xff);
|
||||
bytes[1] = (byte) ((data >> 8) & 0xff);
|
||||
bytes[2] = (byte) ((data >> 16) & 0xff);
|
||||
bytes[3] = (byte) ((data >> 24) & 0xff);
|
||||
bytes[4] = (byte) ((data >> 32) & 0xff);
|
||||
bytes[5] = (byte) ((data >> 40) & 0xff);
|
||||
bytes[6] = (byte) ((data >> 48) & 0xff);
|
||||
bytes[7] = (byte) ((data >> 56) & 0xff);
|
||||
} else {
|
||||
bytes[7] = (byte) (data & 0xff);
|
||||
bytes[6] = (byte) ((data >> 8) & 0xff);
|
||||
bytes[5] = (byte) ((data >> 16) & 0xff);
|
||||
bytes[4] = (byte) ((data >> 24) & 0xff);
|
||||
bytes[3] = (byte) ((data >> 32) & 0xff);
|
||||
bytes[2] = (byte) ((data >> 40) & 0xff);
|
||||
bytes[1] = (byte) ((data >> 48) & 0xff);
|
||||
bytes[0] = (byte) ((data >> 56) & 0xff);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的单精度浮点值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 4 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(float data) {
|
||||
return getBytes(Float.floatToIntBits(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字节数组的形式返回指定的双精度浮点值
|
||||
* @param data 要转换的数字
|
||||
* @return 长度为 8 的字节数组
|
||||
*/
|
||||
public static byte[] getBytes(double data) {
|
||||
return getBytes(Double.doubleToLongBits(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定字符串中的所有字符编码为一个字节序列
|
||||
* @param data 包含要编码的字符的字符串
|
||||
* @return 一个字节数组,包含对指定的字符集进行编码的结果
|
||||
*/
|
||||
public static byte[] getBytes(String data) {
|
||||
return data.getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定字符串中的所有字符编码为一个字节序列
|
||||
* @param data 包含要编码的字符的字符串
|
||||
* @param charsetName 字符集编码
|
||||
* @return 一个字节数组,包含对指定的字符集进行编码的结果
|
||||
*/
|
||||
public static byte[] getBytes(String data, String charsetName) {
|
||||
return data.getBytes(Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的布尔值
|
||||
* @param bytes 字节数组
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean toBoolean(byte[] bytes) {
|
||||
return bytes[0] == 0 ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的一个字节转换来的布尔值
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 布尔值
|
||||
*/
|
||||
public static boolean toBoolean(byte[] bytes, int startIndex) {
|
||||
return toBoolean(copyFrom(bytes, startIndex, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 16 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由两个字节构成的 16 位有符号整数
|
||||
*/
|
||||
public static short toShort(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (short) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
|
||||
} else {
|
||||
return (short) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的两个字节转换来的 16 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由两个字节构成的 16 位有符号整数
|
||||
*/
|
||||
public static short toShort(byte[] bytes, int startIndex) {
|
||||
return toShort(copyFrom(bytes, startIndex, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 Unicode 字符
|
||||
* @param bytes 字节数组
|
||||
* @return 由两个字节构成的字符
|
||||
*/
|
||||
public static char toChar(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (char) ((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
|
||||
} else {
|
||||
return (char) ((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的两个字节转换来的 Unicode 字符
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由两个字节构成的字符
|
||||
*/
|
||||
public static char toChar(byte[] bytes, int startIndex) {
|
||||
return toChar(copyFrom(bytes, startIndex, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 32 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由四个字节构成的 32 位有符号整数
|
||||
*/
|
||||
public static int toInt(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (0xff & bytes[0])
|
||||
| (0xff00 & (bytes[1] << 8))
|
||||
| (0xff0000 & (bytes[2] << 16))
|
||||
| (0xff000000 & (bytes[3] << 24));
|
||||
} else {
|
||||
return (0xff & bytes[3])
|
||||
| (0xff00 & (bytes[2] << 8))
|
||||
| (0xff0000 & (bytes[1] << 16))
|
||||
| (0xff000000 & (bytes[0] << 24));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的四个字节转换来的 32 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由四个字节构成的 32 位有符号整数
|
||||
*/
|
||||
public static int toInt(byte[] bytes, int startIndex) {
|
||||
return toInt(copyFrom(bytes, startIndex, 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的 64 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @return 由八个字节构成的 64 位有符号整数
|
||||
*/
|
||||
public static long toLong(byte[] bytes) {
|
||||
if (isLittleEndian()) {
|
||||
return (0xffL & (long) bytes[0])
|
||||
| (0xff00L & ((long) bytes[1] << 8))
|
||||
| (0xff0000L & ((long) bytes[2] << 16))
|
||||
| (0xff000000L & ((long) bytes[3] << 24))
|
||||
| (0xff00000000L & ((long) bytes[4] << 32))
|
||||
| (0xff0000000000L & ((long) bytes[5] << 40))
|
||||
| (0xff000000000000L & ((long) bytes[6] << 48))
|
||||
| (0xff00000000000000L & ((long) bytes[7] << 56));
|
||||
} else {
|
||||
return (0xffL & (long) bytes[7])
|
||||
| (0xff00L & ((long) bytes[6] << 8))
|
||||
| (0xff0000L & ((long) bytes[5] << 16))
|
||||
| (0xff000000L & ((long) bytes[4] << 24))
|
||||
| (0xff00000000L & ((long) bytes[3] << 32))
|
||||
| (0xff0000000000L & ((long) bytes[2] << 40))
|
||||
| (0xff000000000000L & ((long) bytes[1] << 48))
|
||||
| (0xff00000000000000L & ((long) bytes[0] << 56));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的八个字节转换来的 64 位有符号整数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由八个字节构成的 64 位有符号整数
|
||||
*/
|
||||
public static long toLong(byte[] bytes, int startIndex) {
|
||||
return toLong(copyFrom(bytes, startIndex, 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的单精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @return 由四个字节构成的单精度浮点数
|
||||
*/
|
||||
public static float toFloat(byte[] bytes) {
|
||||
return Float.intBitsToFloat(toInt(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的四个字节转换来的单精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由四个字节构成的单精度浮点数
|
||||
*/
|
||||
public static float toFloat(byte[] bytes, int startIndex) {
|
||||
return Float.intBitsToFloat(toInt(copyFrom(bytes, startIndex, 4)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的双精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @return 由八个字节构成的双精度浮点数
|
||||
*/
|
||||
public static double toDouble(byte[] bytes) {
|
||||
return Double.longBitsToDouble(toLong(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组中的指定的八个字节转换来的双精度浮点数
|
||||
* @param bytes 字节数组
|
||||
* @param startIndex 起始下标
|
||||
* @return 由八个字节构成的双精度浮点数
|
||||
*/
|
||||
public static double toDouble(byte[] bytes, int startIndex) {
|
||||
return Double.longBitsToDouble(toLong(copyFrom(bytes, startIndex, 8)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的字符串
|
||||
* @param bytes 字节数组
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String toString(byte[] bytes) {
|
||||
return new String(bytes, Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回由字节数组转换来的字符串
|
||||
* @param bytes 字节数组
|
||||
* @param charsetName 字符集编码
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String toString(byte[] bytes, String charsetName) {
|
||||
return new String(bytes, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字符串表示形式返回字节数组的内容
|
||||
* @param bytes 字节数组
|
||||
* @return 字符串形式的 <tt>bytes</tt>
|
||||
*/
|
||||
public static String toHexString(byte[] bytes) {
|
||||
if (bytes == null)
|
||||
return "null";
|
||||
int iMax = bytes.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(String.format("%02x", bytes[i] & 0xFF));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* 数组拷贝。
|
||||
* @param src 字节数组。
|
||||
* @param off 起始下标。
|
||||
* @param len 拷贝长度。
|
||||
* @return 指定长度的字节数组。
|
||||
*/
|
||||
private static byte[] copyFrom(byte[] src, int off, int len) {
|
||||
// return Arrays.copyOfRange(src, off, off + len);
|
||||
byte[] bits = new byte[len];
|
||||
for (int i = off, j = 0; i < src.length && j < len; i++, j++) {
|
||||
bits[j] = src[i];
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 CPU Endian 是否为 Little
|
||||
* @return 判断结果
|
||||
*/
|
||||
private static boolean isLittleEndian() {
|
||||
return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7,11 +7,11 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
|||
|
||||
/**
|
||||
* 网关启动程序
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })// 关闭自动配置功能
|
||||
public class RuoYiGatewayApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
|
|
@ -28,4 +28,4 @@ public class RuoYiGatewayApplication
|
|||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,76 +8,76 @@
|
|||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>ruoyi-modules-system</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-modules-system系统模块
|
||||
</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- SpringCloud Ailibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Swagger -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Mysql Connector -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Ruoyi Common Security -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Ruoyi Common Datascope -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datascope</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Ruoyi Common Log -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Ruoyi Common Swagger -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-swagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- RuoYi Common Redis-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
|
@ -101,5 +101,5 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
<?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">
|
||||
<parent>
|
||||
<artifactId>ruoyi-visual</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>2.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hystrix-dashboard</artifactId>
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Ailibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Ailibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-javanica</artifactId>
|
||||
<version>RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.sarnath.hystrix.dashboard;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.cloud.client.SpringCloudApplication;
|
||||
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
|
||||
|
||||
@EnableHystrixDashboard
|
||||
@SpringCloudApplication
|
||||
public class HystrixDashBoardApplication {
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(HystrixDashBoardApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ hystrix-dashboard服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
"____.___._________ \n" +
|
||||
"\\__ | |\\_ ___ \\ \n" +
|
||||
" / | |/ \\ \\/ \n" +
|
||||
" \\____ |\\ \\____\n" +
|
||||
" / ______| \\______ /\n" +
|
||||
" \\/ \\/ ");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
.__ __ .__ .___ .__ ___. .___
|
||||
| |__ ___.__. _______/ |________|__|__ ___ __| _/____ _____| |__\_ |__ _________ _______ __| _/
|
||||
| | < | |/ ___/\ __\_ __ \ \ \/ / ______ / __ |\__ \ / ___/ | \| __ \ / _ \__ \\_ __ \/ __ |
|
||||
| Y \___ |\___ \ | | | | \/ |> < /_____/ / /_/ | / __ \_\___ \| Y \ \_\ ( <_> ) __ \| | \/ /_/ |
|
||||
|___| / ____/____ > |__| |__| |__/__/\_ \ \____ |(____ /____ >___| /___ /\____(____ /__| \____ |
|
||||
\/\/ \/ \/ \/ \/ \/ \/ \/ \/ \/
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8100
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: hystrix-dashboard
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 127.0.0.1:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
<modules>
|
||||
<module>ruoyi-monitor</module>
|
||||
<module>hystrix-dashboard</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-visual</artifactId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue