1. 新增数据源oracle,已在application.yml中配置
2. 新增任务状态类,未来将在切换任务状态中使用 3. 新增ProtectLevel实体类,用来存储Template对应的三种防护等级数据 4. Task实体类中删除protectObjectIds,因为MySQL表结构发生修改 5. TaskController新增audit和delete路由,用以审核和删除Task 6. TemplateMapper新增newProtectLevel方法 7.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.realtime.protection;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.realtime.protection.configuration.entity.defense.template;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ProtectLevel {
|
||||
private Integer protectLevelId;
|
||||
|
||||
private Boolean hasProtectObjectIP = false;
|
||||
|
||||
private Boolean hasProtectObjectPort = false;
|
||||
|
||||
private Boolean hasPeerIP = false;
|
||||
|
||||
private Boolean hasPeerPort = false;
|
||||
|
||||
private Boolean hasProtocol = false;
|
||||
|
||||
private Boolean hasURL = false;
|
||||
|
||||
private Boolean hasDNS = false;
|
||||
}
|
||||
@@ -15,30 +15,31 @@ public class Template {
|
||||
@NotNull(message = "template name should not be empty.")
|
||||
private String templateName;
|
||||
|
||||
@JsonProperty("template_elements")
|
||||
private List<String> templateElements;
|
||||
|
||||
@JsonProperty("default_op")
|
||||
@NotNull(message = "default_op should not be empty.")
|
||||
private String defaultOp;
|
||||
|
||||
@JsonProperty("template_running_tasks")
|
||||
private Integer templateRunningTasks;
|
||||
|
||||
@JsonProperty("template_used")
|
||||
private Integer templateUsedTimes;
|
||||
|
||||
private Boolean hasProtectObjectIP;
|
||||
@JsonProperty("source_system")
|
||||
@NotNull(message = "source_system should not be empty. ")
|
||||
private String sourceSystem;
|
||||
|
||||
private Boolean hasProtectObjectPort;
|
||||
@JsonProperty("protect_level_low")
|
||||
@NotNull(message = "protect_level_low should not be empty. ")
|
||||
private ProtectLevel protectLevelLow;
|
||||
|
||||
private Boolean hasPeerIP;
|
||||
@JsonProperty("protect_level_medium")
|
||||
@NotNull(message = "protect_level_medium should not be empty. ")
|
||||
private ProtectLevel protectLevelMedium;
|
||||
|
||||
private Boolean hasPeerPort;
|
||||
@JsonProperty("protect_level_high")
|
||||
@NotNull(message = "protect_level_high should not be empty. ")
|
||||
private ProtectLevel protectLevelHigh;
|
||||
|
||||
private Boolean hasProtocol;
|
||||
private Integer createUserId;
|
||||
|
||||
private Boolean hasURL;
|
||||
private String createUsername;
|
||||
|
||||
private Boolean hasDNS;
|
||||
private String createDepart;
|
||||
}
|
||||
|
||||
@@ -55,9 +55,6 @@ public class Task {
|
||||
@JsonProperty("dynamic_rule_ids")
|
||||
private List<Integer> dynamicRuleIds;
|
||||
|
||||
@JsonProperty("protect_object_ids")
|
||||
private List<Integer> protectObjectIds;
|
||||
|
||||
@JsonProperty("task_status")
|
||||
private Integer taskStatus;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.realtime.protection.configuration.utils;
|
||||
package com.realtime.protection.configuration.utils.status;
|
||||
|
||||
public class AuditStatusValidator {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.realtime.protection.configuration.utils.status;
|
||||
|
||||
import com.realtime.protection.configuration.utils.status.state.State;
|
||||
|
||||
public class StatusChanger {
|
||||
|
||||
private final State state;
|
||||
|
||||
public StatusChanger(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public static StatusChanger setOriginal(State original) {
|
||||
return new StatusChanger(original);
|
||||
}
|
||||
|
||||
public Boolean changeState(State newState) {
|
||||
return this.state.handle(newState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.realtime.protection.configuration.utils.status.state;
|
||||
|
||||
public class PauseState implements State {
|
||||
@Override
|
||||
public Boolean handle(State newState) {
|
||||
if (!(newState instanceof RunningState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return handleRun();
|
||||
}
|
||||
|
||||
private Boolean handleRun() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.realtime.protection.configuration.utils.status.state;
|
||||
|
||||
public class RunningState implements State {
|
||||
@Override
|
||||
public Boolean handle(State newState) {
|
||||
if (newState instanceof RunningState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newState instanceof PauseState) {
|
||||
return handlePause();
|
||||
}
|
||||
|
||||
if (newState instanceof StopState) {
|
||||
return handleStop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean handlePause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean handleStop() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.realtime.protection.configuration.utils.status.state;
|
||||
|
||||
public interface State {
|
||||
|
||||
Boolean handle(State newState);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.realtime.protection.configuration.utils.status.state;
|
||||
|
||||
public class StopState implements State {
|
||||
|
||||
@Override
|
||||
public Boolean handle(State newState) {
|
||||
if (!(newState instanceof RunningState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return handleRun();
|
||||
}
|
||||
|
||||
public Boolean handleRun() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,9 @@ public class ProtectObjectController {
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
public ResponseResult uploadFile(MultipartFile uploadFile) throws IOException {
|
||||
public ResponseResult uploadFile(
|
||||
@NotNull(message = "uploadFile cannot be null") MultipartFile uploadFile
|
||||
) throws IOException {
|
||||
EasyExcel.read(uploadFile.getInputStream(), ProtectObject.class,
|
||||
new ProjectObjectDataListener(protectObjectService)).sheet().doRead();
|
||||
return ResponseResult.ok();
|
||||
@@ -52,11 +54,12 @@ public class ProtectObjectController {
|
||||
public void downloadTemplate(HttpServletResponse response) throws IOException {
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
String fileName = URLEncoder.encode("防护对象", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
||||
String fileName = URLEncoder.encode("防护对象上传模板", StandardCharsets.UTF_8)
|
||||
.replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
||||
|
||||
EasyExcel.write(response.getOutputStream(), ProtectObject.class)
|
||||
.sheet("防护对象")
|
||||
.sheet("防护对象上传模板")
|
||||
.doWrite(List.of());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@ package com.realtime.protection.server.defense.object;
|
||||
|
||||
import com.alibaba.excel.util.ListUtils;
|
||||
import com.realtime.protection.configuration.entity.defense.object.ProtectObject;
|
||||
import com.realtime.protection.configuration.utils.AuditStatusValidator;
|
||||
import com.realtime.protection.configuration.utils.status.AuditStatusValidator;
|
||||
import com.realtime.protection.configuration.utils.SqlSessionWrapper;
|
||||
import org.apache.ibatis.exceptions.PersistenceException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -12,12 +11,12 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ProtectObjectService {
|
||||
private final ProtectObjectMapper protectObjectMapper;
|
||||
private final SqlSessionWrapper sqlSessionWrapper;
|
||||
private static final Integer batchSize = 100;
|
||||
|
||||
public ProtectObjectService(ProtectObjectMapper protectObjectMapper, SqlSessionWrapper sqlSessionWrapper) {
|
||||
this.protectObjectMapper = protectObjectMapper;
|
||||
@@ -39,10 +38,10 @@ public class ProtectObjectService {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ProtectObject> protectObjectBatch = ListUtils.newArrayListWithExpectedSize(100);
|
||||
List<ProtectObject> protectObjectBatch = ListUtils.newArrayListWithExpectedSize(batchSize);
|
||||
for (ProtectObject protectObject : protectObjectList) {
|
||||
protectObjectBatch.add(protectObject);
|
||||
if (protectObjectBatch.size() < 100) {
|
||||
if (protectObjectBatch.size() < batchSize) {
|
||||
continue;
|
||||
}
|
||||
mapper.newProtectObjects(protectObjectBatch);
|
||||
@@ -81,10 +80,10 @@ public class ProtectObjectService {
|
||||
boolean success = true;
|
||||
Integer result;
|
||||
|
||||
List<Integer> protectObjectBatch = ListUtils.newArrayListWithExpectedSize(100);
|
||||
List<Integer> protectObjectBatch = ListUtils.newArrayListWithExpectedSize(batchSize);
|
||||
for (Integer protectObjectId : list) {
|
||||
protectObjectBatch.add(protectObjectId);
|
||||
if (protectObjectBatch.size() < 100) {
|
||||
if (protectObjectBatch.size() < batchSize) {
|
||||
continue;
|
||||
}
|
||||
mapper.deleteProtectObjects(protectObjectBatch);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.realtime.protection.server.defense.template;
|
||||
|
||||
import com.realtime.protection.configuration.entity.defense.template.ProtectLevel;
|
||||
import com.realtime.protection.configuration.entity.defense.template.Template;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@@ -10,10 +11,14 @@ import java.util.List;
|
||||
public interface TemplateMapper {
|
||||
void newTemplate(@Param("template") Template template);
|
||||
|
||||
void newProtectLevel(@Param("level") ProtectLevel protectLevel);
|
||||
|
||||
List<Template> queryTemplates(@Param("template_name") String templateName,
|
||||
@Param("page") Integer page,
|
||||
@Param("page_size") Integer pageSize);
|
||||
|
||||
ProtectLevel queryProtectLevel(@Param("level_id") Integer protectLevelId);
|
||||
|
||||
Boolean updateTemplateInformation(@Param("template") Template template);
|
||||
|
||||
void countTemplateRunningTasks(@Param("template_id") Integer templateId);
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.realtime.protection.server.defense.template;
|
||||
|
||||
import com.realtime.protection.configuration.entity.defense.template.Template;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.beans.Transient;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -11,18 +13,15 @@ public class TemplateService {
|
||||
|
||||
private final TemplateMapper templateMapper;
|
||||
|
||||
private final String[] permittedOps = new String[]{"阻断", "清洗", "篡改", "反制"};
|
||||
|
||||
public TemplateService(TemplateMapper templateMapper) {
|
||||
this.templateMapper = templateMapper;
|
||||
}
|
||||
|
||||
public Integer newTemplate(Template template) throws IllegalArgumentException {
|
||||
if (!Arrays.asList(permittedOps).contains(template.getDefaultOp())) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
setTemplateElements(template);
|
||||
@Transactional
|
||||
public Integer newTemplate(Template template) {
|
||||
templateMapper.newProtectLevel(template.getProtectLevelLow());
|
||||
templateMapper.newProtectLevel(template.getProtectLevelMedium());
|
||||
templateMapper.newProtectLevel(template.getProtectLevelHigh());
|
||||
|
||||
templateMapper.newTemplate(template);
|
||||
|
||||
@@ -37,28 +36,11 @@ public class TemplateService {
|
||||
}
|
||||
|
||||
public Boolean updateTemplate(Integer templateId, Template template) {
|
||||
setTemplateElements(template);
|
||||
template.setTemplateId(templateId);
|
||||
|
||||
return templateMapper.updateTemplateInformation(template);
|
||||
}
|
||||
|
||||
private void setTemplateElements(Template template) {
|
||||
for (String choice : template.getTemplateElements()) {
|
||||
switch (choice) {
|
||||
case "防护对象IP" -> template.setHasProtectObjectIP(true);
|
||||
case "防护对象端口" -> template.setHasProtectObjectPort(true);
|
||||
case "对端IP" -> template.setHasPeerIP(true);
|
||||
case "对端端口" -> template.setHasPeerPort(true);
|
||||
case "协议" -> template.setHasProtocol(true);
|
||||
case "URL" -> template.setHasURL(true);
|
||||
case "DNS" -> template.setHasDNS(true);
|
||||
|
||||
default -> throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean addTemplateUsedTimes(Integer templateId, Integer addTimes) {
|
||||
return templateMapper.addTemplateUsedTimes(templateId, addTimes);
|
||||
}
|
||||
|
||||
@@ -65,17 +65,28 @@ public class TaskController {
|
||||
.setData("task_start_time", task.getTaskStartTime())
|
||||
.setData("task_end_time", task.getTaskEndTime())
|
||||
.setData("task_static_rule_ids", task.getStaticRuleIds())
|
||||
.setData("task_dynamic_rule_ids", task.getDynamicRuleIds())
|
||||
.setData("task_protect_object_ids", task.getProtectObjectIds());
|
||||
.setData("task_dynamic_rule_ids", task.getDynamicRuleIds());
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/update")
|
||||
public ResponseResult updateTask(@PathVariable("id") @Min(1) Integer taskId, @RequestBody @Valid Task task) {
|
||||
task.setTaskId(taskId);
|
||||
taskService.updateTask(task);
|
||||
|
||||
return ResponseResult.ok()
|
||||
.setData("task_id", taskId)
|
||||
.setData("success", true);
|
||||
.setData("success", taskService.updateTask(task));
|
||||
}
|
||||
|
||||
@GetMapping("/{taskId}/{auditStatus}/audit")
|
||||
public ResponseResult changeTaskAuditStatus(@PathVariable Integer auditStatus, @PathVariable Integer taskId) {
|
||||
return ResponseResult.ok()
|
||||
.setData("task_id", taskId)
|
||||
.setData("success", taskService.changeTaskAuditStatus(taskId, auditStatus));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/delete")
|
||||
public ResponseResult deleteTask(@PathVariable("id") Integer taskId) {
|
||||
return ResponseResult.ok()
|
||||
.setData("task_id", taskId)
|
||||
.setData("success", taskService.deleteTask(taskId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.util.List;
|
||||
public interface TaskMapper {
|
||||
void newTask(@Param("task") Task task);
|
||||
|
||||
void newTaskProtectObjectConcat(@Param("task_id") Integer taskId, @Param("proobj_id") Integer proobjId);
|
||||
|
||||
void newTaskStaticRuleConcat(@Param("task_id") Integer taskId,
|
||||
@Param("rule_ids") List<Integer> staticRuleIds);
|
||||
|
||||
@@ -24,17 +22,13 @@ public interface TaskMapper {
|
||||
|
||||
Task queryTask(@Param("task_id") Integer taskId);
|
||||
|
||||
List<Integer> queryTaskConcatProtectObjectIds(@Param("task_id") Integer taskId);
|
||||
|
||||
List<Integer> queryTaskConcatStaticRuleIds(@Param("task_id") Integer taskId);
|
||||
|
||||
List<Integer> queryTaskConcatDynamicRuleIds(@Param("task_id") Integer taskId);
|
||||
|
||||
void updateTask(@Param("task") Task task);
|
||||
|
||||
void clearTaskProtectObjectConcat(@Param("task_id") Integer taskId);
|
||||
|
||||
void clearTaskConnectedStaticRule(@Param("task_id") Integer taskId);
|
||||
|
||||
void clearTaskConnectedDynamicRule(@Param("task_id") Integer taskId);
|
||||
|
||||
void changeTaskAuditStatus(@Param("task_id") Integer taskId, @Param("audit_status") Integer auditStatus);
|
||||
|
||||
Boolean deleteTask(@Param("task_id") Integer taskId);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.realtime.protection.server.task;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.realtime.protection.configuration.entity.task.Task;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import com.realtime.protection.configuration.utils.status.AuditStatusValidator;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -10,38 +10,19 @@ import java.util.List;
|
||||
|
||||
@Service
|
||||
public class TaskService {
|
||||
|
||||
private final SqlSessionFactory sqlSessionFactory;
|
||||
private final TaskMapper taskMapper;
|
||||
|
||||
public TaskService(SqlSessionFactory sqlSessionFactory, TaskMapper taskMapper) {
|
||||
this.sqlSessionFactory = sqlSessionFactory;
|
||||
public TaskService(TaskMapper taskMapper) {
|
||||
this.taskMapper = taskMapper;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Integer newTask(Task task) {
|
||||
SqlSession session = sqlSessionFactory.openSession(false);
|
||||
TaskMapper taskMapper = session.getMapper(TaskMapper.class);
|
||||
try {
|
||||
taskMapper.newTask(task);
|
||||
taskMapper.newTask(task);
|
||||
|
||||
task.getProtectObjectIds().forEach(
|
||||
proobjId -> taskMapper.newTaskProtectObjectConcat(task.getTaskId(), proobjId));
|
||||
taskMapper.newTaskStaticRuleConcat(task.getTaskId(), task.getStaticRuleIds());
|
||||
taskMapper.newTaskDynamicRuleConcat(task.getTaskId(), task.getDynamicRuleIds());
|
||||
|
||||
taskMapper.newTaskStaticRuleConcat(task.getTaskId(), task.getStaticRuleIds());
|
||||
// taskMapper.newTaskDynamicRuleConcat(task.getTaskId(), task.getDynamicRuleIds());
|
||||
|
||||
session.commit();
|
||||
} catch (Exception e) {
|
||||
session.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
|
||||
if (task.getTaskId() == null) {
|
||||
return 0;
|
||||
}
|
||||
return task.getTaskId();
|
||||
}
|
||||
|
||||
@@ -52,41 +33,32 @@ public class TaskService {
|
||||
}
|
||||
|
||||
public Task queryTask(Integer id) {
|
||||
SqlSession session = sqlSessionFactory.openSession(false);
|
||||
TaskMapper taskMapper = session.getMapper(TaskMapper.class);
|
||||
Task task;
|
||||
|
||||
try {
|
||||
task = taskMapper.queryTask(id);
|
||||
if (task == null) {
|
||||
return null;
|
||||
}
|
||||
task.setProtectObjectIds(taskMapper.queryTaskConcatProtectObjectIds(task.getTaskId()));
|
||||
// task.setDynamicRuleIds(taskMapper.queryTaskConcatDynamicRuleIds(task.getTaskId()));
|
||||
task.setStaticRuleIds(taskMapper.queryTaskConcatStaticRuleIds(task.getTaskId()));
|
||||
|
||||
session.commit();
|
||||
} catch (Exception e) {
|
||||
session.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return task;
|
||||
return taskMapper.queryTask(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateTask(Task task) {
|
||||
public Boolean updateTask(Task task) {
|
||||
taskMapper.updateTask(task);
|
||||
|
||||
taskMapper.clearTaskProtectObjectConcat(task.getTaskId());
|
||||
taskMapper.clearTaskConnectedStaticRule(task.getTaskId());
|
||||
// taskMapper.clearTaskConnectedDynamicRule(task.getTaskId());
|
||||
taskMapper.clearTaskConnectedDynamicRule(task.getTaskId());
|
||||
|
||||
task.getProtectObjectIds().forEach(
|
||||
proobjId -> taskMapper.newTaskProtectObjectConcat(task.getTaskId(), proobjId));
|
||||
taskMapper.newTaskStaticRuleConcat(task.getTaskId(), task.getStaticRuleIds());
|
||||
// taskMapper.newTaskDynamicRuleConcat(task.getTaskId(), task.getDynamicRuleIds());
|
||||
taskMapper.newTaskDynamicRuleConcat(task.getTaskId(), task.getDynamicRuleIds());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Boolean changeTaskAuditStatus(Integer taskId, Integer taskAuditStatus) {
|
||||
if (AuditStatusValidator.setOriginal(taskMapper.queryTask(taskId).getTaskAuditStatus()).checkValidate(taskAuditStatus))
|
||||
taskMapper.changeTaskAuditStatus(taskId, taskAuditStatus);
|
||||
else return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Boolean deleteTask(Integer taskId) {
|
||||
return taskMapper.deleteTask(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@Mapper
|
||||
// just for example, not for production environment
|
||||
public interface LoginMapper {
|
||||
Integer login(@Param("username") String username, @Param("password") String password);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.realtime.protection.server.whitelist;
|
||||
import com.alibaba.excel.util.ListUtils;
|
||||
import com.realtime.protection.configuration.entity.rule.staticrule.StaticRuleObject;
|
||||
import com.realtime.protection.configuration.entity.whitelist.WhiteListObject;
|
||||
import com.realtime.protection.configuration.utils.AuditStatusValidator;
|
||||
import com.realtime.protection.configuration.utils.status.AuditStatusValidator;
|
||||
import com.realtime.protection.configuration.utils.SqlSessionWrapper;
|
||||
import com.realtime.protection.server.rule.staticrule.StaticRuleMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
Reference in New Issue
Block a user