动作参数取值范围+角色配置权限

This commit is contained in:
2026-04-30 15:16:48 +08:00
parent 0bc6dd7761
commit 05770f7e56
177 changed files with 13913 additions and 9863 deletions

View File

@@ -14,47 +14,6 @@
<description>rczn-common公共模块实体类、工具类、统一响应</description>
<packaging>jar</packaging>
<!-- 若想引用modbus4j需要引入下列repository id:ias-snapshots id:ias-releases 两个 ,使用默认仓库下载,不要使用阿里云仓库-->
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>Infinite Automation Snapshot Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>Infinite Automation Release Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
<!-- ====================== 新增Spring AI 必须的仓库 ====================== -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
</repository>
<!-- ===================================================================== -->
</repositories>
<dependencies>
<!-- 核心依赖 -->
<dependency>
@@ -85,6 +44,11 @@
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- 如果需要 Web 相关类(拦截器等) -->
<dependency>
<groupId>org.springframework</groupId>
@@ -92,41 +56,13 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<!-- springAI框架 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.ai</groupId>-->
<!-- <artifactId>spring-ai-starter-model-openai</artifactId>-->
<!-- <version>1.0.0</version>-->
<!-- </dependency>-->
<!-- Servlet API -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- S7connector 依赖 -->
<dependency>
<groupId>com.github.s7connector</groupId>
<artifactId>s7connector</artifactId>
<version>2.1</version>
</dependency>
<!-- modbus4j -->
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>modbus4j</artifactId>
<version>3.0.3</version> <!-- 或其他稳定版本 -->
</dependency>
<!-- 连接池(工业场景必加,优化多设备连接) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.0</version>
</dependency>
<!-- Spring Context如果需要 @Component 等注解) -->
<dependency>
<groupId>org.springframework</groupId>
@@ -134,9 +70,8 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.testng</groupId>
@@ -154,12 +89,6 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- websocket 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -1,23 +0,0 @@
package com.rczn;
/**
* modbus 指令常量enum
*/
public class ModbusCmdConst {
//下面是指令值:
//就绪
public static final int plc_ready = 10;
//运行
public static final int plc_run = 11;
//暂停
public static final int plc_pause = 12;
//停止
public static final int plc_stop = 10;
//故障复位
public static final int plc_reset_error = 20;
//修改模式
public static final int plc_set_model = 0;
//参数读取:
public static final int plc_read_param = 18;
//
}

View File

@@ -1,40 +0,0 @@
package com.rczn.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步线程池配置用于PLC数据读取的异步执行
*/
@Configuration
@EnableAsync //开启异步任务
public class AsyncThreadPoolConfig {
/**
* 定义PLC专用线程池
*/
@Bean(name = "plcAsyncExecutor")
public Executor plcAsyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数(根据业务调整)
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量
executor.setQueueCapacity(20);
// 线程名前缀(便于日志排查)
executor.setThreadNamePrefix("PLC-Async-");
// 线程空闲超时时间
executor.setKeepAliveSeconds(60);
// 拒绝策略:队列满时由调用线程处理(避免任务丢失)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化线程池
executor.initialize();
return executor;
}
}

View File

@@ -1,14 +0,0 @@
package com.rczn.config;
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();
}
}

View File

@@ -1,7 +1,5 @@
package com.rczn.domain;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
public class BaseBean {
@@ -17,7 +15,6 @@ public class BaseBean {
private String remark;
private LocalDateTime startTime;
private LocalDateTime endTime;
// 无参构造器、全参构造器(同步修改 delSign 类型)

View File

@@ -1,16 +0,0 @@
package com.rczn.exception;
import com.rczn.domain.Result;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(Exception.class)
public Result handleException(Exception e){
e.printStackTrace();
return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage() : "系统异常");
}
}

View File

