Compare commits

..

9 Commits

Author SHA1 Message Date
c635efaacf #3 -- Fix inference 2023-11-06 20:00:06 +04:00
24a59f204d Merge branch 'master' into 3-parse-rule
# Conflicts:
#	src/main/java/ru/ulstu/fc/rule/model/Variable.java
#	src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java
#	src/main/resources/templates/default.html
2023-11-06 19:21:39 +04:00
0bbe406486 #3 -- Save vars 2023-09-26 22:29:53 +04:00
df4fd6d0ff #3 -- Add models and pages 2023-09-26 21:58:00 +04:00
950dde7f83 #3 -- Add rule models 2023-09-11 19:47:41 +04:00
a705fe5fdb #3 -- Page title fixes 2023-09-11 19:33:42 +04:00
8fbd17c63e #3 -- Add term methods and model 2023-09-11 19:23:27 +04:00
b88ed0211f #3 -- Add rule controller 2023-09-11 19:05:13 +04:00
1c8eabfc08 #3 -- Config of fuzzy engine 2023-09-11 18:22:00 +04:00
27 changed files with 717 additions and 195 deletions

View File

@ -1,78 +0,0 @@
import json
import requests
url = 'http://plans.athene.tech/rest/get-inference'
headers = {
'Content-type': 'application/json',
'Accept': 'application/json'
}
age = 65
income = 20000
data = {
"inputVariables": [
{
"name": "возраст",
"values": [
{
"fuzzyTerm": "молодой",
"value": 35
},
{
"fuzzyTerm": "средний",
"value": 45
},
{
"fuzzyTerm": "старый",
"value": 65
}]
},
{
"name": "доход",
"values": [
{
"fuzzyTerm": "низкий",
"value": 50000
},
{
"fuzzyTerm": "средний",
"value": 100000
},
{
"fuzzyTerm": "высокий",
"value": 500000
}]
}],
"outputVariable":
{
"name": "кредит",
"values": [
{
"fuzzyTerm": "небольшой",
"value": 50000
},
{
"fuzzyTerm": "средний",
"value": 100000
},
{
"fuzzyTerm": "большой",
"value": 200000
}]
},
"rules": [
"if доход is высокий and возраст is молодой then кредит is большой",
"if доход is высокий and возраст is средний then кредит is средний",
"if доход is высокий and возраст is старый then кредит is средний",
"if доход is низкий and возраст is молодой then кредит is небольшой"
],
"values":
{
"доход": income,
"возраст": age
}
}
response = requests.post(url, data=json.dumps(data), headers=headers)
print(response.json())

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

@ -0,0 +1,86 @@
package ru.ulstu.fc.core;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import java.io.Serializable;
@MappedSuperclass
public abstract class BaseEntity implements Serializable, Comparable<BaseEntity> {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
@Version
private Integer version;
public BaseEntity() {
}
public BaseEntity(Integer id, Integer version) {
this.id = id;
this.version = version;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getVersion() {
return version;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.getId() != null) {
return false;
}
} else if (!id.equals(other.getId())) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
return result;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"id=" + id +
", version=" + version +
'}';
}
@Override
public int compareTo(BaseEntity o) {
return id != null ? id.compareTo(o.getId()) : -1;
}
public void reset() {
this.id = null;
this.version = null;
}
}

View File

