3-parse-rule #10

Merged
romanov73 merged 17 commits from 3-parse-rule into master 2025-02-25 13:34:08 +04:00
37 changed files with 332 additions and 294 deletions

View File

@ -1,5 +1,5 @@
name: CI fuzzy controller
on: [push]
on: [ push ]
jobs:
container-test-job:
runs-on: ubuntu-latest
@ -8,8 +8,8 @@ jobs:
- name: Set up JDK 21 for x64
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
architecture: x64
java-version: '21'
distribution: 'temurin'
architecture: x64
- name: Test with Gradle
run: bash ./gradlew test

20
.vscode/launch.json vendored
View File

@ -1,12 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "FuzzyControllerApplication",
"request": "launch",
"mainClass": "ru.ulstu.fc.FuzzyControllerApplication",
"projectName": "fuzzy-controller"
}
]
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "FuzzyControllerApplication",
"request": "launch",
"mainClass": "ru.ulstu.fc.FuzzyControllerApplication",
"projectName": "fuzzy-controller"
}
]
}

View File

@ -1,4 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "interactive",
"java.compile.nullAnalysis.mode": "disabled"
"java.configuration.updateBuildConfiguration": "interactive",
"java.compile.nullAnalysis.mode": "disabled"
}

View File

@ -0,0 +1,16 @@
package ru.ulstu.fc.config;
import com.fuzzylite.Engine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FuzzyEngine {
@Bean
public Engine getFuzzyEngine() {
Engine engine = new Engine();
engine.setName("Fuzzy rules");
engine.setDescription("");
return engine;
}
}

View File