@@ -9,29 +9,13 @@ import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Map;
@Component
//@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 放行OPTIONS预检请求直接返回200 OK不做任何校验
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
// 手动添加跨域响应头(兜底)
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,PATCH,PUT,DELETE,OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Max-Age", "3600");
return true; // 直接放行,不执行后续拦截逻辑
}
try {
String token = request.getHeader("Authorization");
String[] tokens = token.split(" ");
if(tokens.length>1){
token = tokens[1];
}
Map<String, Object> claims = JwtUtil.parseToken(token);
//保存用户数据到ThreadLocalUtil
ThreadLocalUtil.set(claims);

View File

@@ -1,380 +0,0 @@
package com.rczn.modbus;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.ReadInputRegistersResponse;
import java.util.Map;
/**
* modbus通讯工具类,采用modbus4j实现
*
* @author lxq
* @dependencies modbus4j-3.0.3.jar
* @website https://github.com/infiniteautomation/modbus4j
*/
public class Modbus4jUtils {
/**
* 工厂。
*/
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取master
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getMaster() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost("localhost");
params.setPort(502);
//
// modbusFactory.createRtuMaster(params); //RTU 协议
// modbusFactory.createUdpMaster(params);//UDP 协议
// modbusFactory.createAsciiMaster(params);//ASCII 协议
// 采用 Modbus RTU over TCP/IP第二个参数为 true即 modbusFactory.createTcpMaster(params, true)
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.setTimeout(3000);
master.setRetries(1);
master.init();
return master;
}
/**
* 获取master
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getMaster(String ipAddr,Integer port) throws ModbusInitException {
IpParameters params = new IpParameters();
// params.setHost("localhost");
params.setHost(ipAddr);
// params.setPort(502);
params.setPort(port);
//
// modbusFactory.createRtuMaster(params); //RTU 协议
// modbusFactory.createUdpMaster(params);//UDP 协议
// modbusFactory.createAsciiMaster(params);//ASCII 协议
// 采用 Modbus RTU over TCP/IP第二个参数为 true即 modbusFactory.createTcpMaster(params, true)
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.setTimeout(3000);
master.setRetries(1);
master.init();
return master;
}
/**
* 获取和测试Master对象
* @param ip
* @param port
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getAndTestMaster(String ip, Integer port)
throws ModbusInitException {
ModbusMaster master = getMaster(ip, port);
try {
// 随便读一个确定存在的寄存器
BaseLocator<Number> locator =
BaseLocator.holdingRegister(1, 0, DataType.TWO_BYTE_INT_SIGNED);
Number value = master.getValue(locator);// ⭐ 真正触发 TCP 连接
System.out.println("value:"+value);
} catch (Exception e) {
master.destroy();
throw new RuntimeException("PLC 连接失败:" + ip + ":" + port, e);
}
return master;
}
/**
* 读取[01 Coil Status 0x]类型 开关数据
*
* @param slaveId
* slaveId
* @param offset
* 位置
* @return 读取值
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Boolean readCoilStatus(ModbusMaster modbusMaster,int slaveId, int offset)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 01 Coil Status
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
Boolean value = modbusMaster.getValue(loc);
return value;
}
/**
* 读取[02 Input Status 1x]类型 开关数据
*
* @param slaveId
* @param offset
* @return
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static Boolean readInputStatus(ModbusMaster modbusMaster,int slaveId, int offset)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 02 Input Status
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
Boolean value = modbusMaster.getValue(loc);
return value;
}
/**
* 读取[03 Holding Register类型 2x]模拟量数据
*
* @param slaveId
* slave Id
* @param offset
* 位置
* @param dataType
* 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Number readHoldingRegister(ModbusMaster modbusMaster,int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 03 Holding Register类型数据读取
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
Number value = modbusMaster.getValue(loc);
return value;
}
/**
* 读取[04 Input Registers 3x]类型 模拟量数据
*
* @param modbusMaster
* modbusMaster modbus连接对象
* @param slaveId
* slaveId 设备号
* @param offset
* 位置
* @param dataType
* 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return 返回结果
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Number readInputRegisters(ModbusMaster modbusMaster,int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 04 Input Registers类型数据读取
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
Number value = modbusMaster.getValue(loc);
return value;
}
/**
* 批量读取使用方法
*
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static BatchResults<Integer> batchRead(ModbusMaster modbusMaster,int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
BatchRead<Integer> batch = new BatchRead<Integer>();
batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT));
batch.addLocator(1, BaseLocator.inputStatus(1, 0));
batch.setContiguousRequests(false);
BatchResults<Integer> results = modbusMaster.send(batch);
System.out.println(results.getValue(0));
System.out.println(results.getValue(1));
return results;
}
/**
* 连续读取多个 Holding Register
*/
public static Number[] readHoldingRegisters(
ModbusMaster master,
int slaveId,
int startOffset,
int count,
int dataType)
throws ModbusTransportException, ErrorResponseException {
Number[] values = new Number[count];
for (int i = 0; i < count; i++) {
BaseLocator<Number> locator =
BaseLocator.holdingRegister(slaveId, startOffset + i, dataType);
values[i] = master.getValue(locator);
}
return values;
}
/**
* 连续读取多个 Input Register
*/
public static Number[] readInputRegistersBatch(
ModbusMaster master,
int slaveId,
int startOffset,
int count,
int dataType)
throws ModbusTransportException, ErrorResponseException {
Number[] values = new Number[count];
for (int i = 0; i < count; i++) {
BaseLocator<Number> locator =
BaseLocator.inputRegister(slaveId, startOffset + i, dataType);
values[i] = master.getValue(locator);
}
return values;
}
/**
* 批量读取多个 Holding Register高性能
*/
public static BatchResults<Integer> batchReadHoldingRegisters(
ModbusMaster master,
int slaveId,
int[] offsets,
int dataType)
throws ModbusTransportException, ErrorResponseException {
BatchRead<Integer> batch = new BatchRead<>();
for (int i = 0; i < offsets.length; i++) {
batch.addLocator(i,
BaseLocator.holdingRegister(slaveId, offsets[i], dataType));
}
batch.setContiguousRequests(true); // 连续优化
return master.send(batch);
}
/**
* 混合批量读取
*/
public static BatchResults<Integer> batchReadMixed(
ModbusMaster master,
int slaveId)
throws ModbusTransportException, ErrorResponseException {
BatchRead<Integer> batch = new BatchRead<>();
batch.addLocator(0,
BaseLocator.holdingRegister(slaveId, 0, DataType.FOUR_BYTE_FLOAT));
batch.addLocator(1,
BaseLocator.holdingRegister(slaveId, 2, DataType.TWO_BYTE_INT_SIGNED));
batch.addLocator(2,
BaseLocator.coilStatus(slaveId, 0));
batch.setContiguousRequests(false);
return master.send(batch);
}
public static void close(ModbusMaster master) {
if (master != null) {
master.destroy();
}
}
public static void main(String[] args) {
try {
ModbusMaster master = getMaster("192.178.111.123", 501);
} catch (ModbusInitException e) {
throw new RuntimeException(e);
}
}
/**
* 测试
*
* @param args
*/
public static void main1(String[] args) {
try {
ModbusMaster modbusMaster = getMaster();
// 01测试
// Boolean v011 = readCoilStatus(modbusMaster,1, 0);
// Boolean v012 = readCoilStatus(modbusMaster,1, 1);
// Boolean v013 = readCoilStatus(modbusMaster,1, 6);
// System.out.println("v011:" + v011);
// System.out.println("v012:" + v012);
// System.out.println("v013:" + v013);
// // 02测试
// Boolean v021 = readInputStatus(modbusMaster,1, 0);
// Boolean v022 = readInputStatus(modbusMaster,1, 1);
// Boolean v023 = readInputStatus(modbusMaster,1, 2);
// System.out.println("v021:" + v021);
// System.out.println("v022:" + v022);
// System.out.println("v023:" + v023);
//
// // 03测试
// Number v031 = readHoldingRegister(modbusMaster,1, 1, DataType.FOUR_BYTE_FLOAT);// 注意,float
// Number v032 = readHoldingRegister(modbusMaster,1, 3, DataType.FOUR_BYTE_FLOAT);// 同上
// System.out.println("v031:" + v031);
// System.out.println("v032:" + v032);
// 04测试
// Number v041 = readInputRegisters(modbusMaster,1, 0, DataType.FOUR_BYTE_FLOAT);//
Number v041 = readInputRegisters(modbusMaster,1, 0, DataType.FOUR_BYTE_INT_UNSIGNED);//
Number v042 = readInputRegisters(modbusMaster,1, 2, DataType.FOUR_BYTE_FLOAT);//
System.out.println("v041:" + v041);
System.out.println("v042:" + v042);
Number vff = readHoldingRegister(modbusMaster,1,0,DataType.TWO_BYTE_INT_SIGNED);
System.out.println("vff:" + vff);
Number vff2 = readHoldingRegister(modbusMaster,1,2,DataType.TWO_BYTE_INT_SIGNED);
System.out.println("vff2:" + vff2);
// 批量读取
// batchRead();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,247 +0,0 @@
package com.rczn.modbus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.ModbusResponse;
import com.serotonin.modbus4j.msg.WriteCoilRequest;
import com.serotonin.modbus4j.msg.WriteCoilResponse;
import com.serotonin.modbus4j.msg.WriteCoilsRequest;
import com.serotonin.modbus4j.msg.WriteCoilsResponse;
import com.serotonin.modbus4j.msg.WriteRegisterRequest;
import com.serotonin.modbus4j.msg.WriteRegisterResponse;
import com.serotonin.modbus4j.msg.WriteRegistersRequest;
/**
* modbus4j写入数据
*
* @author xq
*
*/
public class Modbus4jWriteUtils {
static Log log = LogFactory.getLog(Modbus4jWriteUtils.class);
/**
* 工厂。
*/
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取tcpMaster
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getMaster() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost("localhost");
params.setPort(502);
ModbusMaster tcpMaster = modbusFactory.createTcpMaster(params, false);
tcpMaster.init();
return tcpMaster;
}
/**
* 获取master
*
* @return
* @throws ModbusInitException
*/
public static ModbusMaster getMaster(String ipAddr,Integer port) throws ModbusInitException {
IpParameters params = new IpParameters();
// params.setHost("localhost");
params.setHost(ipAddr);
// params.setPort(502);
params.setPort(port);
//
// modbusFactory.createRtuMaster(params); //RTU 协议
// modbusFactory.createUdpMaster(params);//UDP 协议
// modbusFactory.createAsciiMaster(params);//ASCII 协议
// 采用 Modbus RTU over TCP/IP第二个参数为 true即 modbusFactory.createTcpMaster(params, true)
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.init();
return master;
}
/**
* 写 [01 Coil Status(0x)]写一个 function ID = 5
*
* @param slaveId
* slave的ID
* @param writeOffset
* 位置
* @param writeValue
* 值
* @return 是否写入成功
* @throws ModbusTransportException
* @throws ModbusInitException
*/
public static boolean writeCoil(ModbusMaster tcpMaster,int slaveId, int writeOffset, boolean writeValue)
throws ModbusTransportException, ModbusInitException {
// 获取master
// ModbusMaster tcpMaster = getMaster();
// 创建请求
WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
// 发送请求并获取响应对象
WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/**
* 写[01 Coil Status(0x)] 写多个 function ID = 15
*
* @param slaveId
* slaveId
* @param startOffset
* 开始位置
* @param bdata
* 写入的数据
* @return 是否写入成功
* @throws ModbusTransportException
* @throws ModbusInitException
*/
public static boolean writeCoils(ModbusMaster tcpMaster,int slaveId, int startOffset, boolean[] bdata)
throws ModbusTransportException, ModbusInitException {
// 获取master
// ModbusMaster tcpMaster = getMaster();
// 创建请求
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
// 发送请求并获取响应对象
WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/***
* 写[03 Holding Register(4x)] 写一个 function ID = 6
*
* @param slaveId
* @param writeOffset
* @param writeValue
* @return
* @throws ModbusTransportException
* @throws ModbusInitException
*/
public static boolean writeRegister(ModbusMaster tcpMaster,int slaveId, int writeOffset, short writeValue)
throws ModbusTransportException, ModbusInitException {
// 获取master
// ModbusMaster tcpMaster = getMaster();
// 创建请求对象
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
if (response.isException()) {
log.error(response.getExceptionMessage());
return false;
} else {
return true;
}
}
/**
*
* 写入[03 Holding Register(4x)]写多个 function ID=16
*
* @param slaveId
* modbus的slaveID
* @param startOffset
* 起始位置偏移量值
* @param sdata
* 写入的数据
* @return 返回是否写入成功
* @throws ModbusTransportException
* @throws ModbusInitException
*/
public static boolean writeRegisters(ModbusMaster tcpMaster,int slaveId, int startOffset, short[] sdata)
throws ModbusTransportException, ModbusInitException {
// 获取master
// ModbusMaster tcpMaster = getMaster();
// 创建请求对象
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
// 发送请求并获取响应对象
ModbusResponse response = tcpMaster.send(request);
if (response.isException()) {
log.error(response.getExceptionMessage());
return false;
} else {
return true;
}
}
/**
* 写入数字类型的模拟量(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long
*
* @param slaveId
* @param offset
* @param value
* 写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long
* @param dataType
* ,com.serotonin.modbus4j.code.DataType
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static void writeHoldingRegister(ModbusMaster tcpMaster,int slaveId, int offset, Number value, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 获取master
// ModbusMaster tcpMaster = getMaster();
// 类型
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
tcpMaster.setValue(locator, value);
}
public static void main1(String[] args) {
try {
ModbusMaster modbusMaster = getMaster();
//@formatter:off
// 测试01
// boolean t01 = writeCoil(1, 0, true);
// System.out.println("T01:" + t01);
// 测试02
// boolean t02 = writeCoils(1, 0, new boolean[] { true, false, true });
// System.out.println("T02:" + t02);
// 测试03
// short v = -3;
// boolean t03 = writeRegister(1, 0, v);
// System.out.println("T03:" + t03);
// 测试04
// boolean t04 = writeRegisters(1, 0, new short[] { -3, 3, 9 });
// System.out.println("t04:" + t04);
writeRegister(modbusMaster,1,2,(short) 3);
//写模拟量
writeHoldingRegister(modbusMaster,1,0, 999, DataType.TWO_BYTE_INT_SIGNED);
//@formatter:on
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,56 +0,0 @@
package com.rczn.plc;
import com.github.s7connector.api.annotation.S7Variable;
import com.github.s7connector.impl.utils.S7Type;
import lombok.Data;
@Data
public class PLCData {
/**
* type是这个点位在PLC中设置的类型源码会解析其长度
* byteOffset对应PLC偏移量中的整数部分;
* bitOffset指偏移量的小数部分bitOffset指第几个bit.
* byteOffset和bitOffset 也可理解为返回的byte[]中第byteOffset到bitOffset
*/
@S7Variable(type= S7Type.BOOL,byteOffset = 0,bitOffset = 0)
public Boolean data10;//bool型的值不要用private
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 1)
public Boolean data11;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 2)
public Boolean data12;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 3)
public Boolean data13;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 4)
public Boolean data14;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 5)
public Boolean data15;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 6)
public Boolean data16;
@S7Variable(type=S7Type.BOOL,byteOffset = 0,bitOffset = 7)
public Boolean data17;
@S7Variable(type=S7Type.BYTE,byteOffset = 1,bitOffset = 0)
public Byte dataB1;
@S7Variable(type=S7Type.STRING,byteOffset = 2,bitOffset = 0)
public String dataS1;
@S7Variable(type=S7Type.STRING,byteOffset = 258,bitOffset = 40)
public String dataS2;
@S7Variable(type=S7Type.STRING,byteOffset = 514,bitOffset = 40)
public String dataS3;
@S7Variable(type=S7Type.STRING,byteOffset = 770)
public String dataS4;
}