@ -0,0 +1,96 @@
package ru.ulstu.fc.rule.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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.bind.annotation.RequestParam;
import ru.ulstu.fc.rule.model.AddRuleForm;
import ru.ulstu.fc.rule.model.AddTermForm;
import ru.ulstu.fc.rule.model.AddVariableForm;
import ru.ulstu.fc.rule.service.RuleParseService;
import ru.ulstu.fc.rule.service.RuleService;
import ru.ulstu.fc.rule.service.TermsService;
import ru.ulstu.fc.rule.service.VariableService;
import java.util.List;
@Controller
public class RuleController {
private final RuleParseService ruleParseService;
private final RuleService ruleService;
private final TermsService termService;
private final VariableService variableService;
public RuleController(RuleParseService ruleParseService,
RuleService ruleService,
TermsService termService,
VariableService variableService) {
this.ruleParseService = ruleParseService;
this.ruleService = ruleService;
this.termService = termService;
this.variableService = variableService;
}
@GetMapping("listRules")
public String listRules(Model model) {
model.addAttribute("rules", ruleService.getRules());
return "listRules";
}
@GetMapping("listTerms")
public String listTerms(Model model) {
model.addAttribute("terms", termService.getTerms());
return "listTerms";
}
@GetMapping("listVars")
public String listVariables(Model model) {
model.addAttribute("vars", variableService.getVars());
return "listVars";
}
@GetMapping("addRule")
public String addRule(Model model) {
model.addAttribute("addRuleForm", new AddRuleForm());
return "addRule";
}
@PostMapping("addRule")
public String parse(@ModelAttribute AddRuleForm addRuleForm, Model model) {
try {
System.out.println(ruleParseService.parseRules(List.of(addRuleForm.getRule())));
} catch (Exception ex) {
return "addRule";
}
model.addAttribute("addRuleForm", addRuleForm);
return "listRules";
}
@GetMapping("addVariable")
public String addVariable(Model model, @RequestParam(required = false) Integer id) {
model.addAttribute("addVariableForm", variableService.getAddVariableFormOrDefault(id));
return "addVariable";
}
@PostMapping("addVariable")
public String addVariable(@ModelAttribute AddVariableForm addVariableForm, Model model) {
model.addAttribute("addVariableForm", addVariableForm);
variableService.save(addVariableForm);
model.addAttribute("vars", variableService.getVars());
return "listVars";
}
@GetMapping("addTerm")
public String addTerm(Model model) {
model.addAttribute("addTermForm", new AddTermForm());
return "addTerm";
}
@PostMapping("addTerm")
public String addTerm(@ModelAttribute AddTermForm addTermForm, Model model) {
model.addAttribute("addTermForm", addTermForm);
return "listTerms";
}
}

View File

@ -0,0 +1,13 @@
package ru.ulstu.fc.rule.model;
public class AddRuleForm {
private String rule;
public String getRule() {
return rule;
}
public void setRule(String rule) {
this.rule = rule;
}
}

View File

@ -0,0 +1,40 @@
package ru.ulstu.fc.rule.model;
public class AddTermForm {
private String variable;
private String term;
private String min;
private String max;
public String getVariable() {
return variable;
}
public void setVariable(String variable) {
this.variable = variable;
}
public String getTerm() {
return term;
}
public void setTerm(String term) {
this.term = term;
}
public String getMin() {
return min;
}
public void setMin(String min) {
this.min = min;
}
public String getMax() {
return max;
}
public void setMax(String max) {
this.max = max;
}
}

View File

@ -0,0 +1,31 @@
package ru.ulstu.fc.rule.model;
public class AddVariableForm {
private Integer id;
private String name;
public AddVariableForm(Variable variable) {
this.id = variable.getId();
this.name = variable.getName();
}
public AddVariableForm() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}

View File