@ -18,15 +18,15 @@ import ru.ulstu.fc.user.model.UserRoleConstants;
@Controller
@Hidden
@RequestMapping("project")
@Secured({ UserRoleConstants.ADMIN })
@Secured({UserRoleConstants.ADMIN})
public class ProjectController {
private final ProjectService projectService;
private final ProjectRulesService projectRulesService;
private final ProjectVariableService projectVariableService;
public ProjectController(ProjectService projectService,
ProjectRulesService projectRulesService,
ProjectVariableService projectVariableService) {
ProjectRulesService projectRulesService,
ProjectVariableService projectVariableService) {
this.projectService = projectService;
this.projectRulesService = projectRulesService;
this.projectVariableService = projectVariableService;

View File

@ -0,0 +1,37 @@
package ru.ulstu.fc.project.controller;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.fc.project.service.ProjectRulesService;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.project.service.ProjectVariableService;
import ru.ulstu.fc.user.model.UserRoleConstants;
@Controller
@Hidden
@RequestMapping("runProject")
@Secured({UserRoleConstants.ADMIN})
public class ProjectRunController {
private final ProjectService projectService;
private final ProjectRulesService projectRulesService;
private final ProjectVariableService projectVariableService;
public ProjectRunController(ProjectService projectService,
ProjectRulesService projectRulesService,
ProjectVariableService projectVariableService) {
this.projectService = projectService;
this.projectRulesService = projectRulesService;
this.projectVariableService = projectVariableService;
}
@GetMapping("init/{projectId}")
public String getProjects(@PathVariable(value = "projectId") Integer projectId, Model model) {
model.addAttribute("project", projectService.getById(projectId));
return "project/init";
}
}

View File

@ -1,7 +1,5 @@
package ru.ulstu.fc.project.model;
import java.util.Date;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
@ -9,9 +7,11 @@ import jakarta.validation.constraints.NotEmpty;
import ru.ulstu.fc.core.model.BaseEntity;
import ru.ulstu.fc.user.model.User;
import java.util.Date;
@Entity
public class Project extends BaseEntity {
@NotEmpty(message = "Текст новости не может быть пустым")
@NotEmpty(message = "Название проекта не может быть пустым")
private String name;
private Date createDate = new Date();
@ManyToOne(cascade = CascadeType.MERGE)

View File

@ -1,9 +1,12 @@
package ru.ulstu.fc.project.model;
import jakarta.validation.constraints.NotEmpty;
import java.util.Date;
public class ProjectForm {
private Integer id;
@NotEmpty(message = "Название проекта не может быть пустым")
private String name;
private Date createDate;

View File

@ -1,20 +1,19 @@
package ru.ulstu.fc.project.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.FuzzyRule;
import ru.ulstu.fc.rule.repository.FuzzyRuleRepository;
import java.util.Collections;
import java.util.List;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.repository.FuzzyRuleRepository;
import ru.ulstu.fc.rule.model.FuzzyRule;
@Service
public class ProjectRulesService {
private final FuzzyRuleRepository ruleRepository;
private final ProjectService projectService;
public ProjectRulesService(FuzzyRuleRepository ruleRepository,
ProjectService projectService) {
ProjectService projectService) {
this.ruleRepository = ruleRepository;
this.projectService = projectService;
}

View File

@ -1,20 +1,19 @@
package ru.ulstu.fc.project.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.repository.VariableRepository;
import java.util.Collections;
import java.util.List;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.repository.VariableRepository;
import ru.ulstu.fc.rule.model.Variable;
@Service
public class ProjectVariableService {
private final VariableRepository variableRepository;
private final ProjectService projectService;
public ProjectVariableService(VariableRepository variableRepository,
ProjectService projectService) {
ProjectService projectService) {
this.variableRepository = variableRepository;
this.projectService = projectService;
}

View File

@ -1,5 +1,6 @@
package ru.ulstu.fc.rule.controller;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
@ -7,23 +8,21 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.validation.Valid;
import ru.ulstu.fc.rule.model.FuzzyRuleForm;
import ru.ulstu.fc.rule.service.FuzzyRuleService;
@Controller
@RequestMapping("rule")
public class RuleController {
public class FuzzyRuleController {
private final FuzzyRuleService ruleService;
public RuleController(FuzzyRuleService ruleService) {
public FuzzyRuleController(FuzzyRuleService ruleService) {
this.ruleService = ruleService;
}
@GetMapping("/edit/{projectId}/{ruleId}")
public String edit(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "ruleId") Integer id, Model model) {
@PathVariable(value = "ruleId") Integer id, Model model) {
model.addAttribute("projectId", projectId);
model.addAttribute("fuzzyRuleForm",
(id != null && id != 0)

View File

@ -1,5 +1,6 @@
package ru.ulstu.fc.rule.controller;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
@ -7,8 +8,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.validation.Valid;
import ru.ulstu.fc.rule.model.FuzzyTermForm;
import ru.ulstu.fc.rule.service.FuzzyTermService;
@ -23,8 +22,8 @@ public class FuzzyTermController {
@GetMapping("/edit/{projectId}/{variableId}/{fuzzyTermId}")
public String edit(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "variableId") Integer variableId,
@PathVariable(value = "fuzzyTermId") Integer fuzzyTermId, Model model) {
@PathVariable(value = "variableId") Integer variableId,
@PathVariable(value = "fuzzyTermId") Integer fuzzyTermId, Model model) {
model.addAttribute("projectId", projectId);
model.addAttribute("variableId", variableId);
model.addAttribute("fuzzyTermForm",

View File

@ -7,8 +7,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import ru.ulstu.fc.rule.model.InferenceForm;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.InferenceForm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.service.FuzzyInferenceService;

View File

@ -1,5 +1,6 @@
package ru.ulstu.fc.rule.controller;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
@ -7,8 +8,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.validation.Valid;
import ru.ulstu.fc.rule.model.VariableForm;
import ru.ulstu.fc.rule.service.FuzzyTermService;
import ru.ulstu.fc.rule.service.VariableService;
@ -20,14 +19,14 @@ public class VariableController {
private final FuzzyTermService termService;
public VariableController(VariableService variableService,
FuzzyTermService termService) {
FuzzyTermService termService) {
this.variableService = variableService;
this.termService = termService;
}
@GetMapping("/edit/{projectId}/{variableId}")
public String edit(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "variableId") Integer variableId, Model model) {
@PathVariable(value = "variableId") Integer variableId, Model model) {
model.addAttribute("projectId", projectId);
model.addAttribute("variableForm",
(variableId == null || variableId == 0)

View File

@ -1,8 +1,5 @@
package ru.ulstu.fc.rule.model;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
@ -14,17 +11,20 @@ import jakarta.validation.constraints.Size;
import ru.ulstu.fc.core.model.BaseEntity;
import ru.ulstu.fc.project.model.Project;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Variable extends BaseEntity {
@Size(min = 3, max = 250, message = "Длина должна быть от 3 до 250")
private String name;
@ManyToOne
@NotNull
private Project project;
private boolean input = true;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "variable_id")
private List<FuzzyTerm> fuzzyTerms = new ArrayList<>();
@ -72,4 +72,4 @@ public class Variable extends BaseEntity {
public void setInput(boolean input) {
this.input = input;
}
}
}

View File

@ -1,12 +1,11 @@
package ru.ulstu.fc.rule.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.project.model.Project;
import ru.ulstu.fc.rule.model.FuzzyRule;
import java.util.List;
public interface FuzzyRuleRepository extends JpaRepository<FuzzyRule, Integer> {
List<FuzzyRule> findByProject(Project project);

View File

@ -1,7 +1,6 @@
package ru.ulstu.fc.rule.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.rule.model.FuzzyTerm;
public interface FuzzyTermRepository extends JpaRepository<FuzzyTerm, Integer> {

View File

@ -1,12 +1,11 @@
package ru.ulstu.fc.rule.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.project.model.Project;
import ru.ulstu.fc.rule.model.Variable;
import java.util.List;
public interface VariableRepository extends JpaRepository<Variable, Integer> {
List<Variable> findByProject(Project project);

View File

@ -14,8 +14,8 @@ import com.fuzzylite.variable.OutputVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.OutputValue;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.OutputValue;
import ru.ulstu.fc.rule.model.Variable;
import java.util.List;
@ -30,14 +30,17 @@ public class FuzzyInferenceService {
+ OUTPUT_VARIABLE_NAME
+ " is %s";
private final static String NO_RESULT = "Нет результата";
private final Engine fuzzyEngine;
public FuzzyInferenceService(Engine fuzzyEngine) {
this.fuzzyEngine = fuzzyEngine;
}
private List<String> getDemoRules() {
return List.of(
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "высокий", "большой"),
String.format(RULE_TEMPLATE, "возраст", "средний", "доход", "высокий", "средний"),
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "высокий", "средний"),
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "небольшой", "небольшой"),
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "небольшой", "небольшой")
String.format(RULE_TEMPLATE, "возраст", "молодой", "доход", "высокий", "средний"),
String.format(RULE_TEMPLATE, "возраст", "средний", "доход", "высокий", "большой"),
String.format(RULE_TEMPLATE, "возраст", "старый", "доход", "средний", "средний")
);
}
@ -102,13 +105,6 @@ public class FuzzyInferenceService {
return mamdani;
}
private Engine getFuzzyEngine() {
Engine engine = new Engine();
engine.setName("Fuzzy rules");
engine.setDescription("");
return engine;
}
private List<OutputValue> getConsequent(Engine engine, Map<String, Double> variableValues) {
OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME);
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
@ -152,8 +148,8 @@ public class FuzzyInferenceService {
Map<String, Double> values,
List<Variable> inputVariables,
Variable outputVariable) {
Engine engine = getFuzzyEngine();
engine.addRuleBlock(getRuleBlock(engine, rules, inputVariables, outputVariable));
return getConsequent(engine, values);
fuzzyEngine.getRuleBlocks().clear();
fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, rules, inputVariables, outputVariable));
return getConsequent(fuzzyEngine, values);
}
}

View File

@ -0,0 +1,44 @@
package ru.ulstu.fc.rule.service;
import com.fuzzylite.Engine;
import com.fuzzylite.rule.Rule;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class FuzzyRuleParseService {
private final static String RU_IF_STATEMENT = "если";
private final static String ENG_IF_STATEMENT = "if";
private final static String RU_THEN_STATEMENT = "то";
private final static String ENG_THEN_STATEMENT = "then";
private final static String RU_AND_STATEMENT = "и";
private final static String ENG_AND_STATEMENT = "and";
private final static String RU_IS_STATEMENT = "является";
private final static String RU_EQ_STATEMENT = "равно";
private final static String ENG_IS_STATEMENT = "is";
private final Engine fuzzyEngine;
public FuzzyRuleParseService(Engine fuzzyEngine) {
this.fuzzyEngine = fuzzyEngine;
}
public List<Rule> parseRules(List<String> stringRules) {
return stringRules
.stream()
.map(s -> Rule.parse(replaceEnglishKeywords(s), fuzzyEngine))
.collect(Collectors.toList());
}
private String replaceEnglishKeywords(String stringRule) {
stringRule = stringRule.toLowerCase();
return stringRule
.replaceFirst(RU_IF_STATEMENT, ENG_IF_STATEMENT)
.replaceFirst(RU_AND_STATEMENT, ENG_AND_STATEMENT)
.replaceFirst(RU_IS_STATEMENT, ENG_IS_STATEMENT)
.replaceFirst(RU_EQ_STATEMENT, ENG_IS_STATEMENT)
.replaceAll(RU_THEN_STATEMENT, ENG_THEN_STATEMENT);
}
}

View File

@ -1,11 +1,10 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.repository.FuzzyRuleRepository;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.rule.model.FuzzyRule;
import ru.ulstu.fc.rule.model.FuzzyRuleForm;
import ru.ulstu.fc.rule.repository.FuzzyRuleRepository;
@Service
public class FuzzyRuleService {

View File

@ -1,21 +1,20 @@
package ru.ulstu.fc.rule.service;
import java.util.Collections;
import java.util.List;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.FuzzyTermForm;
import ru.ulstu.fc.rule.repository.FuzzyTermRepository;
import java.util.Collections;
import java.util.List;
@Service
public class FuzzyTermService {
private final FuzzyTermRepository fuzzyTermRepository;
private final VariableService variableService;
public FuzzyTermService(FuzzyTermRepository fuzzyTermRepository,
VariableService variableService) {
VariableService variableService) {
this.fuzzyTermRepository = fuzzyTermRepository;
this.variableService = variableService;
}

View File

@ -1,7 +1,6 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.rule.model.FuzzyTerm;
import ru.ulstu.fc.rule.model.Variable;

View File

@ -1,5 +1,7 @@
package ru.ulstu.fc.user.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
@ -7,9 +9,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.request.WebRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import ru.ulstu.fc.user.model.User;
import ru.ulstu.fc.user.model.UserDto;
import ru.ulstu.fc.user.service.UserService;

View File

@ -1,8 +1,5 @@
package ru.ulstu.fc.user.model;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
@ -15,6 +12,9 @@ import jakarta.validation.constraints.Size;
import ru.ulstu.fc.config.Constants;
import ru.ulstu.fc.core.model.BaseEntity;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "is_users")
public class User extends BaseEntity {

View File

@ -1,19 +1,18 @@
package ru.ulstu.fc.user.service;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.fc.config.Constants;
import java.io.IOException;
@Component
public class UserSessionLoginHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private final Logger log = LoggerFactory.getLogger(UserSessionLoginHandler.class);

View File

@ -1,19 +1,18 @@
package ru.ulstu.fc.user.service;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.stereotype.Component;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.fc.config.Constants;
import java.io.IOException;
@Component
public class UserSessionLogoutHandler extends SimpleUrlLogoutSuccessHandler {
private final Logger log = LoggerFactory.getLogger(UserSessionLogoutHandler.class);

View File

@ -13,6 +13,7 @@ extractor.custom-projects-dir=
server.error.include-stacktrace=always
server.error.include-exception=true
server.error.include-message=always
# go to http://localhost:8080/h2-console
spring.datasource.url=jdbc:h2:file:./data/db
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa

View File

@ -1,83 +0,0 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Простая обработка формы на Spring MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<form action="/listRule" th:action="${@route.ADD_RULE}" th:object="${addRuleForm}" method="post">
<input type="hidden" th:field="*{ruleId}">
<div class="row">
<div class="col-md-2 col-sm-12">
Если
</div>
<div class="col-md-6 col-sm-12">
<select id="select-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{firstAntecedentId}"
data-width="90%">
<option th:each="antecedent : ${antecedents}"
th:value="${antecedent}"
th:utext="${antecedent.description}">
</option>
</select>
</div>
<div class="col-md-2 col-sm-12">
имеет тенденцию
</div>
<div class="col-md-2 col-sm-12">
<select id="select-measures" class="selectpicker m-2" data-live-search="true"
th:field="*{firstAntecedentValueId}"
data-width="100%">
<option th:each="antecedentValue : ${antecedentValues}"
th:value="${antecedentValue.id}"
th:utext="${antecedentValue.antecedentValue}">
</option>
</select>
</div>
<div class="col-md-2 col-sm-12">
и
</div>
<div class="col-md-6 col-sm-12">
<select id="select-second-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{secondAntecedentId}"
data-width="90%">
<option th:each="antecedent : ${antecedents}"
th:value="${antecedent}"
th:utext="${antecedent.description}">
</option>
</select>
</div>
<div class="col-md-2 col-sm-12">
имеет тенденцию
</div>
<div class="col-md-2 col-sm-12">
<select id="select-second-measures" class="selectpicker m-2" data-live-search="true"
th:field="*{secondAntecedentValueId}"
data-width="100%">
<option th:each="antecedentValue : ${antecedentValues}"
th:value="${antecedentValue.id}"
th:utext="${antecedentValue.antecedentValue}">
</option>
</select>
</div>
<div class="col-md-2 col-sm-12">
то:
</div>
<div class="col-md-6 col-sm-12">
<input type="text" class="form-control m-1" th:field="*{consequent}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12"></div>
<div class="col-md-4 col-sm-12">
<input type="submit" class="btn btn-outline-success m-2" th:if="*{ruleId == null}"
value="Создать правило"/>
<input type="submit" class="btn btn-outline-success m-2" th:if="*{ruleId != null}"
value="Сохранить правило"/>
</div>
</div>
</form>
</div>
</html>

View File

@ -1,71 +1,71 @@
<!DOCTYPE html>
<html lang="ru" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head>
<meta charset="UTF-8" />
<meta charset="UTF-8"/>
<title>Нечеткий контроллер</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/4.6.0/js/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap-select/1.13.8/js/bootstrap-select.min.js"></script>
<link rel="stylesheet" href="/webjars/bootstrap/4.6.0/css/bootstrap.min.css" />
<link rel="stylesheet" href="/webjars/bootstrap-select/1.13.8/css/bootstrap-select.min.css" />
<link rel="stylesheet" href="/webjars/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="/webjars/bootstrap/4.6.0/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/bootstrap-select/1.13.8/css/bootstrap-select.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/4.7.0/css/font-awesome.min.css"/>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Проекты</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/project/list">Список проектов</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html">API</a>
</li>
<li>
<div sec:authorize="isAuthenticated()">
<a class="nav-link" href="/logout">
<span sec:authentication="name">Bob</span>
(Выход)</a>
</div>
<div sec:authorize="!isAuthenticated()">
<a class="nav-link" href="/login">Вход</a>
</div>
</li>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">Проекты</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/project/list">Список проектов</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html">API</a>
</li>
<li>
<div sec:authorize="isAuthenticated()">
<a class="nav-link" href="/logout">
<span sec:authentication="name">Bob</span>
(Выход)</a>
</div>
<div sec:authorize="!isAuthenticated()">
<a class="nav-link" href="/login">Вход</a>
</div>
</li>
</ul>
</div>
</nav>
<div class="wrapper">
<div id="sidebar" class="collapse navbar-collapse sidebar-mobile">
<ul id="menu" class="list-unstyled">
</ul>
</div>
<div id="content">
<div id="breadcrumbs" class="container-fluid">
</div>
<div class="container-fluid">
<ul id="messages" class="feedback-panel">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
</div>
</ul>
</div>
</nav>
<div class="wrapper">
<div id="sidebar" class="collapse navbar-collapse sidebar-mobile">
<ul id="menu" class="list-unstyled">
</ul>
</div>
<div id="content">
<div id="breadcrumbs" class="container-fluid">
</div>
<div class="container-fluid">
<ul id="messages" class="feedback-panel">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
</div>
</ul>
</div>
<div layout:fragment="content">
</div>
<div layout:fragment="content">
</div>
</div>
</div>
</body>
</html>

View File

@ -39,7 +39,7 @@
Не может быть пустым
</p>
</div>
<button name="save" type="submit" class="btn btn-outline-dark">Сохранить</button>
<button name="delete"
type="submit"

View File

@ -6,11 +6,11 @@
<head>
</head>
<body>
<nav layout:fragment="navbar">
<div class="navbar-header">
<a class="navbar-brand" href="/"><span class="ui-menuitem-text">Нечеткий контроллер</span></a>
</div>
</nav>
<nav layout:fragment="navbar">
<div class="navbar-header">
<a class="navbar-brand" href="/"><span class="ui-menuitem-text">Нечеткий контроллер</span></a>
</div>
</nav>
<div class="container" layout:fragment="content">
<div class="container-fluid">
<ul id="messages" class="feedback-panel">

View File

@ -1,10 +1,10 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
layout:decorate="~{default}">
<head>
<title>Редактирование проекта</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<h3>Редактирование проекта:</h3>
@ -27,7 +27,7 @@
<a href="/project/list" class="btn btn-outline-dark">Отмена</a>
</form>
<hr />
<hr/>
<div class="row">
<div class="col col-md-6">
<h4> Список переменных</h4>
@ -48,39 +48,52 @@
<div class="row" th:each="r, iter : ${rules}">
<div class="col col-md-12">
<a th:href="@{'/rule/edit/' + ${projectId}+'/'+${r.id}}">
<span class="badge badge-light" th:text="${iter.index+1} + '. ' + ${r.content}"></span>
<div class="rule row" th:text="${r.content}"></div>
</a>
</div>
</div>
<!-- <div class="col col-md-2 offset-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-2">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-2">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-1">
<span class="badge badge-danger">И / ИЛИ</span>
</div>
<div class="col col-md-2 offset-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-2">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-2">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-1">
<span class="badge badge-danger">И / ИЛИ</span>
</div>-->
</div>
<a th:href="@{'/rule/edit/' + ${projectId}+'/0'}" th:if="${not #lists.isEmpty(variables)}"
class="btn btn-outline-dark">Добавить правило</a>
class="btn btn-outline-dark">Добавить правило</a>
</div>
</div>
<script>
function getAntecedent(rule) {
withoutIf = rule.split('if');
return withoutIf[1].trim().split('then')[0].trim();
}
function getAntecedentComponents(antecedent) {
return antecedent.split('and').map((i) => i.trim());
}
function getVariable(antecedent) {
return antecedent.split('is')[0].trim();
}
function getVariableValue(antecedent) {
return antecedent.split('is')[1].trim();
}
function addRule(index, el, rule) {
ruleHtml = "<div class='col col-md-12'><span class='badge badge-light'>"+(index+1) +". Если</span></div>"
antecedentComponents = getAntecedentComponents(getAntecedent(rule));
for (let i = 0; i < antecedentComponents.length; i++) {
a = antecedentComponents[i];
if (i > 0) {
ruleHtml += "<div class='col col-md-12'><span class='badge badge-danger'>И</span></div>";
}
ruleHtml += "<div class='col col-md-2 offset-md-1'><span class='badge badge-primary'>"+getVariable(a)+"</span></div>";
ruleHtml += "<div class='col col-md-2'><span class='badge badge-light'>есть</span></div>";
ruleHtml += "<div class='col col-md-2'><span class='badge badge-success'>"+getVariableValue(a)+"</span></div>";
}
$(el).html(ruleHtml);
}
$('.rule').each(function(index ) {
addRule(index, $(this), $(this).text());
});
</script>
</div>
</html>

View File

@ -1,10 +1,10 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<title>Список правил</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<h3> Список правил</h3>

View File

@ -6,19 +6,19 @@
<div class="form-group">
<label for="login">Логин</label>
<input th:field="*{login}" id="login" type="text" required class="form-control"
placeholder="Логин пользователя">
placeholder="Логин пользователя">
<p th:each="error: ${#fields.errors('login')}" th:text="${error}">Validation error</p>
</div>
<div class="form-group">
<label for="password">Пароль</label>
<input th:field="*{password}" id="password" type="text" required class="form-control"
placeholder="Пароль">
placeholder="Пароль">
<p th:each="error : ${#fields.errors('password')}" th:text="${error}">Validation error</p>
</div>
<div class="form-group">
<label for="confirmPass">Подтверждение пароля</label>
<input id = "confirmPass" type="password" th:field="*{matchingPassword}" required class="form-control"
placeholder="Подтверждение пароля"/>
<input id="confirmPass" type="password" th:field="*{matchingPassword}" required class="form-control"
placeholder="Подтверждение пароля"/>
</div>
<button type="submit" class="btn btn-outline-dark">Зарегистрировать</button>
<a href="/login" class="btn btn-outline-dark">Вернуться на страницу входа</a>

View File

@ -12,9 +12,9 @@
<input type="hidden" th:field="*{projectId}">
<input type="hidden" th:field="*{id}">
<div class="form-group">
<label for="content">Правило</label>
<label for="ruleContent">Правило</label>
<input th:field="*{content}"
id="content"
id="ruleContent"
type="text"
required
class="form-control"
@ -24,7 +24,31 @@
Не может быть пустым
</p>
</div>
<div class="form-group">
<label class="col col-md-1">Если</label>
<select id="select-variable" class="selectpicker m-2" data-live-search="true" data-width="70%">
<option>Скорость</option>
</select>
</div>
<div class="form-group">
<label class="col col-md-1">есть</label>
<select id="select-val" class="selectpicker m-2" data-live-search="true" data-width="70%">
<option>Высокая</option>
</select>
</div>
<div class="form-group">
<label class="col col-md-1">то</label>
<select id="select-val1" class="selectpicker m-2" data-live-search="true" data-width="70%">
<option>Действие</option>
</select>
</div>
<div class="form-group">
<label class="col col-md-1">есть</label>
<select id="select-val4" class="selectpicker m-2" data-live-search="true" data-width="70%">
<option>Сливать воду</option>
</select>
</div>
<button name="save" type="submit" class="btn btn-outline-dark">Сохранить</button>
<button name="delete"
type="submit"

View File

@ -1,10 +1,10 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
layout:decorate="~{default}">
<head>
<title>Редактирование переменной</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<h3>Редактирование переменной:</h3>
@ -26,12 +26,12 @@
<button name="save" type="submit" class="btn btn-outline-dark">Сохранить</button>
<button name="delete" type="submit" class="btn btn-outline-dark" th:if="*{id != 0}"
onclick="return confirm('Удалить запись?')">
onclick="return confirm('Удалить запись?')">
Удалить
</button>
<a th:href="@{'/project/edit/' + ${projectId}}" class="btn btn-outline-dark">Отмена</a>
<hr />
<hr/>
<div class="row">
<div class="col col-md-6">
<h4> Список термов</h4>
@ -40,12 +40,13 @@
<div class="col col-md-12">
<a th:href="@{'/fuzzyTerm/edit/' + ${projectId} + '/' + ${variableId}+'/'+${t.id}}">
<span class="badge badge-light"
th:text="${iter.index+1} + '. ' + ${t.description}"></span>
th:text="${iter.index+1} + '. ' + ${t.description}"></span>
</a>
</div>
</div>
</div>
<a th:href="@{'/fuzzyTerm/edit/' + ${projectId} + '/' + ${variableId}+'/0'}" class="btn btn-outline-dark">Добавить терм</a>
<a th:href="@{'/fuzzyTerm/edit/' + ${projectId} + '/' + ${variableId}+'/0'}"
class="btn btn-outline-dark">Добавить терм</a>
</div>
</div>
</form>