View File

@@ -1,102 +0,0 @@
package com.rczn.plc;
import com.github.s7connector.api.DaveArea;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.factory.S7ConnectorFactory;
import com.github.s7connector.impl.serializer.converter.StringConverter;
import java.util.Scanner;
/**
* @author 木春
* @className S7PlcClient.java
* @Form no
* @Description ToDo
* @createTime 2022 年 11 月 18 日 21 21:40:49
**/
public class S7PlcClient {
public static void main(String[] args) throws InterruptedException {
//初始化 创建一个链接对象
S7Connector connector =
S7ConnectorFactory
.buildTCPConnector()
.withHost("192.168.0.105") //
.withRack(0) //架机号 可选
.withSlot(1) //插槽号 可选
.build();
// 写数据线程
new Thread(new Runnable() {
@Override
public void run() {
java_write_plc(connector);//写数据
}
}).start();
// 读数据线程
new Thread(new Runnable() {
@Override
public void run() {
java_read_plc(connector);//调用读取数据方法
}
}).start();
}
//读取数据
public static void java_read_plc(S7Connector connector) {
/* 读取数据方法*/
byte[] PlcData = null;
String str = null;
String str1 = null;
StringConverter converter = null;
String extract1 = null;
//循环读取
while (true) {
PlcData = connector.read(
DaveArea.DB, //选择区块
1, // 区块编号
255, //长度
260); //偏移地址
converter = new StringConverter();//字符串转换
//将读取到的数据转换成字符串类型 读取到的数据转换后
extract1 = converter.extract(String.class, PlcData, 0, 0);
//比对两次数据是否一样 不一样就打印
if (!(extract1.equals(str1))) {
System.out.println(" ");
System.out.println("接收plc的数据为 = " + extract1);
str1 = extract1;
//plc发送 qu 就结束退出程序
if (extract1.equals("qu")) {
break;
}
}
}
}
//发送数据
public static void java_write_plc(S7Connector connector) {
while (true) {
/*发送数据*/
String data = null;
// byte[] bytes = null;
String input = null;
Scanner sc = new Scanner(System.in);
System.out.print("请输入要发送的数据: ");
input = sc.nextLine();
String data_Baotou = " ";//数据包头 两个空格
String data_tail = " ";//包尾 六个空格
data = data_Baotou + input + data_tail;//发送的数据
byte[] bytes = new byte[input.length()];
bytes = data.getBytes();//转字节
System.out.println("发送的字节长度 = " + bytes.length);//发送的字节长度
connector.write(DaveArea.DB, 1, 4, bytes);//写入到 DB1 偏移量为4的变量
System.out.println("发送的数据为 = " + data);
}
}
}

