Merge pull request '13-register' (#14) from 13-register into master
All checks were successful
CI fuzzy controller / container-test-job (push) Successful in 1m10s

Reviewed-on: #14
This commit is contained in:
romanov73 2025-02-18 14:17:08 +04:00
commit 0d7f970629
32 changed files with 612 additions and 145 deletions

2
.gitignore vendored
View File

@ -2,6 +2,8 @@
# Created by https://www.toptal.com/developers/gitignore/api/intellij,java,maven,gradle,eclipse,netbeans,node # Created by https://www.toptal.com/developers/gitignore/api/intellij,java,maven,gradle,eclipse,netbeans,node
# Edit at https://www.toptal.com/developers/gitignore?templates=intellij,java,maven,gradle,eclipse,netbeans,node # Edit at https://www.toptal.com/developers/gitignore?templates=intellij,java,maven,gradle,eclipse,netbeans,node
data/*
### Eclipse ### ### Eclipse ###
.metadata .metadata
bin/ bin/

12
.vscode/launch.json vendored Normal file
View File

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

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}

View File

@ -14,12 +14,12 @@ import ru.ulstu.fc.user.model.UserRoleConstants;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration { public class SecurityConfiguration {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private final String[] permittedUrls = new String[]{ private final String[] permittedUrls = new String[]{
"/login", "/index", "/login", "/index", "/user/register",
"/public/**", "/organizers", "/webjars/**", "/public/**", "/organizers", "/webjars/**",
"/error", "/register",
"/h2-console/*", "/h2-console", "/h2-console/*", "/h2-console",
"/css/**", "/js/**", "/img/**", "/css/**", "/js/**", "/img/**",
"/templates/**", "/webjars/**"}; "/templates/**", "/webjars/**"};

View File

@ -3,6 +3,7 @@ package ru.ulstu.fc.config;
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect; import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
import org.thymeleaf.spring6.SpringTemplateEngine; import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.ITemplateResolver;
@ -10,10 +11,11 @@ import org.thymeleaf.templateresolver.ITemplateResolver;
public class TemplateConfiguration { public class TemplateConfiguration {
@Bean @Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) { public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver, SpringSecurityDialect sec) {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine(); final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(templateResolver); templateEngine.addTemplateResolver(templateResolver);
templateEngine.addDialect(new LayoutDialect()); templateEngine.addDialect(new LayoutDialect());
templateEngine.addDialect(sec);
return templateEngine; return templateEngine;
} }
} }

View File

@ -10,18 +10,22 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.fc.project.model.Project; import ru.ulstu.fc.project.model.Project;
import ru.ulstu.fc.project.model.ProjectForm; import ru.ulstu.fc.project.model.ProjectForm;
import ru.ulstu.fc.project.service.ProjectRulesService;
import ru.ulstu.fc.project.service.ProjectService; import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.user.model.UserRoleConstants; import ru.ulstu.fc.user.model.UserRoleConstants;
@Controller @Controller
@Hidden @Hidden
@RequestMapping("project") @RequestMapping("project")
@Secured({UserRoleConstants.ADMIN}) @Secured({ UserRoleConstants.ADMIN })
public class ProjectController { public class ProjectController {
private final ProjectService projectService; private final ProjectService projectService;
private final ProjectRulesService projectRulesService;
public ProjectController(ProjectService projectService) { public ProjectController(ProjectService projectService,
ProjectRulesService projectRulesService) {
this.projectService = projectService; this.projectService = projectService;
this.projectRulesService = projectRulesService;
} }
@GetMapping("list") @GetMapping("list")
@ -36,6 +40,8 @@ public class ProjectController {
new ProjectForm((id != null && id != 0) new ProjectForm((id != null && id != 0)
? projectService.getById(id) ? projectService.getById(id)
: new Project())); : new Project()));
model.addAttribute("rules", projectRulesService.getByProjectId(id));
return "project/edit"; return "project/edit";
} }

View File

@ -0,0 +1,12 @@
package ru.ulstu.fc.project.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.fc.rule.model.Rule;
public interface RuleRepository extends JpaRepository<Rule, Integer> {
List<Rule> findByProjectId(Integer projectId);
}

View File

@ -0,0 +1,21 @@
package ru.ulstu.fc.project.service;
import java.util.List;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.repository.RuleRepository;
import ru.ulstu.fc.rule.model.Rule;
@Service
public class ProjectRulesService {
private final RuleRepository ruleRepository;
public ProjectRulesService(RuleRepository ruleRepository) {
this.ruleRepository = ruleRepository;
}
public List<Rule> getByProjectId(Integer projectId) {
return ruleRepository.findByProjectId(projectId);
}
}

View File

@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import ru.ulstu.fc.rule.model.Antecedent; import ru.ulstu.fc.rule.model.Antecedent;
import ru.ulstu.fc.rule.model.InferenceForm; import ru.ulstu.fc.rule.model.InferenceForm;
import ru.ulstu.fc.rule.model.Variable;
import ru.ulstu.fc.rule.model.VariableValue;
import ru.ulstu.fc.rule.service.FuzzyInferenceService; import ru.ulstu.fc.rule.service.FuzzyInferenceService;
import java.util.Arrays; import java.util.Arrays;
@ -26,35 +28,38 @@ public class InferenceMvcController {
@GetMapping("/") @GetMapping("/")
public String initInference(Model model) { public String initInference(Model model) {
model.addAttribute("ageAntecedents", getAgeAntecedents()); model.addAttribute("ageValues", getAgeValues());
model.addAttribute("incomeAntecedents", getIncomeAntecedents()); model.addAttribute("incomeValues", getIncomeValues());
model.addAttribute("inferenceForm", new InferenceForm()); model.addAttribute("inferenceForm", new InferenceForm());
return "index"; return "index";
} }
@RequestMapping(value = "get-inference", method = RequestMethod.POST) @RequestMapping(value = "get-inference", method = RequestMethod.POST)
public String getInference(@ModelAttribute InferenceForm inferenceForm, Model model) { public String getInference(@ModelAttribute InferenceForm inferenceForm, Model model) {
model.addAttribute("ageAntecedents", getAgeAntecedents()); model.addAttribute("ageValues", getAgeValues());
model.addAttribute("incomeAntecedents", getIncomeAntecedents()); model.addAttribute("incomeValues", getIncomeValues());
model.addAttribute("inferenceForm", inferenceForm); model.addAttribute("inferenceForm", inferenceForm);
model.addAttribute("response", fuzzyInferenceService.getFuzzyInference( model.addAttribute("response", fuzzyInferenceService.getFuzzyInference(
Map.of("возраст", Double.valueOf(inferenceForm.getAgeAntecedent()), Map.of("возраст", Double.valueOf(inferenceForm.getAgeValue()),
"доход", Double.valueOf(inferenceForm.getIncomeAntecedent()) "доход", Double.valueOf(inferenceForm.getIncomeValue()))));
)));
return "index"; return "index";
} }
private List<Antecedent> getAgeAntecedents() { private List<VariableValue> getAgeValues() {
return Arrays.asList( Variable var = new Variable("Age");
new Antecedent("молодой", "30"), var.getValues().addAll(Arrays.asList(
new Antecedent("средний", "45"), new VariableValue("молодой", 30.0),
new Antecedent("старый", "60")); new VariableValue("средний", 45.0),
new VariableValue("старый", 60.0)));
return var.getValues();
} }
private List<Antecedent> getIncomeAntecedents() { private List<VariableValue> getIncomeValues() {
return Arrays.asList( Variable var = new Variable("Income");
new Antecedent("небольшой", "20000"), var.getValues().addAll(Arrays.asList(
new Antecedent("средний", "90000"), new VariableValue("небольшой", 20000.0),
new Antecedent("высокий", "200000")); new VariableValue("средний", 90000.0),
new VariableValue("высокий", 200000.0)));
return var.getValues();
} }
} }

View File

@ -0,0 +1,48 @@
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import ru.ulstu.fc.rule.model.Rule;
import ru.ulstu.fc.rule.model.RuleForm;
import ru.ulstu.fc.rule.service.RuleService;
@Controller
@RequestMapping("rule")
public class RuleController {
private final RuleService ruleService;
public RuleController(RuleService ruleService) {
this.ruleService = ruleService;
}
@GetMapping("/edit/{projectId}/{ruleId}")
public String edit(@PathVariable(value = "projectId") Integer projectId,
@PathVariable(value = "ruleId") Integer id, Model model) {
model.addAttribute("projectId", projectId);
model.addAttribute("rule",
new RuleForm((id != null && id != 0)
? ruleService.getById(id)
: new Rule()));
return "rule/edit";
}
@PostMapping(value = "save", params = "save")
public String save(RuleForm ruleForm, Model model) {
model.addAttribute("rule", ruleService.save(ruleForm));
return "redirect:/project/edit/" + ruleForm.getProjectId();
}
@PostMapping(value = "save", params = "delete")
public String delete(RuleForm ruleForm) {
if (ruleForm != null && ruleForm.getId() != null) {
ruleService.delete(ruleForm);
}
return "redirect:/project/edit/" + ruleForm.getProjectId();
}
}

View File

@ -1,19 +1,25 @@
package ru.ulstu.fc.rule.model; package ru.ulstu.fc.rule.model;
public class Antecedent { import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Antecedent extends BaseEntity {
@ManyToOne
private Variable variable;
private String value; private String value;
private String description;
public Antecedent(String description, String value) { public Variable getVariable() {
this.description = description; return variable;
this.value = value; }
public void setVariable(Variable variable) {
this.variable = variable;
} }
public String getValue() { public String getValue() {
return value; return value;
} }
public void setValue(String value) {
public String getDescription() { this.value = value;
return description;
} }
} }

View File

@ -0,0 +1,29 @@
package ru.ulstu.fc.rule.model;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Consequent extends BaseEntity {
@ManyToOne
private Variable variable;
private String value;
public Variable getVariable() {
return variable;
}
public void setVariable(Variable variable) {
this.variable = variable;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -1,22 +1,22 @@
package ru.ulstu.fc.rule.model; package ru.ulstu.fc.rule.model;
public class InferenceForm { public class InferenceForm {
private String ageAntecedent; private String ageValue;
private String incomeAntecedent; private String incomeValue;
public String getAgeAntecedent() { public String getAgeValue() {
return ageAntecedent; return ageValue;
} }
public void setAgeAntecedent(String ageAntecedent) { public void setAgeValue(String ageAntecedent) {
this.ageAntecedent = ageAntecedent; this.ageValue = ageAntecedent;
} }
public String getIncomeAntecedent() { public String getIncomeValue() {
return incomeAntecedent; return incomeValue;
} }
public void setIncomeAntecedent(String incomeAntecedent) { public void setIncomeValue(String incomeAntecedent) {
this.incomeAntecedent = incomeAntecedent; this.incomeValue = incomeAntecedent;
} }
} }

View File

@ -0,0 +1,47 @@
package ru.ulstu.fc.rule.model;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import ru.ulstu.fc.core.model.BaseEntity;
import ru.ulstu.fc.project.model.Project;
@Entity
public class Rule extends BaseEntity {
@ManyToOne
private Project project;
@OneToMany
private List<Antecedent> antecedents; //TODO: AND / OR?
@ManyToOne
private Consequent consequent;
public Rule() {
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public List<Antecedent> getAntecedents() {
return antecedents;
}
public void setAntecedents(List<Antecedent> antecedents) {
this.antecedents = antecedents;
}
public Consequent getConsequent() {
return consequent;
}
public void setConsequent(Consequent consequent) {
this.consequent = consequent;
}
}

View File

@ -0,0 +1,32 @@
package ru.ulstu.fc.rule.model;
public class RuleForm {
private Integer id;
private Integer projectId;
public RuleForm() {
}
public RuleForm(Rule rule) {
this.projectId = (rule == null || rule.getProject() == null)
? null
: rule.getProject().getId();
}
public Integer getProjectId() {
return projectId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
}

View File

@ -1,10 +1,17 @@
package ru.ulstu.fc.rule.model; package ru.ulstu.fc.rule.model;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Variable { import jakarta.persistence.Entity;
import jakarta.persistence.OneToMany;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class Variable extends BaseEntity {
private String name; private String name;
private List<VariableValue> values; @OneToMany
private List<VariableValue> values = new ArrayList<>();
public Variable() { public Variable() {
} }
@ -14,6 +21,10 @@ public class Variable {
this.values = values; this.values = values;
} }
public Variable(String name) {
this.name = name;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -1,6 +1,10 @@
package ru.ulstu.fc.rule.model; package ru.ulstu.fc.rule.model;
public class VariableValue { import jakarta.persistence.Entity;
import ru.ulstu.fc.core.model.BaseEntity;
@Entity
public class VariableValue extends BaseEntity {
private String fuzzyTerm; private String fuzzyTerm;
private Double value; private Double value;

View File

@ -0,0 +1,43 @@
package ru.ulstu.fc.rule.service;
import org.springframework.stereotype.Service;
import ru.ulstu.fc.project.repository.RuleRepository;
import ru.ulstu.fc.project.service.ProjectService;
import ru.ulstu.fc.rule.model.Rule;
import ru.ulstu.fc.rule.model.RuleForm;
@Service
public class RuleService {
private final RuleRepository ruleRepository;
private final ProjectService projectService;
public RuleService(RuleRepository ruleRepository, ProjectService projectService) {
this.ruleRepository = ruleRepository;
this.projectService = projectService;
}
public Rule getById(Integer id) {
return ruleRepository
.findById(id)
.orElseThrow(() -> new RuntimeException("Rule not found by id"));
}
public Object save(RuleForm ruleForm) {
if (ruleForm.getId() == null) {
Rule rule = new Rule();
rule.setProject(projectService.getById(ruleForm.getProjectId()));
// rule.set...
return ruleRepository.save(rule);
}
Rule dbRule = getById(ruleForm.getId());
dbRule.setProject(projectService.getById(ruleForm.getProjectId()));
// dbRule.set ...
return ruleRepository.save(dbRule);
}
public void delete(RuleForm ruleForm) {
getById(ruleForm.getId());
ruleRepository.deleteById(ruleForm.getId());
}
}

View File

@ -0,0 +1,42 @@
package ru.ulstu.fc.user.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
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 org.springframework.web.servlet.ModelAndView;
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;
@Controller
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user/register")
public String showRegistrationForm(WebRequest request, Model model) {
UserDto userDto = new UserDto();
model.addAttribute("user", userDto);
return "register";
}
@PostMapping("/user/register")
public String registerUserAccount(
@ModelAttribute("user") @Valid UserDto userDto,
HttpServletRequest request,
Errors errors) {
userService.createUser(new User(userDto));
return "redirect:/login";
}
}

View File

@ -6,6 +6,7 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable; import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@ -46,6 +47,11 @@ public class User extends BaseEntity {
this.roles = roles; this.roles = roles;
} }
public User(UserDto userDto) {
this.login = userDto.getLogin();
this.password = userDto.getPassword();
}
public String getLogin() { public String getLogin() {
return login; return login;
} }

View File

@ -0,0 +1,40 @@
package ru.ulstu.fc.user.model;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
public class UserDto {
@NotNull
@NotEmpty
private String login;
@NotNull
@NotEmpty
private String password;
private String matchingPassword;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
}

View File

@ -7,6 +7,8 @@ logging.level.ru.ulstu=DEBUG
logging.level.sun.rmi.transport=off logging.level.sun.rmi.transport=off
logging.level.javax.management.remote.rmi=off logging.level.javax.management.remote.rmi=off
logging.level.java.rmi.server=off logging.level.java.rmi.server=off
logging.level.org.apache.tomcat=INFO
logging.level.org.apache.tomcat.util.net=WARN
extractor.custom-projects-dir= extractor.custom-projects-dir=
server.error.include-stacktrace=always server.error.include-stacktrace=always
server.error.include-exception=true server.error.include-exception=true

View File

@ -1,57 +1,71 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru" <html lang="ru" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"> xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<title>Нечеткий контроллер</title> <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/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/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> <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/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/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/font-awesome/4.7.0/css/font-awesome.min.css" />
</head> </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"
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>
</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"> <body>
<div id="breadcrumbs" class="container-fluid"> <nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
</div> <a class="navbar-brand" href="/">Нечеткий контроллер</a>
<div class="container-fluid"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
<ul id="messages" class="feedback-panel"> aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}"> <span class="navbar-toggler-icon"></span>
</div> </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> </ul>
</div> </div>
<div layout:fragment="content"> </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> </div>
</div> </div>
</div>
</body> </body>
</html> </html>

View File

@ -25,11 +25,11 @@
</div> </div>
<div class="col-md-6 col-sm-12"> <div class="col-md-6 col-sm-12">
<select id="select-age-antecedent" class="selectpicker m-2" data-live-search="true" <select id="select-age-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{ageAntecedent}" th:field="*{ageValue}"
data-width="90%"> data-width="90%">
<option th:each="ageAntecedent : ${ageAntecedents}" <option th:each="ageValue : ${ageValues}"
th:value="${ageAntecedent.value}" th:value="${ageValue.value}"
th:utext="${ageAntecedent.description}"> th:utext="${ageValue.fuzzyTerm}">
</option> </option>
</select> </select>
</div> </div>
@ -40,11 +40,11 @@
</div> </div>
<div class="col-md-6 col-sm-12"> <div class="col-md-6 col-sm-12">
<select id="select-income-antecedent" class="selectpicker m-2" data-live-search="true" <select id="select-income-antecedent" class="selectpicker m-2" data-live-search="true"
th:field="*{incomeAntecedent}" th:field="*{incomeValue}"
data-width="90%"> data-width="90%">
<option th:each="incomeAntecedent : ${incomeAntecedents}" <option th:each="incomeValue : ${incomeValues}"
th:value="${incomeAntecedent.value}" th:value="${incomeValue.value}"
th:utext="${incomeAntecedent.description}"> th:utext="${incomeValue.fuzzyTerm}">
</option> </option>
</select> </select>
</div> </div>

View File

@ -1,42 +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>Список правил</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="dbRule: ${rules}">
<td><span class="badge badge-info">Если</span></td>
<td><span class="badge badge-success" th:text="${dbRule.firstAntecedent.description}"></span></td>
<td><span class="badge badge-success" th:text="${dbRule.firstAntecedentValue.antecedentValue}"></span></td>
<td><span class="badge badge-info">и</span></td>
<td><span class="badge badge-success" th:text="${dbRule.secondAntecedent.description }"></span></td>
<td><span class="badge badge-success" th:text="${dbRule.secondAntecedentValue.antecedentValue}"></span></td>
<td><span class="badge badge-info">то</span></td>
<td><span class="badge badge-warning" th:text="${dbRule.consequent}"></span></td>
<td>
<a role="button" class="btn btn-info" th:href="@{${@route.ADD_RULE} + '?ruleId=' + ${dbRule.id}}">
<i class="fa fa-pencil-square-o" aria-hidden="true"></i>
</a>
</td>
<td>
<a role="button" class="btn btn-danger" th:href="@{'deleteRule?id=' + ${dbRule.id}}"
onclick="return confirm('Удалить правило?')">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
</td>
</tr>
</tbody>
</table>
<a href="/addRule" class="btn btn-outline-success">Добавить правило</a>
</div>
</html>

View File

@ -24,7 +24,8 @@
<input type="password" name="password" id="password" class="form-control" <input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/> placeholder="Пароль" required="true"/>
</div> </div>
<button type="submit" class="btn btn-outline-dark btn-block">Войти</button> <button type="submit" class="btn btn-outline-dark">Войти</button>
<a href="/user/register" class="btn btn-outline-dark">Регистрация</a>
</fieldset> </fieldset>
</form> </form>
</div> </div>

View File

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

View File

@ -35,5 +35,39 @@
</button> </button>
<a href="/project/list" class="btn btn-outline-dark">Отмена</a> <a href="/project/list" class="btn btn-outline-dark">Отмена</a>
</form> </form>
<hr/>
<h4> Список правил</h4>
<div class="row" th:each="r, iter : ${rules}">
<div class="col col-md-12">
<span class="badge badge-light" th:text="${iter} + ' Если'"></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 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'}" class="btn btn-outline-dark">Добавить правило</a>
</div> </div>
</html> </html>

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>Список правил</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,30 @@
<!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">
<h3> Список правил</h3>
<div class="rowд">
<div class="col col-md-12">
<span class="badge badge-light">1. Если</span>
</div>
<div class="col col-md-3">
<span class="badge badge-primary">Переменная</span>
</div>
<div class="col col-md-3">
<span class="badge badge-light">есть</span>
</div>
<div class="col col-md-3">
<span class="badge badge-success">значение</span>
</div>
<div class="col col-md-3">
<span class="badge badge-danger">И / ИЛИ</span>
</div>
</div>
</div>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{default}">
<div class="container" layout:fragment="content">
<h3>Регистрация</h3>
<form action="/user/register" th:object="${user}" method="POST" enctype="utf8">
<div class="form-group">
<label for="login">Логин</label>
<input th:field="*{login}" id="login" type="text" required class="form-control"
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="Пароль">
<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="Подтверждение пароля"/>
</div>
<button type="submit" class="btn btn-outline-dark">Зарегистрировать</button>
<a href="/login" class="btn btn-outline-dark">Вернуться на страницу входа</a>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!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">
<h3>Редактирование правила:</h3>
<form th:action="@{/rule/save}" th:object="${rule}" method="post">
<input type="hidden" th:field="${projectId}">
<input type="hidden" th:field="*{id}">
<div class="form-group">
<label for="name">Название</label>
</div>
<button name="save" type="submit" class="btn btn-outline-dark">Сохранить</button>
<button name="delete"
type="submit"
class="btn btn-outline-dark"
onclick="return confirm('Удалить запись?')">
Удалить
</button>
<a th:href="@{'/project/edit/' + ${projectId}}" class="btn btn-outline-dark">Отмена</a>
</form>
</div>
</html>