@ -0,0 +1,18 @@
package ru.ulstu.fc.rule.model;
import ru.ulstu.fc.core.BaseEntity;
import javax.persistence.Entity;
@Entity
public class Rule extends BaseEntity {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,45 @@
package ru.ulstu.fc.rule.model;
import ru.ulstu.fc.core.BaseEntity;
import javax.persistence.Entity;
@Entity
public class Term extends BaseEntity {
private String name;
private double min;
private double max;
public Term() {
}
public Term(String name, double min, double max) {
this.name = name;
this.min = min;
this.max = max;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMin() {
return min;
}
public void setMin(double min) {
this.min = min;
}
public double getMax() {
return max;
}
public void setMax(double max) {
this.max = max;
}
}

View File

@ -1,24 +1,42 @@
package ru.ulstu.fc.rule.model; package ru.ulstu.fc.rule.model;
import ru.ulstu.fc.core.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import java.util.List; import java.util.List;
public class Variable { @Entity
public class Variable extends BaseEntity {
private String name; private String name;
private List<VariableValue> values; @OneToMany
private List<Term> terms;
public Variable() { public Variable() {
} }
public Variable(String name, List<VariableValue> values) { public Variable(String name) {
this.name = name; this.name = name;
this.values = values; }
public Variable(String name, List<Term> terms) {
this.name = name;
this.terms = terms;
} }
public String getName() { public String getName() {
return name; return name;
} }
public List<VariableValue> getValues() { public void setName(String name) {
return values; this.name = name;
} }
}
public List<Term> getTerms() {
return terms;
}
public void setTerms(List<Term> terms) {
this.terms = terms;
}
}

View File

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

View File

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

View File

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

View File

@ -15,8 +15,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.OutputValue; import ru.ulstu.fc.rule.model.OutputValue;
import ru.ulstu.fc.rule.model.Term;
import ru.ulstu.fc.rule.model.Variable; import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.VariableValue;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -30,14 +30,17 @@ public class FuzzyInferenceService {
+ OUTPUT_VARIABLE_NAME + OUTPUT_VARIABLE_NAME
+ " is %s"; + " is %s";
private final static String NO_RESULT = "Нет результата"; private final static String NO_RESULT = "Нет результата";
private final Engine fuzzyEngine;
public FuzzyInferenceService(Engine fuzzyEngine) {
this.fuzzyEngine = fuzzyEngine;
}
private List<String> getDemoRules() { private List<String> getDemoRules() {
return List.of( 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, "возраст", "молодой", "доход", "небольшой", "небольшой")
); );
} }
@ -45,16 +48,13 @@ public class FuzzyInferenceService {
final InputVariable input = new InputVariable(); final InputVariable input = new InputVariable();
input.setName(variable.getName()); input.setName(variable.getName());
input.setDescription(""); input.setDescription("");
input.setRange(0, variable.getValues().get(variable.getValues().size() - 1).getValue()); input.setRange(0, variable.getTerms().get(variable.getTerms().size() - 1).getMax());
input.setEnabled(true); input.setEnabled(true);
input.setLockValueInRange(false); input.setLockValueInRange(false);
double prev = 0; for (int i = 0; i < variable.getTerms().size(); i++) {
for (int i = 0; i < variable.getValues().size(); i++) { Triangle term = new Triangle(variable.getTerms().get(i).getName(),
Triangle term = new Triangle(variable.getValues().get(i).getFuzzyTerm(), variable.getTerms().get(i).getMin(),
prev, variable.getTerms().get(i).getMax());
variable.getValues().get(i).getValue(),
variable.getValues().get(i).getValue() + variable.getValues().get(i).getValue() - prev);
prev = term.getVertexB();
input.addTerm(term); input.addTerm(term);
} }
return input; return input;
@ -64,20 +64,16 @@ public class FuzzyInferenceService {
final OutputVariable output = new OutputVariable(); final OutputVariable output = new OutputVariable();
output.setName(variable.getName()); output.setName(variable.getName());
output.setDescription(""); output.setDescription("");
output.setRange(0, variable.getValues().get(variable.getValues().size() - 1).getValue()); output.setRange(0, variable.getTerms().get(variable.getTerms().size() - 1).getMax());
output.setEnabled(true); output.setEnabled(true);
output.setAggregation(new Maximum()); output.setAggregation(new Maximum());
output.setDefuzzifier(new WeightedAverage()); output.setDefuzzifier(new WeightedAverage());
output.setDefaultValue(Double.NaN); output.setDefaultValue(Double.NaN);
output.setLockValueInRange(false); output.setLockValueInRange(false);
double prev = 0; for (int i = 0; i < variable.getTerms().size(); i++) {
for (int i = 0; i < variable.getValues().size(); i++) { Triangle term = new Triangle(variable.getTerms().get(i).getName(),
Triangle term = new Triangle( variable.getTerms().get(i).getMin(),
variable.getValues().get(i).getFuzzyTerm(), variable.getTerms().get(i).getMax());
prev,
variable.getValues().get(i).getValue(),
variable.getValues().get(i).getValue() + variable.getValues().get(i).getValue() - prev);
prev = term.getVertexB();
output.addTerm(term); output.addTerm(term);
} }
return output; return output;
@ -101,13 +97,6 @@ public class FuzzyInferenceService {
return mamdani; 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) { private List<OutputValue> getConsequent(Engine engine, Map<String, Double> variableValues) {
OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME); OutputVariable outputVariable = engine.getOutputVariable(OUTPUT_VARIABLE_NAME);
for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) { for (Map.Entry<String, Double> variableValue : variableValues.entrySet()) {
@ -130,20 +119,21 @@ public class FuzzyInferenceService {
public List<OutputValue> getFuzzyInference(Map<String, Double> vals) { public List<OutputValue> getFuzzyInference(Map<String, Double> vals) {
return getFuzzyInference(getDemoRules(), vals, return getFuzzyInference(getDemoRules(), vals,
List.of(new Variable("возраст", List.of( List.of(new Variable("возраст", List.of(
new VariableValue("молодой", 35.0), new Term("молодой", 0.0, 40.0),
new VariableValue("средний", 60.0), new Term("средний", 20.0, 60.0),
new VariableValue("старый", 100.0)) new Term("старый", 50.0, 100.0))
), ),
new Variable("доход", List.of( new Variable("доход", List.of(
new VariableValue("небольшой", 35000.0), new Term("небольшой", 0.0, 35000.0),
new VariableValue("средний", 100000.0), new Term("средний", 20000.0, 100000.0),
new VariableValue("высокий", 500000.0)) new Term("высокий", 80000.0, 500000.0))
) )
), ),
new Variable("кредит", List.of( new Variable("кредит", List.of(
new VariableValue("небольшой", 20000.0), new Term("не_выдавать_кредит", 0.0, 1.0),
new VariableValue("средний", 100000.0), new Term("небольшой", 1.0, 50000.0),
new VariableValue("большой", 1000000.0))) new Term("средний", 25000.0, 100000.0),
new Term("большой", 75000.0, 1000000.0)))
); );
} }
@ -151,8 +141,8 @@ public class FuzzyInferenceService {
Map<String, Double> values, Map<String, Double> values,
List<Variable> inputVariables, List<Variable> inputVariables,
Variable outputVariable) { Variable outputVariable) {
Engine engine = getFuzzyEngine(); fuzzyEngine.getRuleBlocks().clear();
engine.addRuleBlock(getRuleBlock(engine, rules, inputVariables, outputVariable)); fuzzyEngine.addRuleBlock(getRuleBlock(fuzzyEngine, rules, inputVariables, outputVariable));
return getConsequent(engine, values); 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 RuleParseService {
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 RuleParseService(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

@ -0,0 +1,20 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.Rule;
import ru.ulstu.fc.rule.repository.RuleRepository;
import java.util.List;
@Service
public class RuleService {
private final RuleRepository ruleRepository;
public RuleService(RuleRepository ruleRepository) {
this.ruleRepository = ruleRepository;
}
public List<Rule> getRules() {
return ruleRepository.findAll();
}
}

View File

@ -0,0 +1,20 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.Term;
import ru.ulstu.fc.rule.repository.TermRepository;
import java.util.List;
@Service
public class TermService {
private final TermRepository termRepository;
public TermService(TermRepository termRepository) {
this.termRepository = termRepository;
}
public List<Term> getTerms() {
return termRepository.findAll();
}
}

View File

@ -0,0 +1,20 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.Term;
import ru.ulstu.fc.rule.repository.TermRepository;
import java.util.List;
@Service
public class TermsService {
private final TermRepository termRepository;
public TermsService(TermRepository termRepository) {
this.termRepository = termRepository;
}
public List<Term> getTerms() {
return termRepository.findAll();
}
}

View File

@ -0,0 +1,38 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.rule.model.AddVariableForm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.repository.VariableRepository;
import java.util.List;
@Service
public class VariableService {
private final VariableRepository variableRepository;
public VariableService(VariableRepository variableRepository) {
this.variableRepository = variableRepository;
}
public List<Variable> getVars() {
return variableRepository.findAll();
}
public void save(AddVariableForm addVariableForm) {
if (addVariableForm.getId() == null) {
variableRepository.save(new Variable(addVariableForm.getName()));
} else {
Variable dbVar = variableRepository.findById(addVariableForm.getId()).orElseThrow(() -> new RuntimeException("Variable not found by id"));
dbVar.setName(addVariableForm.getName());
variableRepository.save(dbVar);
}
}
public AddVariableForm getAddVariableFormOrDefault(Integer id) {
return id == null
? new AddVariableForm()
: new AddVariableForm(variableRepository.findById(id).orElseThrow(() -> new RuntimeException("Var not foubd by id")));
}
}

View File

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

View File

@ -3,79 +3,20 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}"> layout:decorate="~{default}">
<head> <head>
<title>Простая обработка формы на Spring MVC</title> <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> </head>
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">
<form action="/listRule" th:action="${@route.ADD_RULE}" th:object="${addRuleForm}" method="post"> <form action="/addRule" th:object="${addRuleForm}" method="post">
<input type="hidden" th:field="*{ruleId}">
<div class="row"> <div class="row">
<div class="col-md-2 col-sm-12"> <div class="col-md-2 col-sm-12">
Если <input class="form-control" type="text" th:field="*{rule}">
</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> </div>
<div class="row"> <div class="row">
<div class="col-md-4 col-sm-12"></div>
<div class="col-md-4 col-sm-12"> <div class="col-md-4 col-sm-12">
<input type="submit" class="btn btn-outline-success m-2" th:if="*{ruleId == null}" <input type="submit" class="btn btn-outline-success m-2" value="Создать правило"/>
value="Создать правило"/>
<input type="submit" class="btn btn-outline-success m-2" th:if="*{ruleId != null}"
value="Сохранить правило"/>
</div> </div>
</div> </div>
</form> </form>

View File

@ -0,0 +1,41 @@
<!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>Добавить терм</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<form action="/addTerm" th:object="${addTermForm}" method="post">
<div class="row">
<div class="col-md-2 col-sm-12">
<select id="select-variable" class="selectpicker m-2" data-live-search="true"
th:field="*{variable}"
data-width="90%">
<option th:each="var : ${variables}"
th:value="${var}"
th:utext="${var}">
</option>
</select>
</div>
<div class="col-md-2 col-sm-12">
<input class="form-control" type="text" th:field="*{term}">
</div>
<div class="col-md-2 col-sm-12">
<input class="form-control" type="text" th:field="*{min}">
</div>
<div class="col-md-2 col-sm-12">
<input class="form-control" type="text" th:field="*{max}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
<input type="submit" class="btn btn-outline-success m-2" value="Создать term"/>
</div>
</div>
</form>
</div>
</html>

View File

@ -0,0 +1,25 @@
<!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>Добавить переменную</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<form action="/addVariable" th:object="${addVariableForm}" method="post">
<input type="hidden" th:field="*{id}">
<div class="row">
<div class="col-md-2 col-sm-12">
<input class="form-control" type="text" th:field="*{name}">
</div>
</div>
<div class="row">
<div class="col-md-4 col-sm-12">
<input type="submit" class="btn btn-outline-success m-2" value="Создать переменную"/>
</div>
</div>
</form>
</div>
</html>

View File

@ -21,12 +21,18 @@
</button> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/listVars">Переменные</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/listTerms">Термы</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/listRules">Правила</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/swagger-ui/index.html">API</a> <a class="nav-link" href="/swagger-ui/index.html">API</a>
</li> </li>
<!-- <li class="nav-item">-->
<!-- <a class="nav-link" href="/listRules">Правила</a>-->
<!-- </li>-->
</ul> </ul>
</div> </div>
</nav> </nav>

View File

@ -3,7 +3,7 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}"> layout:decorate="~{default}">
<head> <head>
<title>Простая обработка формы на Spring MVC</title> <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> </head>
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">

View File

@ -0,0 +1,35 @@
<!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>Список термов</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col" colspan="10">Термы</th>
</tr>
</thead>
<tbody>
<tr th:each="dbTerm: ${terms}">
<td><span class="badge badge-success" th:text="${dbTerm.name}"></span></td>
<td>
<a role="button" class="btn btn-info" th:href="@{'addTerm?termId=' + ${dbTerm.id}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
</a>
</td>
<td>
<a role="button" class="btn btn-danger" th:href="@{'deleteTerm?id=' + ${dbTerm.id}}"
onclick="return confirm('Удалить терм?')">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
</td>
</tr>
</tbody>
</table>
<a href="/addTerm" class="btn btn-outline-success">Добавить терм</a>
</div>
</html>

View File

@ -0,0 +1,35 @@
<!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>Список переменных</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col" colspan="10">Переменные</th>
</tr>
</thead>
<tbody>
<tr th:each="dbVar: ${vars}">
<td><span class="badge badge-success" th:text="${dbVar.name}"></span></td>
<td>
<a role="button" class="btn btn-info" th:href="@{'addVariable?id=' + ${dbVar.id}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
</a>
</td>
<td>
<a role="button" class="btn btn-danger" th:href="@{'deleteVar?id=' + ${dbVar.id}}"
onclick="return confirm('Удалить переменную?')">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
</td>
</tr>
</tbody>
</table>
<a href="/addVariable" class="btn btn-outline-success">Добавить переменную</a>
</div>
</html>