View File

@@ -1,131 +0,0 @@
package com.rczn.plc;
import com.github.s7connector.api.DaveArea;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.S7Serializer;
import com.github.s7connector.api.factory.S7ConnectorFactory;
import com.github.s7connector.api.factory.S7SerializerFactory;
import java.io.IOException;
public class S7PlcCommun {
/**
* 初始化PLC连接
*/
public S7Connector initConnect(){
//PLC地址
String ipAddress = "192.168.1.2";
//默认端口
Integer port = 102;
S7Connector s7Connector = S7ConnectorFactory
.buildTCPConnector()
.withHost(ipAddress)
.withPort(port)
.withTimeout(10000) //连接超时时间
.withRack(0)
.withSlot(1)
.build();
S7Serializer s7Serializer2L = S7SerializerFactory.buildSerializer(s7Connector);
return s7Connector;
}
/**
* 读取PLC中的数据
*
**/
public void readPlcData() {
S7Connector s7Connector = initConnect();
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB地址若plc中是DB1000则填1000
//第三个参数:数据长度, <=plc中两个偏移量的间隔当前偏移量为1000下一个地址偏移量为1100则长度可填 0-1000
//第四个参数:偏移量
byte[] barcodeByte = s7Connector.read(DaveArea.DB, 1000, 2, 0);
//由于当前PLC地址中保存的数据类型是字符串类型所以直接将byte[] 转成string即可
String barcode =byteToHex(barcodeByte);
System.out.println(barcode);
try {
s7Connector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* byte数组转hex
* @param bytes
* @return
*/
public static String byteToHex(byte[] bytes){
String strHex = "";
StringBuilder sb = new StringBuilder("");
for (int n = 0; n < bytes.length; n++) {
strHex = Integer.toHexString(bytes[n] & 0xFF);
sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示位数不够高位补0
}
return sb.toString().trim();
}
/**
* 向PLC中写数据
*
**/
public void writePlcData() {
S7Connector s7Connector = initConnect();
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB地址若plc中是DB1000则填1000
//第三个参数:偏移量
//第四个参数:写入的数据 二进制数组byte[],由于plc中地址的数据类型是word所以写入的数据必须是4位的16进制数据
s7Connector.write(DaveArea.DB,1000, 4,hexStringToBytes("0001"));
try {
s7Connector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将16进制字符串转成二进制数组
* @param hexString
* @return
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* 将单个16进制字符转换为对应的字节值核心补充方法
* @param c 16进制字符0-9、A-F
* @return 对应的字节值0-15
*/
private static byte charToByte(char c) {
// 0-9 对应 48-57
if (c >= '0' && c <= '9') {
return (byte) (c - '0');
}
// A-F 对应 65-70
else if (c >= 'A' && c <= 'F') {
return (byte) (c - 'A' + 10);
}
// 非法字符抛出异常(避免静默错误)
else {
throw new IllegalArgumentException("非法的16进制字符" + c);
}
}
}

View File

@@ -1,220 +0,0 @@
package com.rczn.plc_common;
import com.github.s7connector.api.DaveArea;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.factory.S7ConnectorFactory;
import com.github.s7connector.impl.serializer.converter.BitConverter;
import com.github.s7connector.impl.serializer.converter.IntegerConverter;
import com.github.s7connector.impl.serializer.converter.RealConverter;
import com.github.s7connector.impl.serializer.converter.StringConverter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class S7ConnectorPLC {
public S7Connector initConnect(String ipAddress,int port,int rack,int slot) {
//默认端口
// 创建与PLC的链接
S7Connector connector = S7ConnectorFactory.buildTCPConnector()
.withHost(ipAddress)
.withPort(port)
.withRack(0) // 架机号 可选,建议选择,可能会报错
.withSlot(2) // 插槽号 可选,建议选择,可能会报错
.build();
return connector;
}
public static void main1(String[] args) {
S7ConnectorPLC s7ConnectorPLC = new S7ConnectorPLC();
S7Connector connector = s7ConnectorPLC.initConnect("192.168.110.123", 102, 0, 2);
// s7ConnectorPLC.Java_To_write(connector);
s7ConnectorPLC.Cyclic_readT(connector);
}
//Int类型的封装类 用来转义
private static IntegerConverter intCon = new IntegerConverter();
//String...
private static StringConverter strCon = new StringConverter();
//Boolean...
private static BitConverter boolCon = new BitConverter();
//real实数浮点...
private static RealConverter realCon = new RealConverter();
//获取到的数据存储
public boolean in_bool = false;//bool
public Integer in_int = null;//int
public String in_String = "";//string
public double in_real = 0.0;//real
public void Cyclic_read(S7Connector connector) {
byte[] PlcData = null;
//读取bool型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
1, // 数据值长度 boolean长度1
0); // 开始位置偏移量
Boolean extract_bool = boolCon.extract(Boolean.class, PlcData, 0, 0);//接收转换的数值
in_bool = extract_bool;//赋值给全局变量
// 读取整型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
2, // 数据值长度 int长度2
2); // 开始位置 偏移量
Integer extract_int = intCon.extract(Integer.class, PlcData, 0, 0);
in_int = extract_int;
// 读取字符串型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
16, // 数据值长度 String最小3 随值长度增加
4); // 开始位置偏移量
String extract_string = strCon.extract(String.class, PlcData, 0, 0);
in_String = extract_string;
// 读取小数型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
4, // 数据值长度 double长度4
260); //偏移量
Double num1 = realCon.extract(Double.class, PlcData, 0, 0);
/* BigDecimal bd1 = new BigDecimal(num1);
System.out.println("转换real浮点= " + bd1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());*/
in_real = num1;
try {
connector.close();//关闭链接
} catch (IOException e) {
e.printStackTrace();
}
}
public void Cyclic_readT(S7Connector connector) {
byte[] PlcData = null;
//读取bool型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
1, // 数据值长度 boolean长度1
0); // 开始位置偏移量
Boolean extract_bool = boolCon.extract(Boolean.class, PlcData, 0, 0);//接收转换的数值
in_bool = extract_bool;//赋值给全局变量
// 读取整型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
2, // 数据值长度 int长度2
2); // 开始位置 偏移量
Integer extract_int = intCon.extract(Integer.class, PlcData, 0, 0);
in_int = extract_int;
// 读取字符串型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
16, // 数据值长度 String最小3 随值长度增加
4); // 开始位置偏移量
String extract_string = strCon.extract(String.class, PlcData, 0, 0);
in_String = extract_string;
// 读取小数型
PlcData = connector.read(DaveArea.DB, // 选择数据区块
5, // 区块编号
4, // 数据值长度 double长度4
260); //偏移量
Double num1 = realCon.extract(Double.class, PlcData, 0, 0);
/* BigDecimal bd1 = new BigDecimal(num1);
System.out.println("转换real浮点= " + bd1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());*/
in_real = num1;
try {
connector.close();//关闭链接
} catch (IOException e) {
e.printStackTrace();
}
}
public void Java_To_write(S7Connector connector) {
byte[] bytes = null;
boolean out_boolen = true;
// bytes = S7Type.BOOL;
// connector.write(DaveArea.DB, 5, 264, bytes);
// 向plc中写int整型数据
// 向PLC中写短整型(2字节对应PLC INT类型)数据
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB块地址若plc中是DB1000则填1000
//第三个参数:偏移量
//第四个参数:写入的数据 二进制数组byte[]
short out_int = 15;
bytes = ByteBuffer.allocate(2).putShort(out_int).array();
connector.write(DaveArea.DB, 5, 266, bytes);
// 向PLC中写整型(4字节对应PLC DINT类型)数据
int data=15;
bytes = ByteBuffer.allocate(4).putInt(data).array();
connector.write(DaveArea.DB,5, 528,bytes);
// 写入字符串
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB块地址若plc中是DB1000则填1000
//第三个参数:偏移量
//第四个参数:写入的数据 二进制数组byte[] ,总长度为10的话有效数据只能是10-8第一位代表总长第二位代表有效数据字节
String out_string = "helloPlc";
int writeStrLength = 10;//地址块大小
byte[] writeBytes = new byte[writeStrLength];
writeBytes[0] = (byte) writeStrLength;//写入本字符串块总宽度
out_string = out_string.trim();//清除掉两边的空串
int availableEffectCharLength = 0;//有效字符数控制
if (out_string.length() > writeStrLength - 2) {//>writeStrLength-2 截断到最大有效数据位
availableEffectCharLength = writeStrLength - 2;
} else {//<=writeStrLength-2
availableEffectCharLength = out_string.length();
}
writeBytes[1] = (byte) availableEffectCharLength;//写入有效字节数
byte[] strBytes = out_string.getBytes(StandardCharsets.US_ASCII);
for (int i = 0; i < availableEffectCharLength; i++) {
writeBytes[i + 2] = strBytes[i];
}
connector.write(DaveArea.DB, 5, 268, writeBytes);
/**
* 写入PLC中的浮点型数据
* java float : plc Real 4 字节
* java double : plc LReal 8 字节
**/
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB块地址若plc中是DB1000则填1000
//第三个参数:偏移量
//第四个参数:写入的数据 二进制数组byte[]
float out_real= 5.54F;
bytes = ByteBuffer.allocate(4).putFloat(out_real).array();
connector.write(DaveArea.DB,5, 524,bytes);
/**
* 写入PLC中的浮点型LREAL(java中是double)数据
* java float : plc Real 4 字节
* java double : plc LReal 8 字节
**/
//第一个参数DaveArea.DB 表示读取PLC的地址区域为DB
//第二个参数DB块地址若plc中是DB1000则填1000
//第三个参数:偏移量
//第四个参数:写入的数据 二进制数组byte[]
float out_Lreal= 15.56F;
bytes = ByteBuffer.allocate(8).putDouble(out_Lreal).array();
connector.write(DaveArea.DB,5, 532,bytes);
try {
connector.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -1,22 +0,0 @@
package com.rczn.task;
import java.time.LocalDateTime;
public class TestCrc {
public static void main(String[] args) throws CloneNotSupportedException {
LocalDateTime localDateTime = LocalDateTime.now();
Video v1 = new Video("123", localDateTime);
Video v2 = (Video) v1.clone();
System.out.println(v1);
System.out.println(v2);
System.out.println("===================================");
localDateTime.minusDays(10);
v1.setName("vvvvvv");
System.out.println(v1);
System.out.println(v2);
System.out.println("===============12312312312====================");
}
}

View File

@@ -1,17 +0,0 @@
package com.rczn.task;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TestTask {
Log log = LogFactory.getLog(TestTask.class);
@Scheduled(cron = "0 0/30 * * * ?")
public void test() {
System.out.println("This is a test task.");
log.info("This is a test task.");
}
}

View File

@@ -1,46 +0,0 @@
package com.rczn.task;
import java.time.LocalDateTime;
public class Video implements Cloneable{
private String name;
private LocalDateTime createTime;
public Video() {
}
public Video(String name, LocalDateTime createTime) {
this.name = name;
this.createTime = createTime;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createTime=" + createTime +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
}

View File

@@ -1,22 +0,0 @@
package com.rczn.utils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class BeanFactoryUtils implements BeanFactoryPostProcessor {
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
BeanFactoryUtils.beanFactory = factory;
}
// 获取Bean
public static <T> T getBean(Class<T> clazz) {
return beanFactory.getBean(clazz);
}
}

View File

@@ -27,11 +27,4 @@ public class JwtUtil {
.asMap();
}
public static void main(String[] args) {
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsicGVybWlzc2lvbnMiOlsiMTExMSIsIjIyMiIsIjU1NSJdLCJpZCI6MywidXNlcm5hbWUiOiJzdHJpbmcifSwiZXhwIjoxNzc2NzE2NzAyfQ.ynjs9Ys0CxoZjRstjz3mjr3c6NYMFiV3MmTGQYpJmKQ";//genToken(null);
System.out.println(token);
Map<String, Object> claims = parseToken(token);
System.out.println(claims);
}
}

View File

@@ -1,75 +0,0 @@
package com.rczn.websocket;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
Log log = LogFactory.getLog(WebSocketServer.class);
//springboot自带json转换器
private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
//存放每个连接对象
private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>();
private Session session;
private Long userId;
/**
* 连接建立成功调用的方法
* @param session
* @param userId
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Long userId) {
this.session = session;
this.userId = userId;
webSockets.add(this);
log.info("有新连接加入!当前在线人数为" + webSockets.size());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(){
webSockets.remove(this);
log.info("有连接关闭!当前在线人数为" + webSockets.size());
}
/**
* 收到客户端消息后调用的方法
* @OnMessage
* @param message 客户端发送过来的消息
* @param session
*/
@OnMessage
public void onMessage(String message,Session session){
log.info("收到来自客户端的消息:" + message);
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误:"+error.getStackTrace());
}
/**
* 发送消息
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
}

View File

@@ -1,12 +1 @@
##spring.application.name=rczn-common
#spring:
# ai:
# openai:
# api-key: "sk-b2b55f0bc7e140668e0326c0cc7a86df" #sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# base-url: "https://api.deepseek.com"
# chat:
# options:
# model: "deepseek-chat"
# # 关键:给语音模型也配置上,就不报错了
# speech:
# api-key: "sk-b2b55f0bc7e140668e0326c0cc7a86df"

View File

@@ -1,13 +0,0 @@
package com.rczn.rczncommon;
//import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class RcznCommonApplicationTests {
// @Test
void contextLoads() {
}
}