Merge branch 'master' into 3-parse-rule
Some checks failed
CI fuzzy controller / container-test-job (push) Failing after 52s
Some checks failed
CI fuzzy controller / container-test-job (push) Failing after 52s
# Conflicts: # src/main/java/ru/ulstu/fc/rule/controller/RuleController.java # src/main/java/ru/ulstu/fc/rule/model/Variable.java # src/main/java/ru/ulstu/fc/rule/repository/VariableRepository.java # src/main/java/ru/ulstu/fc/rule/service/FuzzyInferenceService.java # src/main/java/ru/ulstu/fc/rule/service/VariableService.java # src/main/resources/templates/default.html # src/main/resources/templates/listRules.html
This commit is contained in:
parent
2e0478e9d2
commit
900cfdd036
15
.gitea/workflows/test.yaml
Normal file
15
.gitea/workflows/test.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
name: CI fuzzy controller
|
||||||
|
on: [ push ]
|
||||||
|
jobs:
|
||||||
|
container-test-job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up JDK 21 for x64
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '21'
|
||||||
|
distribution: 'temurin'
|
||||||
|
architecture: x64
|
||||||
|
- name: Test with Gradle
|
||||||
|
run: bash ./gradlew test
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
12
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "java",
|
||||||
|
"name": "FuzzyControllerApplication",
|
||||||
|
"request": "launch",
|
||||||
|
"mainClass": "ru.ulstu.fc.FuzzyControllerApplication",
|
||||||
|
"projectName": "fuzzy-controller"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "interactive",
|
||||||
|
"java.compile.nullAnalysis.mode": "disabled"
|
||||||
|
}
|
31
Jenkinsfile
vendored
Normal file
31
Jenkinsfile
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
tools {
|
||||||
|
jdk 'jdk-21'
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh "sh ./gradlew clean build"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Deploy') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh "bash deploy/nio17.sh &"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
script {
|
||||||
|
if (currentBuild.currentResult == 'FAILURE') {
|
||||||
|
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: "a.romanov@ulstu.ru", sendToIndividuals: true])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
README.md
24
README.md
@ -1,2 +1,24 @@
|
|||||||
# fuzzy-controller
|
# Нечеткий контроллер
|
||||||
|
|
||||||
|
Порядок развертывания проекта разработчиками:
|
||||||
|
|
||||||
|
1. Скачать и установить JDK (используется 21 LTS
|
||||||
|
JDK): https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe
|
||||||
|
|
||||||
|
2. Проверить установку, набрав в консоли команду "java -version"
|
||||||
|
|
||||||
|
3. Скачать и установить IDE: IntelliJIDEA Сommunity
|
||||||
|
version https://www.jetbrains.com/ru-ru/idea/download/#section=windows
|
||||||
|
|
||||||
|
ИЛИ
|
||||||
|
|
||||||
|
Visual Studio Code https://code.visualstudio.com/
|
||||||
|
|
||||||
|
4. Скачать и открыть проект в IDE:
|
||||||
|
|
||||||
|

|
||||||
|
5. Сформировать конфигурацию для запуска:
|
||||||
|

|
||||||
|
6. Запустить проект.
|
||||||
|
7. Открыть страницу в браузере http://localhost:8080/
|
||||||
|
8. Демо: http://plans.athene.tech/
|
||||||
|
78
client example.py
Normal file
78
client example.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
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())
|
4
deploy/nio17.sh
Normal file
4
deploy/nio17.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/
|
||||||
|
bash ./gradlew assemble
|
||||||
|
scp -o StrictHostKeyChecking=no build/libs/fuzzy-controller-0.0.1-SNAPSHOT.jar root@192.168.1.129:/root/fuzzy-controller.jar
|
||||||
|
ssh root@192.168.1.129 "killall java >> /dev/null && /opt/jdk-21/bin/java -jar /root/fuzzy-controller.jar >> /root/fc.log &"
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -2,11 +2,28 @@ package ru.ulstu.fc;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import ru.ulstu.fc.user.service.UserService;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableConfigurationProperties
|
||||||
public class FuzzyControllerApplication {
|
public class FuzzyControllerApplication {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public FuzzyControllerApplication(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(FuzzyControllerApplication.class, args);
|
SpringApplication.run(FuzzyControllerApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void doSomethingAfterStartup() {
|
||||||
|
System.out.println("hello world, I have just started up");
|
||||||
|
userService.initDefaultAdmin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
12
src/main/java/ru/ulstu/fc/config/Constants.java
Normal file
12
src/main/java/ru/ulstu/fc/config/Constants.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static final int MIN_PASSWORD_LENGTH = 6;
|
||||||
|
|
||||||
|
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
|
||||||
|
|
||||||
|
public static final String COOKIES_NAME = "JSESSIONID";
|
||||||
|
public static final String LOGOUT_URL = "/login?logout";
|
||||||
|
public static final String SESSION_ID_ATTR = "sessionId";
|
||||||
|
public static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package ru.ulstu.fc.config;
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@ -7,25 +8,13 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
|
|||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||||
import springfox.documentation.annotations.ApiIgnore;
|
|
||||||
|
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
@ApiIgnore
|
@Hidden
|
||||||
class GlobalDefaultExceptionHandler {
|
class GlobalDefaultExceptionHandler {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);
|
private final static Logger LOG = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);
|
||||||
public static final String DEFAULT_ERROR_VIEW = "error";
|
public static final String DEFAULT_ERROR_VIEW = "error";
|
||||||
|
|
||||||
|
|
||||||
// @ExceptionHandler(value = Exception.class)
|
|
||||||
// public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) {
|
|
||||||
// LOG.warn(e.getMessage());
|
|
||||||
// ModelAndView mav = new ModelAndView();
|
|
||||||
// mav.addObject("exception", e);
|
|
||||||
// mav.addObject("url", req.getRequestURL());
|
|
||||||
// mav.setViewName(DEFAULT_ERROR_VIEW);
|
|
||||||
// return mav;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@ExceptionHandler(NoHandlerFoundException.class)
|
@ExceptionHandler(NoHandlerFoundException.class)
|
||||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||||
public String handle(NoHandlerFoundException ex) {
|
public String handle(NoHandlerFoundException ex) {
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 Anton Romanov - All Rights Reserved
|
|
||||||
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ru.ulstu.fc.config;
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -11,19 +5,19 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.web.servlet.LocaleResolver;
|
import org.springframework.web.servlet.LocaleResolver;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MvcConfiguration implements WebMvcConfigurer {
|
public class MvcConfiguration implements WebMvcConfigurer {
|
||||||
// @Override
|
@Override
|
||||||
// public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
// registry.addViewController("/index");
|
registry.addViewController("/login");
|
||||||
// }
|
registry.addViewController("/loginError");
|
||||||
|
registry.addViewController("/index");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
@ -44,14 +38,6 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
return localeInterceptor;
|
return localeInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Docket api() {
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.select()
|
|
||||||
.apis(RequestHandlerSelectors.basePackage("ru.ulstu"))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(localeInterceptor());
|
registry.addInterceptor(localeInterceptor());
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class PasswordEncoderConfiguration {
|
||||||
|
@Bean
|
||||||
|
public BCryptPasswordEncoder bCryptPasswordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
}
|
51
src/main/java/ru/ulstu/fc/config/SecurityConfiguration.java
Normal file
51
src/main/java/ru/ulstu/fc/config/SecurityConfiguration.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import ru.ulstu.fc.user.model.UserRoleConstants;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class SecurityConfiguration {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
|
||||||
|
private final String[] permittedUrls = new String[]{
|
||||||
|
"/login", "/index", "/user/register",
|
||||||
|
"/public/**", "/organizers", "/webjars/**",
|
||||||
|
"/error", "/register",
|
||||||
|
"/h2-console/*", "/h2-console",
|
||||||
|
"/css/**", "/js/**", "/img/**",
|
||||||
|
"/templates/**", "/webjars/**"};
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
log.debug("Security enabled");
|
||||||
|
|
||||||
|
http
|
||||||
|
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
.authorizeHttpRequests(auth ->
|
||||||
|
auth.requestMatchers("/").permitAll()
|
||||||
|
.requestMatchers(permittedUrls).permitAll()
|
||||||
|
.requestMatchers("/swagger-ui.html").hasAuthority(UserRoleConstants.ADMIN)
|
||||||
|
.anyRequest().authenticated())
|
||||||
|
.formLogin(form ->
|
||||||
|
form.loginPage("/login")
|
||||||
|
.failureUrl("/loginError")
|
||||||
|
.permitAll())
|
||||||
|
.logout(logout ->
|
||||||
|
logout
|
||||||
|
.logoutSuccessUrl(Constants.LOGOUT_URL)
|
||||||
|
.invalidateHttpSession(false)
|
||||||
|
.clearAuthentication(true)
|
||||||
|
.deleteCookies(Constants.COOKIES_NAME)
|
||||||
|
.permitAll());
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,21 @@
|
|||||||
package ru.ulstu.fc.config;
|
package ru.ulstu.fc.config;
|
||||||
|
|
||||||
import nz.net.ultraq.thymeleaf.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.spring5.SpringTemplateEngine;
|
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
|
||||||
|
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package ru.ulstu.fc.config;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class WebClientConfiguration {
|
|
||||||
@Bean
|
|
||||||
public WebClient webClient(WebClient.Builder webClientBuilder) {
|
|
||||||
return webClientBuilder.build();
|
|
||||||
}
|
|
||||||
}
|
|
84
src/main/java/ru/ulstu/fc/core/model/BaseEntity.java
Normal file
84
src/main/java/ru/ulstu/fc/core/model/BaseEntity.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package ru.ulstu.fc.core.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.MappedSuperclass;
|
||||||
|
import jakarta.persistence.Version;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public abstract class BaseEntity implements Serializable, Comparable<BaseEntity> {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private Integer version;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(Integer version) {
|
||||||
|
this.version = 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.id != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!id.equals(other.id)) {
|
||||||
|
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(@NotNull BaseEntity o) {
|
||||||
|
return id != null ? id.compareTo(o.getId()) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.id = null;
|
||||||
|
this.version = null;
|
||||||
|
}
|
||||||
|
}
|
119
src/main/java/ru/ulstu/fc/core/model/OffsetablePageRequest.java
Normal file
119
src/main/java/ru/ulstu/fc/core/model/OffsetablePageRequest.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package ru.ulstu.fc.core.model;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class OffsetablePageRequest implements Pageable, Serializable {
|
||||||
|
private final int offset;
|
||||||
|
private final int count;
|
||||||
|
private final Sort sort;
|
||||||
|
|
||||||
|
public OffsetablePageRequest(int page, long pageSize) {
|
||||||
|
this(pageSize * page, pageSize, Sort.by("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetablePageRequest(long offset, long count, Sort sort) {
|
||||||
|
if (offset < 0) {
|
||||||
|
throw new IllegalArgumentException("Offset value must not be less than zero!");
|
||||||
|
}
|
||||||
|
if (count < 1) {
|
||||||
|
throw new IllegalArgumentException("Count value must not be less than one!");
|
||||||
|
}
|
||||||
|
this.offset = (int) offset;
|
||||||
|
this.count = (int) count;
|
||||||
|
this.sort = sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sort getSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sort getSortOr(Sort sort) {
|
||||||
|
return Pageable.super.getSortOr(sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPageSize() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPaged() {
|
||||||
|
return Pageable.super.isPaged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnpaged() {
|
||||||
|
return Pageable.super.isUnpaged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPageNumber() {
|
||||||
|
return offset / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPrevious() {
|
||||||
|
return offset > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Pageable> toOptional() {
|
||||||
|
return Pageable.super.toOptional();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable next() {
|
||||||
|
return new OffsetablePageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable previousOrFirst() {
|
||||||
|
return hasPrevious() ? previous() : first();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pageable previous() {
|
||||||
|
return getOffset() == 0 ? this : new OffsetablePageRequest(getOffset() - getPageSize(), getPageSize(), getSort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable first() {
|
||||||
|
return new OffsetablePageRequest(0, getPageSize(), getSort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pageable withPage(int pageNumber) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final OffsetablePageRequest other = (OffsetablePageRequest) obj;
|
||||||
|
return this.offset == other.offset && this.count == other.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + offset;
|
||||||
|
result = prime * result + count;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
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.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
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.ProjectVariableService;
|
||||||
|
import ru.ulstu.fc.user.model.UserRoleConstants;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@Hidden
|
||||||
|
@RequestMapping("project")
|
||||||
|
@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) {
|
||||||
|
this.projectService = projectService;
|
||||||
|
this.projectRulesService = projectRulesService;
|
||||||
|
this.projectVariableService = projectVariableService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public String getProjects(Model model) {
|
||||||
|
model.addAttribute("projects", projectService.getCurrentUserProjects());
|
||||||
|
return "project/list";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/edit/{projectId}")
|
||||||
|
public String edit(@PathVariable(value = "projectId") Integer id, Model model) {
|
||||||
|
model.addAttribute("project",
|
||||||
|
new ProjectForm((id != null && id != 0)
|
||||||
|
? projectService.getById(id)
|
||||||
|
: new Project()));
|
||||||
|
|
||||||
|
model.addAttribute("rules", projectRulesService.getByProjectId(id));
|
||||||
|
model.addAttribute("variables", projectVariableService.getByProjectId(id));
|
||||||
|
return "project/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "save")
|
||||||
|
public String save(ProjectForm projectForm, Model model) {
|
||||||
|
model.addAttribute("project", projectService.save(projectForm));
|
||||||
|
return "redirect:/project/list";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "delete")
|
||||||
|
public String delete(ProjectForm projectForm) {
|
||||||
|
if (projectForm != null && projectForm.getId() != null) {
|
||||||
|
projectService.delete(projectForm);
|
||||||
|
}
|
||||||
|
return "redirect:/project/list";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package ru.ulstu.fc.project.controller;
|
||||||
|
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
import ru.ulstu.fc.project.model.ProjectForm;
|
||||||
|
import ru.ulstu.fc.project.service.ProjectService;
|
||||||
|
import ru.ulstu.fc.user.model.UserRoleConstants;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("projectRest")
|
||||||
|
@Secured({UserRoleConstants.ADMIN})
|
||||||
|
public class ProjectRestController {
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
|
public ProjectRestController(ProjectService projectService) {
|
||||||
|
this.projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<Project> getProjects() {
|
||||||
|
return projectService.getCurrentUserProjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public Project save(Project project) {
|
||||||
|
return projectService.save(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("delete")
|
||||||
|
public String delete(ProjectForm projectForm) {
|
||||||
|
projectService.delete(projectForm);
|
||||||
|
return "redirect:/list";
|
||||||
|
}
|
||||||
|
}
|
53
src/main/java/ru/ulstu/fc/project/model/Project.java
Normal file
53
src/main/java/ru/ulstu/fc/project/model/Project.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package ru.ulstu.fc.project.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
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 = "Текст новости не может быть пустым")
|
||||||
|
private String name;
|
||||||
|
private Date createDate = new Date();
|
||||||
|
@ManyToOne(cascade = CascadeType.MERGE)
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public Project() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project(ProjectForm projectForm) {
|
||||||
|
if (projectForm.getId() != null) {
|
||||||
|
setId(projectForm.getId());
|
||||||
|
}
|
||||||
|
this.name = projectForm.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateDate() {
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateDate(Date createDate) {
|
||||||
|
this.createDate = createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
}
|
38
src/main/java/ru/ulstu/fc/project/model/ProjectForm.java
Normal file
38
src/main/java/ru/ulstu/fc/project/model/ProjectForm.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package ru.ulstu.fc.project.model;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class ProjectForm {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
public ProjectForm() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectForm(Project project) {
|
||||||
|
this.id = project.getId();
|
||||||
|
this.name = project.getName();
|
||||||
|
this.createDate = project.getCreateDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateDate() {
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package ru.ulstu.fc.project.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ProjectRepository extends JpaRepository<Project, Integer> {
|
||||||
|
|
||||||
|
List<Project> findAllByUserId(@Param("userId") Integer userId);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ProjectRulesService {
|
||||||
|
private final FuzzyRuleRepository ruleRepository;
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
|
public ProjectRulesService(FuzzyRuleRepository ruleRepository,
|
||||||
|
ProjectService projectService) {
|
||||||
|
this.ruleRepository = ruleRepository;
|
||||||
|
this.projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FuzzyRule> getByProjectId(Integer projectId) {
|
||||||
|
if (projectId == null || projectId == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return ruleRepository.findByProject(projectService.getById(projectId));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package ru.ulstu.fc.project.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
import ru.ulstu.fc.project.model.ProjectForm;
|
||||||
|
import ru.ulstu.fc.project.repository.ProjectRepository;
|
||||||
|
import ru.ulstu.fc.user.model.User;
|
||||||
|
import ru.ulstu.fc.user.service.UserService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ProjectService {
|
||||||
|
private final ProjectRepository projectRepository;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public ProjectService(ProjectRepository projectRepository,
|
||||||
|
UserService userService) {
|
||||||
|
this.projectRepository = projectRepository;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Project> getCurrentUserProjects() {
|
||||||
|
return projectRepository.findAllByUserId(userService.getCurrentUser().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getById(Integer id) {
|
||||||
|
Project project = projectRepository
|
||||||
|
.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Project not found by id"));
|
||||||
|
checkUserProjectWithThrow(project, userService.getCurrentUser());
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project save(ProjectForm projectForm) {
|
||||||
|
return save(new Project(projectForm));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project save(Project projectToSave) {
|
||||||
|
User currentUser = userService.getCurrentUser();
|
||||||
|
if (projectToSave.getId() == null) {
|
||||||
|
projectToSave.setUser(currentUser);
|
||||||
|
return projectRepository.save(projectToSave);
|
||||||
|
}
|
||||||
|
Project dbProject = getById(projectToSave.getId());
|
||||||
|
dbProject.setName(projectToSave.getName());
|
||||||
|
return projectRepository.save(dbProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(ProjectForm projectForm) {
|
||||||
|
getById(projectForm.getId());
|
||||||
|
projectRepository.deleteById(projectForm.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUserProjectWithThrow(Project project, User currentUser) {
|
||||||
|
if (!isUserProject(project, currentUser)) {
|
||||||
|
throw new RuntimeException("User can not get access to project");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUserProject(Project project, User currentUser) {
|
||||||
|
return (currentUser.equals(project.getUser()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ProjectVariableService {
|
||||||
|
private final VariableRepository variableRepository;
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
|
public ProjectVariableService(VariableRepository variableRepository,
|
||||||
|
ProjectService projectService) {
|
||||||
|
this.variableRepository = variableRepository;
|
||||||
|
this.projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Variable> getByProjectId(Integer projectId) {
|
||||||
|
if (projectId == null || projectId == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return variableRepository.findByProject(projectService.getById(projectId));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
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;
|
||||||
|
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.FuzzyTermForm;
|
||||||
|
import ru.ulstu.fc.rule.service.FuzzyTermService;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("fuzzyTerm")
|
||||||
|
public class FuzzyTermController {
|
||||||
|
private final FuzzyTermService fuzzyTermService;
|
||||||
|
|
||||||
|
public FuzzyTermController(FuzzyTermService fuzzyTermService) {
|
||||||
|
this.fuzzyTermService = fuzzyTermService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
model.addAttribute("projectId", projectId);
|
||||||
|
model.addAttribute("variableId", variableId);
|
||||||
|
model.addAttribute("fuzzyTermForm",
|
||||||
|
(fuzzyTermId == null || fuzzyTermId == 0)
|
||||||
|
? new FuzzyTermForm(fuzzyTermId, projectId, variableId)
|
||||||
|
: new FuzzyTermForm(fuzzyTermId, projectId, variableId, fuzzyTermService.getById(fuzzyTermId)));
|
||||||
|
model.addAttribute("fuzzyTerms", fuzzyTermService.getByVariableId(variableId));
|
||||||
|
return "fuzzyTerm/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "save")
|
||||||
|
public String save(@Valid FuzzyTermForm fuzzyTermForm, BindingResult result, Model model) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
model.addAttribute("projectId", fuzzyTermForm.getProjectId());
|
||||||
|
return "fuzzyTerm/edit";
|
||||||
|
}
|
||||||
|
fuzzyTermService.save(fuzzyTermForm);
|
||||||
|
return "redirect:/variable/edit/" + fuzzyTermForm.getProjectId() + "/" + fuzzyTermForm.getVariableId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "delete")
|
||||||
|
public String delete(FuzzyTermForm fuzzyTermForm) {
|
||||||
|
if (fuzzyTermForm != null && fuzzyTermForm.getId() != null) {
|
||||||
|
fuzzyTermService.delete(fuzzyTermForm);
|
||||||
|
}
|
||||||
|
return "redirect:/variable/edit/" + fuzzyTermForm.getProjectId() + "/" + fuzzyTermForm.getVariableId();
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,23 @@
|
|||||||
package ru.ulstu.fc.rule.controller;
|
package ru.ulstu.fc.rule.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
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.FuzzyTerm;
|
||||||
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.service.FuzzyInferenceService;
|
import ru.ulstu.fc.rule.service.FuzzyInferenceService;
|
||||||
import springfox.documentation.annotations.ApiIgnore;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@ApiIgnore
|
@Hidden
|
||||||
public class InferenceMvcController {
|
public class InferenceMvcController {
|
||||||
private final FuzzyInferenceService fuzzyInferenceService;
|
private final FuzzyInferenceService fuzzyInferenceService;
|
||||||
|
|
||||||
@ -26,35 +27,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<FuzzyTerm> getAgeValues() {
|
||||||
return Arrays.asList(
|
Variable var = new Variable("Age");
|
||||||
new Antecedent("молодой", "30"),
|
var.getFuzzyTerms().addAll(Arrays.asList(
|
||||||
new Antecedent("средний", "45"),
|
new FuzzyTerm("молодой", 30.0),
|
||||||
new Antecedent("старый", "60"));
|
new FuzzyTerm("средний", 45.0),
|
||||||
|
new FuzzyTerm("старый", 60.0)));
|
||||||
|
return var.getFuzzyTerms();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Antecedent> getIncomeAntecedents() {
|
private List<FuzzyTerm> getIncomeValues() {
|
||||||
return Arrays.asList(
|
Variable var = new Variable("Income");
|
||||||
new Antecedent("небольшой", "20000"),
|
var.getFuzzyTerms().addAll(Arrays.asList(
|
||||||
new Antecedent("средний", "90000"),
|
new FuzzyTerm("небольшой", 20000.0),
|
||||||
new Antecedent("высокий", "200000"));
|
new FuzzyTerm("средний", 90000.0),
|
||||||
|
new FuzzyTerm("высокий", 200000.0)));
|
||||||
|
return var.getFuzzyTerms();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import ru.ulstu.fc.rule.service.FuzzyInferenceService;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("rest")
|
@RequestMapping("inferenceRest")
|
||||||
public class InferenceRestController {
|
public class InferenceRestController {
|
||||||
private final FuzzyInferenceService fuzzyInferenceService;
|
private final FuzzyInferenceService fuzzyInferenceService;
|
||||||
|
|
||||||
|
@ -1,96 +1,51 @@
|
|||||||
package ru.ulstu.fc.rule.controller;
|
package ru.ulstu.fc.rule.controller;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import ru.ulstu.fc.rule.model.AddRuleForm;
|
import ru.ulstu.fc.rule.model.FuzzyRuleForm;
|
||||||
import ru.ulstu.fc.rule.model.AddTermForm;
|
import ru.ulstu.fc.rule.service.FuzzyRuleService;
|
||||||
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
|
@Controller
|
||||||
|
@RequestMapping("rule")
|
||||||
public class RuleController {
|
public class RuleController {
|
||||||
private final RuleParseService ruleParseService;
|
private final FuzzyRuleService ruleService;
|
||||||
private final RuleService ruleService;
|
|
||||||
private final TermsService termService;
|
|
||||||
private final VariableService variableService;
|
|
||||||
|
|
||||||
public RuleController(RuleParseService ruleParseService,
|
public RuleController(FuzzyRuleService ruleService) {
|
||||||
RuleService ruleService,
|
|
||||||
TermsService termService,
|
|
||||||
VariableService variableService) {
|
|
||||||
this.ruleParseService = ruleParseService;
|
|
||||||
this.ruleService = ruleService;
|
this.ruleService = ruleService;
|
||||||
this.termService = termService;
|
|
||||||
this.variableService = variableService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("listRules")
|
@GetMapping("/edit/{projectId}/{ruleId}")
|
||||||
public String listRules(Model model) {
|
public String edit(@PathVariable(value = "projectId") Integer projectId,
|
||||||
model.addAttribute("rules", ruleService.getRules());
|
@PathVariable(value = "ruleId") Integer id, Model model) {
|
||||||
return "listRules";
|
model.addAttribute("projectId", projectId);
|
||||||
|
model.addAttribute("fuzzyRuleForm",
|
||||||
|
(id != null && id != 0)
|
||||||
|
? new FuzzyRuleForm(id, ruleService.getById(id))
|
||||||
|
: new FuzzyRuleForm(id, projectId));
|
||||||
|
return "rule/edit";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("listTerms")
|
@PostMapping(value = "save", params = "save")
|
||||||
public String listTerms(Model model) {
|
public String save(@Valid FuzzyRuleForm fuzzyRuleForm, BindingResult bindingResult, Model model) {
|
||||||
model.addAttribute("terms", termService.getTerms());
|
if (bindingResult.hasErrors()) {
|
||||||
return "listTerms";
|
model.addAttribute("projectId", fuzzyRuleForm.getProjectId());
|
||||||
}
|
return "rule/edit";
|
||||||
|
|
||||||
@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);
|
ruleService.save(fuzzyRuleForm);
|
||||||
return "listRules";
|
return "redirect:/project/edit/" + fuzzyRuleForm.getProjectId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("addVariable")
|
@PostMapping(value = "save", params = "delete")
|
||||||
public String addVariable(Model model, @RequestParam(required = false) Integer id) {
|
public String delete(FuzzyRuleForm fuzzyRuleForm) {
|
||||||
model.addAttribute("addVariableForm", variableService.getAddVariableFormOrDefault(id));
|
if (fuzzyRuleForm != null && fuzzyRuleForm.getId() != null) {
|
||||||
return "addVariable";
|
ruleService.delete(fuzzyRuleForm);
|
||||||
}
|
}
|
||||||
|
return "redirect:/project/edit/" + fuzzyRuleForm.getProjectId();
|
||||||
@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";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
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;
|
||||||
|
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.VariableForm;
|
||||||
|
import ru.ulstu.fc.rule.service.FuzzyTermService;
|
||||||
|
import ru.ulstu.fc.rule.service.VariableService;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("variable")
|
||||||
|
public class VariableController {
|
||||||
|
private final VariableService variableService;
|
||||||
|
private final FuzzyTermService termService;
|
||||||
|
|
||||||
|
public VariableController(VariableService variableService,
|
||||||
|
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) {
|
||||||
|
model.addAttribute("projectId", projectId);
|
||||||
|
model.addAttribute("variableForm",
|
||||||
|
(variableId == null || variableId == 0)
|
||||||
|
? new VariableForm(variableId, projectId)
|
||||||
|
: new VariableForm(variableId, variableService.getById(variableId)));
|
||||||
|
model.addAttribute("fuzzyTerms", termService.getByVariableId(variableId));
|
||||||
|
return "variable/edit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "save")
|
||||||
|
public String save(@Valid VariableForm variableForm, BindingResult result, Model model) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
model.addAttribute("projectId", variableForm.getProjectId());
|
||||||
|
return "variable/edit";
|
||||||
|
}
|
||||||
|
variableService.save(variableForm);
|
||||||
|
return "redirect:/project/edit/" + variableForm.getProjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "save", params = "delete")
|
||||||
|
public String delete(VariableForm variableForm) {
|
||||||
|
if (variableForm != null && variableForm.getId() != null) {
|
||||||
|
variableService.delete(variableForm);
|
||||||
|
}
|
||||||
|
return "redirect:/project/edit/" + variableForm.getProjectId();
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
package ru.ulstu.fc.rule.model;
|
|
||||||
|
|
||||||
public class Antecedent {
|
|
||||||
private String value;
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
public Antecedent(String description, String value) {
|
|
||||||
this.description = description;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
36
src/main/java/ru/ulstu/fc/rule/model/FuzzyRule.java
Normal file
36
src/main/java/ru/ulstu/fc/rule/model/FuzzyRule.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import ru.ulstu.fc.core.model.BaseEntity;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class FuzzyRule extends BaseEntity {
|
||||||
|
@ManyToOne
|
||||||
|
@NotNull
|
||||||
|
private Project project;
|
||||||
|
@Size(min = 5, max = 250, message = "Длина от 5 до 250 символов")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public FuzzyRule() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getProject() {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProject(Project project) {
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/ru/ulstu/fc/rule/model/FuzzyRuleForm.java
Normal file
52
src/main/java/ru/ulstu/fc/rule/model/FuzzyRuleForm.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class FuzzyRuleForm {
|
||||||
|
private Integer id;
|
||||||
|
@NotNull
|
||||||
|
private Integer projectId;
|
||||||
|
|
||||||
|
@Size(min = 5, max = 250, message = "Длина от 5 до 250 символов")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public FuzzyRuleForm() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyRuleForm(Integer id, Integer projectId) {
|
||||||
|
this.id = id;
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyRuleForm(Integer id, FuzzyRule fuzzyRule) {
|
||||||
|
this.id = fuzzyRule.getId();
|
||||||
|
this.projectId = fuzzyRule.getProject().getId();
|
||||||
|
this.content = fuzzyRule.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
src/main/java/ru/ulstu/fc/rule/model/FuzzyTerm.java
Normal file
34
src/main/java/ru/ulstu/fc/rule/model/FuzzyTerm.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import ru.ulstu.fc.core.model.BaseEntity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class FuzzyTerm extends BaseEntity {
|
||||||
|
private String description;
|
||||||
|
private Double crispValue;
|
||||||
|
|
||||||
|
public FuzzyTerm() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTerm(String description, Double value) {
|
||||||
|
this.description = description;
|
||||||
|
this.crispValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getCrispValue() {
|
||||||
|
return crispValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCrispValue(Double crispValue) {
|
||||||
|
this.crispValue = crispValue;
|
||||||
|
}
|
||||||
|
}
|
71
src/main/java/ru/ulstu/fc/rule/model/FuzzyTermForm.java
Normal file
71
src/main/java/ru/ulstu/fc/rule/model/FuzzyTermForm.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
public class FuzzyTermForm {
|
||||||
|
private Integer projectId;
|
||||||
|
private Integer variableId;
|
||||||
|
private Integer id;
|
||||||
|
private String description;
|
||||||
|
private Double crispValue;
|
||||||
|
|
||||||
|
public FuzzyTermForm() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTermForm(String description, Double value) {
|
||||||
|
this.description = description;
|
||||||
|
this.crispValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTermForm(Integer id, Integer projectId, Integer variableId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
this.variableId = variableId;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTermForm(Integer id, Integer projectId, Integer variableId, FuzzyTerm fuzzyTerm) {
|
||||||
|
this.id = id;
|
||||||
|
this.projectId = projectId;
|
||||||
|
this.variableId = variableId;
|
||||||
|
this.crispValue = fuzzyTerm.getCrispValue();
|
||||||
|
this.description = fuzzyTerm.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getCrispValue() {
|
||||||
|
return crispValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCrispValue(Double crispValue) {
|
||||||
|
this.crispValue = crispValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getProjectId() {
|
||||||
|
return projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(Integer projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVariableId() {
|
||||||
|
return variableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVariableId(Integer variableId) {
|
||||||
|
this.variableId = variableId;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,33 @@
|
|||||||
package ru.ulstu.fc.rule.model;
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
import ru.ulstu.fc.core.BaseEntity;
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import ru.ulstu.fc.core.model.BaseEntity;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import java.util.ArrayList;
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class Variable extends BaseEntity {
|
public class Variable extends BaseEntity {
|
||||||
|
@Size(min = 3, max = 250, message = "Длина должна быть от 3 до 250")
|
||||||
private String name;
|
private String name;
|
||||||
@OneToMany
|
|
||||||
private List<Term> terms;
|
@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<>();
|
||||||
|
|
||||||
public Variable() {
|
public Variable() {
|
||||||
}
|
}
|
||||||
@ -19,9 +36,9 @@ public class Variable extends BaseEntity {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Variable(String name, List<Term> terms) {
|
public Variable(String name, List<FuzzyTerm> fuzzyTerms) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.terms = terms;
|
this.fuzzyTerms = fuzzyTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -32,11 +49,27 @@ public class Variable extends BaseEntity {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Term> getTerms() {
|
public List<FuzzyTerm> getFuzzyTerms() {
|
||||||
return terms;
|
return fuzzyTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTerms(List<Term> terms) {
|
public void setFuzzyTerms(List<FuzzyTerm> fuzzyTerms) {
|
||||||
this.terms = terms;
|
this.fuzzyTerms = fuzzyTerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Project getProject() {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProject(Project project) {
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInput() {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInput(boolean input) {
|
||||||
|
this.input = input;
|
||||||
}
|
}
|
||||||
}
|
}
|
61
src/main/java/ru/ulstu/fc/rule/model/VariableForm.java
Normal file
61
src/main/java/ru/ulstu/fc/rule/model/VariableForm.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package ru.ulstu.fc.rule.model;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class VariableForm {
|
||||||
|
private Integer id;
|
||||||
|
@NotNull
|
||||||
|
private Integer projectId;
|
||||||
|
@Size(min = 3, max = 250, message = "Длина должна быть от 3 до 250")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private boolean input = true;
|
||||||
|
|
||||||
|
public VariableForm() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableForm(Integer id, Integer projectId) {
|
||||||
|
this.id = id;
|
||||||
|
this.projectId = projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableForm(Integer id, Variable variable) {
|
||||||
|
this.id = id;
|
||||||
|
this.projectId = variable.getProject().getId();
|
||||||
|
this.name = variable.getName();
|
||||||
|
this.input = variable.isInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInput() {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInput(boolean input) {
|
||||||
|
this.input = input;
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
package ru.ulstu.fc.rule.model;
|
|
||||||
|
|
||||||
public class VariableValue {
|
|
||||||
private String fuzzyTerm;
|
|
||||||
private Double value;
|
|
||||||
|
|
||||||
public VariableValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public VariableValue(String fuzzyTerm, Double value) {
|
|
||||||
this.fuzzyTerm = fuzzyTerm;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFuzzyTerm() {
|
|
||||||
return fuzzyTerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFuzzyTerm(String fuzzyTerm) {
|
|
||||||
this.fuzzyTerm = fuzzyTerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(Double value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,12 @@
|
|||||||
|
package ru.ulstu.fc.rule.repository;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
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> {
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,12 @@
|
|||||||
package ru.ulstu.fc.rule.repository;
|
package ru.ulstu.fc.rule.repository;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.ulstu.fc.project.model.Project;
|
||||||
import ru.ulstu.fc.rule.model.Variable;
|
import ru.ulstu.fc.rule.model.Variable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface VariableRepository extends JpaRepository<Variable, Integer> {
|
public interface VariableRepository extends JpaRepository<Variable, Integer> {
|
||||||
|
|
||||||
|
List<Variable> findByProject(Project project);
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ import com.fuzzylite.variable.OutputVariable;
|
|||||||
import org.slf4j.Logger;
|
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.FuzzyTerm;
|
||||||
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 java.util.List;
|
import java.util.List;
|
||||||
@ -48,13 +48,16 @@ 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.getTerms().get(variable.getTerms().size() - 1).getMax());
|
input.setRange(0, variable.getFuzzyTerms().get(variable.getFuzzyTerms().size() - 1).getCrispValue());
|
||||||
input.setEnabled(true);
|
input.setEnabled(true);
|
||||||
input.setLockValueInRange(false);
|
input.setLockValueInRange(false);
|
||||||
for (int i = 0; i < variable.getTerms().size(); i++) {
|
double prev = 0;
|
||||||
Triangle term = new Triangle(variable.getTerms().get(i).getName(),
|
for (int i = 0; i < variable.getFuzzyTerms().size(); i++) {
|
||||||
variable.getTerms().get(i).getMin(),
|
Triangle term = new Triangle(variable.getFuzzyTerms().get(i).getDescription(),
|
||||||
variable.getTerms().get(i).getMax());
|
prev,
|
||||||
|
variable.getFuzzyTerms().get(i).getCrispValue(),
|
||||||
|
variable.getFuzzyTerms().get(i).getCrispValue() + variable.getFuzzyTerms().get(i).getCrispValue() - prev);
|
||||||
|
prev = term.getVertexB();
|
||||||
input.addTerm(term);
|
input.addTerm(term);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
@ -64,16 +67,20 @@ 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.getTerms().get(variable.getTerms().size() - 1).getMax());
|
output.setRange(0, variable.getFuzzyTerms().get(variable.getFuzzyTerms().size() - 1).getCrispValue());
|
||||||
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);
|
||||||
for (int i = 0; i < variable.getTerms().size(); i++) {
|
double prev = 0;
|
||||||
Triangle term = new Triangle(variable.getTerms().get(i).getName(),
|
for (int i = 0; i < variable.getFuzzyTerms().size(); i++) {
|
||||||
variable.getTerms().get(i).getMin(),
|
Triangle term = new Triangle(
|
||||||
variable.getTerms().get(i).getMax());
|
variable.getFuzzyTerms().get(i).getDescription(),
|
||||||
|
prev,
|
||||||
|
variable.getFuzzyTerms().get(i).getCrispValue(),
|
||||||
|
variable.getFuzzyTerms().get(i).getCrispValue() + variable.getFuzzyTerms().get(i).getCrispValue() - prev);
|
||||||
|
prev = term.getVertexB();
|
||||||
output.addTerm(term);
|
output.addTerm(term);
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
@ -94,6 +101,7 @@ public class FuzzyInferenceService {
|
|||||||
mamdani.setImplication(new AlgebraicProduct());
|
mamdani.setImplication(new AlgebraicProduct());
|
||||||
mamdani.setActivation(new General());
|
mamdani.setActivation(new General());
|
||||||
rules.forEach(r -> mamdani.addRule(Rule.parse(r, engine)));
|
rules.forEach(r -> mamdani.addRule(Rule.parse(r, engine)));
|
||||||
|
mamdani.addRule(new Rule());
|
||||||
return mamdani;
|
return mamdani;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,21 +127,20 @@ 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 Term("молодой", 0.0, 40.0),
|
new FuzzyTerm("молодой", 35.0),
|
||||||
new Term("средний", 20.0, 60.0),
|
new FuzzyTerm("средний", 60.0),
|
||||||
new Term("старый", 50.0, 100.0))
|
new FuzzyTerm("старый", 100.0))
|
||||||
),
|
),
|
||||||
new Variable("доход", List.of(
|
new Variable("доход", List.of(
|
||||||
new Term("небольшой", 0.0, 35000.0),
|
new FuzzyTerm("небольшой", 35000.0),
|
||||||
new Term("средний", 20000.0, 100000.0),
|
new FuzzyTerm("средний", 100000.0),
|
||||||
new Term("высокий", 80000.0, 500000.0))
|
new FuzzyTerm("высокий", 500000.0))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new Variable("кредит", List.of(
|
new Variable("кредит", List.of(
|
||||||
new Term("не_выдавать_кредит", 0.0, 1.0),
|
new FuzzyTerm("небольшой", 20000.0),
|
||||||
new Term("небольшой", 1.0, 50000.0),
|
new FuzzyTerm("средний", 100000.0),
|
||||||
new Term("средний", 25000.0, 100000.0),
|
new FuzzyTerm("большой", 1000000.0)))
|
||||||
new Term("большой", 75000.0, 1000000.0)))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/main/java/ru/ulstu/fc/rule/service/FuzzyRuleService.java
Normal file
41
src/main/java/ru/ulstu/fc/rule/service/FuzzyRuleService.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package ru.ulstu.fc.rule.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
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 {
|
||||||
|
private final FuzzyRuleRepository ruleRepository;
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
|
public FuzzyRuleService(FuzzyRuleRepository ruleRepository, ProjectService projectService) {
|
||||||
|
this.ruleRepository = ruleRepository;
|
||||||
|
this.projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyRule getById(Integer id) {
|
||||||
|
return ruleRepository
|
||||||
|
.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Rule not found by id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object save(FuzzyRuleForm ruleForm) {
|
||||||
|
FuzzyRule rule;
|
||||||
|
if (ruleForm.getId() == null || ruleForm.getId() == 0) {
|
||||||
|
rule = new FuzzyRule();
|
||||||
|
} else {
|
||||||
|
rule = getById(ruleForm.getId());
|
||||||
|
}
|
||||||
|
rule.setProject(projectService.getById(ruleForm.getProjectId()));
|
||||||
|
rule.setContent(ruleForm.getContent());
|
||||||
|
return ruleRepository.save(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(FuzzyRuleForm ruleForm) {
|
||||||
|
getById(ruleForm.getId());
|
||||||
|
ruleRepository.deleteById(ruleForm.getId());
|
||||||
|
}
|
||||||
|
}
|
56
src/main/java/ru/ulstu/fc/rule/service/FuzzyTermService.java
Normal file
56
src/main/java/ru/ulstu/fc/rule/service/FuzzyTermService.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package ru.ulstu.fc.rule.service;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
this.fuzzyTermRepository = fuzzyTermRepository;
|
||||||
|
this.variableService = variableService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTerm getById(Integer id) {
|
||||||
|
return fuzzyTermRepository
|
||||||
|
.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Term not found by id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FuzzyTerm save(FuzzyTermForm fuzzyTermForm) {
|
||||||
|
FuzzyTerm term;
|
||||||
|
if (fuzzyTermForm.getId() == null || fuzzyTermForm.getId() == 0) {
|
||||||
|
term = new FuzzyTerm();
|
||||||
|
} else {
|
||||||
|
term = getById(fuzzyTermForm.getId());
|
||||||
|
}
|
||||||
|
term.setDescription(fuzzyTermForm.getDescription());
|
||||||
|
term.setCrispValue(fuzzyTermForm.getCrispValue());
|
||||||
|
FuzzyTerm ft = fuzzyTermRepository.save(term);
|
||||||
|
if (fuzzyTermForm.getId() == null || fuzzyTermForm.getId() == 0) {
|
||||||
|
variableService.addFuzzyTerm(fuzzyTermForm.getVariableId(), ft);
|
||||||
|
}
|
||||||
|
return ft;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(FuzzyTermForm fuzzyTermForm) {
|
||||||
|
getById(fuzzyTermForm.getId());
|
||||||
|
fuzzyTermRepository.deleteById(fuzzyTermForm.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FuzzyTerm> getByVariableId(Integer variableId) {
|
||||||
|
if (variableId == null || variableId == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return variableService.getById(variableId).getFuzzyTerms();
|
||||||
|
}
|
||||||
|
}
|
@ -1,38 +1,49 @@
|
|||||||
package ru.ulstu.fc.rule.service;
|
package ru.ulstu.fc.rule.service;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.ulstu.fc.rule.model.AddVariableForm;
|
import ru.ulstu.fc.project.service.ProjectService;
|
||||||
|
import ru.ulstu.fc.rule.model.FuzzyTerm;
|
||||||
import ru.ulstu.fc.rule.model.Variable;
|
import ru.ulstu.fc.rule.model.Variable;
|
||||||
|
import ru.ulstu.fc.rule.model.VariableForm;
|
||||||
import ru.ulstu.fc.rule.repository.VariableRepository;
|
import ru.ulstu.fc.rule.repository.VariableRepository;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class VariableService {
|
public class VariableService {
|
||||||
private final VariableRepository variableRepository;
|
private final VariableRepository variableRepository;
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
public VariableService(VariableRepository variableRepository) {
|
public VariableService(VariableRepository variableRepository, ProjectService projectService) {
|
||||||
this.variableRepository = variableRepository;
|
this.variableRepository = variableRepository;
|
||||||
|
this.projectService = projectService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Variable getById(Integer id) {
|
||||||
public List<Variable> getVars() {
|
return variableRepository
|
||||||
return variableRepository.findAll();
|
.findById(id)
|
||||||
|
.orElseThrow(() -> new RuntimeException("Variable not found by id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(AddVariableForm addVariableForm) {
|
public Variable save(VariableForm variableForm) {
|
||||||
if (addVariableForm.getId() == null) {
|
Variable variable;
|
||||||
variableRepository.save(new Variable(addVariableForm.getName()));
|
if (variableForm.getId() == null || variableForm.getId() == 0) {
|
||||||
|
variable = new Variable();
|
||||||
} else {
|
} else {
|
||||||
Variable dbVar = variableRepository.findById(addVariableForm.getId()).orElseThrow(() -> new RuntimeException("Variable not found by id"));
|
variable = getById(variableForm.getId());
|
||||||
dbVar.setName(addVariableForm.getName());
|
|
||||||
variableRepository.save(dbVar);
|
|
||||||
}
|
}
|
||||||
|
variable.setProject(projectService.getById(variableForm.getProjectId()));
|
||||||
|
variable.setName(variableForm.getName());
|
||||||
|
variable.setInput(variableForm.isInput());
|
||||||
|
return variableRepository.save(variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddVariableForm getAddVariableFormOrDefault(Integer id) {
|
public void delete(VariableForm ruleForm) {
|
||||||
return id == null
|
getById(ruleForm.getId());
|
||||||
? new AddVariableForm()
|
variableRepository.deleteById(ruleForm.getId());
|
||||||
: new AddVariableForm(variableRepository.findById(id).orElseThrow(() -> new RuntimeException("Var not foubd by id")));
|
}
|
||||||
|
|
||||||
|
public void addFuzzyTerm(Integer variableId, FuzzyTerm ft) {
|
||||||
|
Variable var = getById(variableId);
|
||||||
|
var.getFuzzyTerms().add(ft);
|
||||||
|
variableRepository.save(var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
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;
|
||||||
|
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 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";
|
||||||
|
}
|
||||||
|
}
|
77
src/main/java/ru/ulstu/fc/user/model/User.java
Normal file
77
src/main/java/ru/ulstu/fc/user/model/User.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package ru.ulstu.fc.user.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
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 {
|
||||||
|
@NotNull
|
||||||
|
@Pattern(regexp = Constants.LOGIN_REGEX)
|
||||||
|
@Size(min = 1, max = 50)
|
||||||
|
@Column(length = 50, unique = true, nullable = false)
|
||||||
|
private String login;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Size(min = 60, max = 60)
|
||||||
|
@Column(name = "password_hash", length = 60, nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "is_user_role",
|
||||||
|
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
|
||||||
|
inverseJoinColumns = {@JoinColumn(name = "user_role_name", referencedColumnName = "name")})
|
||||||
|
private Set<UserRole> roles;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
roles = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String login, String password, Set<UserRole> roles) {
|
||||||
|
this.login = login;
|
||||||
|
this.password = password;
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(UserDto userDto) {
|
||||||
|
this.login = userDto.getLogin();
|
||||||
|
this.password = userDto.getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogin() {
|
||||||
|
return login;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogin(String login) {
|
||||||
|
this.login = login.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<UserRole> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(Set<UserRole> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
}
|
40
src/main/java/ru/ulstu/fc/user/model/UserDto.java
Normal file
40
src/main/java/ru/ulstu/fc/user/model/UserDto.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package ru.ulstu.fc.user.model;
|
||||||
|
|
||||||
|
public class UserNotFoundException extends RuntimeException {
|
||||||
|
public UserNotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
50
src/main/java/ru/ulstu/fc/user/model/UserRole.java
Normal file
50
src/main/java/ru/ulstu/fc/user/model/UserRole.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package ru.ulstu.fc.user.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "is_user_roles")
|
||||||
|
public class UserRole {
|
||||||
|
@Id
|
||||||
|
@NotNull
|
||||||
|
@Size(max = 50)
|
||||||
|
@Column(length = 50, nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public UserRole() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRole(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UserRole role = (UserRole) o;
|
||||||
|
return !(name != null ? !name.equals(role.name) : role.name != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return name != null ? name.hashCode() : 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package ru.ulstu.fc.user.model;
|
||||||
|
|
||||||
|
public class UserRoleConstants {
|
||||||
|
public static final String ADMIN = "ROLE_ADMIN";
|
||||||
|
public static final String USER = "ROLE_USER";
|
||||||
|
}
|
105
src/main/java/ru/ulstu/fc/user/model/UserSession.java
Normal file
105
src/main/java/ru/ulstu/fc/user/model/UserSession.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package ru.ulstu.fc.user.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Temporal;
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import ru.ulstu.fc.core.model.BaseEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "is_user_sessions")
|
||||||
|
public class UserSession extends BaseEntity {
|
||||||
|
@NotNull
|
||||||
|
@Column(name = "session_id", nullable = false, unique = true)
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Column(name = "ip_address", nullable = false)
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Column(name = "login_time", nullable = false)
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date loginTime;
|
||||||
|
|
||||||
|
@Column(name = "logout_time")
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date logoutTime;
|
||||||
|
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
public UserSession() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserSession(String sessionId, String ipAddress, String host, User user) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
this.host = host;
|
||||||
|
this.loginTime = new Date();
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIpAddress() {
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLoginTime() {
|
||||||
|
return loginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLogoutTime() {
|
||||||
|
return logoutTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionId(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIpAddress(String ipAddress) {
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginTime(Date loginTime) {
|
||||||
|
this.loginTime = loginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogoutTime(Date logoutTime) {
|
||||||
|
this.logoutTime = logoutTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
this.logoutTime = new Date();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package ru.ulstu.fc.user.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.EntityGraph;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.ulstu.fc.user.model.User;
|
||||||
|
|
||||||
|
public interface UserRepository extends JpaRepository<User, Integer> {
|
||||||
|
User findOneByLoginIgnoreCase(String login);
|
||||||
|
|
||||||
|
@EntityGraph(attributePaths = "roles")
|
||||||
|
User findOneWithRolesById(int id);
|
||||||
|
|
||||||
|
@EntityGraph(attributePaths = "roles")
|
||||||
|
User findOneWithRolesByLogin(String login);
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package ru.ulstu.fc.user.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.ulstu.fc.user.model.UserRole;
|
||||||
|
|
||||||
|
public interface UserRoleRepository extends JpaRepository<UserRole, String> {
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package ru.ulstu.fc.user.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import ru.ulstu.fc.user.model.UserSession;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface UserSessionRepository extends JpaRepository<UserSession, Integer> {
|
||||||
|
UserSession findOneBySessionId(String sessionId);
|
||||||
|
|
||||||
|
List<UserSession> findAllByLogoutTimeIsNullAndLoginTimeBefore(Date date);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package ru.ulstu.fc.user.service;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
public final class IpAddressResolver {
|
||||||
|
//private static final String CLIENT_IP_HEADER = "Client-IP";
|
||||||
|
//private static final String FORWARDED_FOR_HEADER = "X-Forwarded-For";
|
||||||
|
|
||||||
|
public static String getRemoteAddr(HttpServletRequest request) {
|
||||||
|
String headerClientIp = request.getHeader("");
|
||||||
|
String headerXForwardedFor = request.getHeader(HttpServletRequest.FORM_AUTH);
|
||||||
|
if (request.getRemoteAddr().isEmpty() && !headerClientIp.isEmpty()) {
|
||||||
|
return headerClientIp;
|
||||||
|
}
|
||||||
|
if (!headerXForwardedFor.isEmpty()) {
|
||||||
|
return headerXForwardedFor;
|
||||||
|
}
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
src/main/java/ru/ulstu/fc/user/service/UserService.java
Normal file
93
src/main/java/ru/ulstu/fc/user/service/UserService.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package ru.ulstu.fc.user.service;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.ulstu.fc.user.model.User;
|
||||||
|
import ru.ulstu.fc.user.model.UserNotFoundException;
|
||||||
|
import ru.ulstu.fc.user.model.UserRole;
|
||||||
|
import ru.ulstu.fc.user.model.UserRoleConstants;
|
||||||
|
import ru.ulstu.fc.user.repository.UserRepository;
|
||||||
|
import ru.ulstu.fc.user.repository.UserRoleRepository;
|
||||||
|
import ru.ulstu.fc.user.utils.UserUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class UserService implements UserDetailsService {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(UserService.class);
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final UserRoleRepository userRoleRepository;
|
||||||
|
@Value("${admin-password}")
|
||||||
|
private String adminPassword;
|
||||||
|
|
||||||
|
public UserService(PasswordEncoder passwordEncoder,
|
||||||
|
UserRepository userRepository,
|
||||||
|
UserRoleRepository userRoleRepository) {
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.userRoleRepository = userRoleRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUserByLogin(String login) {
|
||||||
|
return userRepository.findOneByLoginIgnoreCase(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) {
|
||||||
|
final User user = userRepository.findOneByLoginIgnoreCase(username);
|
||||||
|
if (user == null) {
|
||||||
|
throw new UserNotFoundException(username);
|
||||||
|
}
|
||||||
|
return new org.springframework.security.core.userdetails.User(user.getLogin(),
|
||||||
|
user.getPassword(),
|
||||||
|
Optional.ofNullable(user.getRoles()).orElse(Collections.emptySet()).stream()
|
||||||
|
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public User createUser(User user) {
|
||||||
|
if (getUserByLogin(user.getLogin()) != null) {
|
||||||
|
throw new RuntimeException(user.getLogin());
|
||||||
|
}
|
||||||
|
User dbUser = (user.getId() == null)
|
||||||
|
? user
|
||||||
|
: getUserById(user.getId());
|
||||||
|
//user.setRoles(Collections.singleton(new UserRole(UserRoleConstants.USER)));
|
||||||
|
dbUser.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||||
|
dbUser.setLogin(user.getLogin());
|
||||||
|
dbUser = userRepository.save(dbUser);
|
||||||
|
log.debug("Created Information for User: {}", dbUser.getLogin());
|
||||||
|
return dbUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUserById(Integer id) {
|
||||||
|
return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found by id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDefaultUser(String login, String userRole) {
|
||||||
|
if (getUserByLogin(login) == null) {
|
||||||
|
UserRole role = userRoleRepository.save(new UserRole(userRole.toString()));
|
||||||
|
createUser(new User(login, login.equals("admin") ? adminPassword : login, Set.of(role)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initDefaultAdmin() {
|
||||||
|
createDefaultUser("admin", UserRoleConstants.ADMIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getCurrentUser() {
|
||||||
|
return getUserByLogin(UserUtils.getCurrentUserLogin());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package ru.ulstu.fc.user.service;
|
||||||
|
|
||||||
|
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);
|
||||||
|
private final UserSessionService userSessionService;
|
||||||
|
|
||||||
|
public UserSessionLoginHandler(UserSessionService userSessionService) {
|
||||||
|
super();
|
||||||
|
this.userSessionService = userSessionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
Authentication authentication) throws IOException, ServletException {
|
||||||
|
super.onAuthenticationSuccess(request, response, authentication);
|
||||||
|
final String login = authentication.getName();
|
||||||
|
final String ipAddress = IpAddressResolver.getRemoteAddr(request);
|
||||||
|
final String host = request.getRemoteHost();
|
||||||
|
log.debug("Authentication Success for {}@{} ({})", login, ipAddress, host);
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
final String sessionId = session.getId();
|
||||||
|
userSessionService.createUserSession(sessionId, login, ipAddress, host);
|
||||||
|
session.setAttribute(Constants.SESSION_ID_ATTR, sessionId);
|
||||||
|
session.setMaxInactiveInterval(Constants.SESSION_TIMEOUT_SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package ru.ulstu.fc.user.service;
|
||||||
|
|
||||||
|
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);
|
||||||
|
private final UserSessionService userSessionService;
|
||||||
|
|
||||||
|
public UserSessionLogoutHandler(UserSessionService userSessionService) {
|
||||||
|
this.userSessionService = userSessionService;
|
||||||
|
setDefaultTargetUrl(Constants.LOGOUT_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLogoutSuccess(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
Authentication authentication) throws IOException, ServletException {
|
||||||
|
if (authentication == null) {
|
||||||
|
super.onLogoutSuccess(request, response, authentication);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String login = authentication.getName();
|
||||||
|
final String ipAddress = IpAddressResolver.getRemoteAddr(request);
|
||||||
|
final String host = request.getRemoteHost();
|
||||||
|
log.debug("Logout Success for {}@{} ({})", login, ipAddress, host);
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
final String sessionId = session.getAttribute(Constants.SESSION_ID_ATTR).toString();
|
||||||
|
userSessionService.closeUserSession(sessionId);
|
||||||
|
session.removeAttribute(Constants.SESSION_ID_ATTR);
|
||||||
|
session.invalidate();
|
||||||
|
}
|
||||||
|
super.onLogoutSuccess(request, response, authentication);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package ru.ulstu.fc.user.service;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.ulstu.fc.user.model.User;
|
||||||
|
import ru.ulstu.fc.user.model.UserNotFoundException;
|
||||||
|
import ru.ulstu.fc.user.model.UserSession;
|
||||||
|
import ru.ulstu.fc.user.repository.UserSessionRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class UserSessionService {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(UserSessionService.class);
|
||||||
|
private final UserSessionRepository userSessionRepository;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
public UserSessionService(UserSessionRepository userSessionRepository, UserService userService) {
|
||||||
|
this.userSessionRepository = userSessionRepository;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createUserSession(String sessionId, String login, String ipAddress, String host) {
|
||||||
|
final User user = userService.getUserByLogin(login);
|
||||||
|
if (user == null) {
|
||||||
|
throw new UserNotFoundException(login);
|
||||||
|
}
|
||||||
|
userSessionRepository.save(new UserSession(sessionId, ipAddress, host, user));
|
||||||
|
log.debug("User session {} created for user {}@{} ({})", sessionId, login, ipAddress, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeUserSession(String sessionId) {
|
||||||
|
final UserSession userSession = userSessionRepository.findOneBySessionId(sessionId);
|
||||||
|
if (userSession == null) {
|
||||||
|
throw new IllegalArgumentException(String.format("User session %s not found", sessionId));
|
||||||
|
}
|
||||||
|
userSession.close();
|
||||||
|
userSessionRepository.save(userSession);
|
||||||
|
log.debug("User session {} closed", sessionId);
|
||||||
|
}
|
||||||
|
}
|
24
src/main/java/ru/ulstu/fc/user/utils/UserUtils.java
Normal file
24
src/main/java/ru/ulstu/fc/user/utils/UserUtils.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package ru.ulstu.fc.user.utils;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
public class UserUtils {
|
||||||
|
public static String getCurrentUserLogin() {
|
||||||
|
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||||
|
if (securityContext == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final Authentication authentication = securityContext.getAuthentication();
|
||||||
|
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||||
|
final UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
|
||||||
|
return springSecurityUser.getUsername();
|
||||||
|
}
|
||||||
|
if (authentication.getPrincipal() instanceof String) {
|
||||||
|
return (String) authentication.getPrincipal();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
spring.main.banner-mode=off
|
spring.main.banner-mode=off
|
||||||
server.port=8080
|
server.port=8080
|
||||||
server.jetty.connection-idle-timeout=1000s
|
server.jetty.connection-idle-timeout=1000s
|
||||||
|
admin-password=admin
|
||||||
# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
|
# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
|
||||||
logging.level.ru.ulstu=DEBUG
|
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
|
||||||
@ -18,6 +21,4 @@ spring.datasource.password=password
|
|||||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
# swagger-ui custom path
|
|
||||||
springdoc.swagger-ui.path=/swagger-ui.html
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!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>
|
||||||
@ -12,6 +13,7 @@
|
|||||||
<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>
|
<body>
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light" layout:fragment="navbar">
|
||||||
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
|
<a class="navbar-brand" href="/">Нечеткий контроллер</a>
|
||||||
@ -21,18 +23,27 @@
|
|||||||
</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">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link" href="/listVars">Переменные</a>
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown"
|
||||||
</li>
|
aria-haspopup="true" aria-expanded="false">Проекты</a>
|
||||||
<li class="nav-item">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<a class="nav-link" href="/listTerms">Термы</a>
|
<a class="dropdown-item" href="/project/list">Список проектов</a>
|
||||||
</li>
|
</div>
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="/listRules">Правила</a>
|
|
||||||
</li>
|
</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>
|
||||||
|
<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>
|
||||||
</nav>
|
</nav>
|
||||||
@ -56,4 +67,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
13
src/main/resources/templates/error/404.html
Normal file
13
src/main/resources/templates/error/404.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container" layout:fragment="content">
|
||||||
|
<h5>Страница не найдена</h5>
|
||||||
|
<a href="/"><h6>Вернуться на главную</h6></a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
13
src/main/resources/templates/error/500.html
Normal file
13
src/main/resources/templates/error/500.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container" layout:fragment="content">
|
||||||
|
<h5>Ошибка сервера</h5>
|
||||||
|
<a href="/"><h6>Вернуться на главную</h6></a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
54
src/main/resources/templates/fuzzyTerm/edit.html
Normal file
54
src/main/resources/templates/fuzzyTerm/edit.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!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="@{/fuzzyTerm/save}" th:object="${fuzzyTermForm}" method="post">
|
||||||
|
<input type="hidden" th:field="*{projectId}">
|
||||||
|
<input type="hidden" th:field="*{variableId}">
|
||||||
|
<input type="hidden" th:field="*{id}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Терм</label>
|
||||||
|
<input th:field="*{description}"
|
||||||
|
id="description"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Терм">
|
||||||
|
<p th:if="${#fields.hasErrors('description')}"
|
||||||
|
th:class="${#fields.hasErrors('description')} ? error">
|
||||||
|
Не может быть пустым
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Значение</label>
|
||||||
|
<input th:field="*{crispValue}"
|
||||||
|
id="crispValue"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Терм">
|
||||||
|
<p th:if="${#fields.hasErrors('crispValue')}"
|
||||||
|
th:class="${#fields.hasErrors('crispValue')} ? error">
|
||||||
|
Не может быть пустым
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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('Удалить запись?')">
|
||||||
|
Удалить
|
||||||
|
</button>
|
||||||
|
<a th:href="@{'/variable/edit/' + ${projectId}+'/' + ${variableId}}" class="btn btn-outline-dark">Отмена</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</html>
|
@ -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.crispValue}"
|
||||||
th:utext="${ageAntecedent.description}">
|
th:utext="${ageValue.description}">
|
||||||
</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.crispValue}"
|
||||||
th:utext="${incomeAntecedent.description}">
|
th:utext="${incomeValue.description}">
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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>
|
|
35
src/main/resources/templates/login.html
Normal file
35
src/main/resources/templates/login.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<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>
|
||||||
|
<div class="container" layout:fragment="content">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div id="signin" class="tab-pane active">
|
||||||
|
<form th:action="@{/login}" method="post" class="margined-top-10">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" name="username" id="username" class="form-control"
|
||||||
|
placeholder="Логин" required="true" autofocus="true"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" name="password" id="password" class="form-control"
|
||||||
|
placeholder="Пароль" required="true"/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-dark">Войти</button>
|
||||||
|
<a href="/user/register" class="btn btn-outline-dark">Регистрация</a>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
39
src/main/resources/templates/loginError.html
Normal file
39
src/main/resources/templates/loginError.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<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>
|
||||||
|
<div class="container" layout:fragment="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<ul id="messages" class="feedback-panel">
|
||||||
|
<div class="alert alert-danger" role="alert">Ошибка входа</div>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div id="signin" class="tab-pane active">
|
||||||
|
<form th:action="@{/login}" method="post" class="margined-top-10">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" name="username" id="username" class="form-control"
|
||||||
|
placeholder="Логин" required="true" autofocus="true"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" name="password" id="password" class="form-control"
|
||||||
|
placeholder="Пароль" required="true"/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-outline-dark btn-block">Войти</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
86
src/main/resources/templates/project/edit.html
Normal file
86
src/main/resources/templates/project/edit.html
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<!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="@{/project/save}" th:object="${project}" method="post">
|
||||||
|
<input type="hidden" th:field="*{id}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Название</label>
|
||||||
|
<input th:field="*{name}" id="name" type="text" required class="form-control" placeholder="Название">
|
||||||
|
<p th:if="${#fields.hasErrors('name')}" th:class="${#fields.hasErrors('name')}? error">
|
||||||
|
Не может быть пустым
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label th:text="'Дата создания: ' + ${#dates.format(project.createDate, 'dd.MM.yyyy HH:mm')}"></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 href="/project/list" class="btn btn-outline-dark">Отмена</a>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<h4> Список переменных</h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row" th:each="v, iter : ${variables}">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
<a th:href="@{'/variable/edit/' + ${projectId}+'/'+${v.id}}">
|
||||||
|
<span class="badge badge-light" th:text="${iter.index+1} + '. ' + ${v.name}"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a th:href="@{'/variable/edit/' + ${projectId}+'/0'}" class="btn btn-outline-dark">Добавить преременную</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<h4> Список правил</h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</html>
|
22
src/main/resources/templates/project/list.html
Normal file
22
src/main/resources/templates/project/list.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!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">
|
||||||
|
<a href="/project/edit/0" class="btn btn-outline-dark">
|
||||||
|
<i class="fa fa-plus-square" aria-hidden="true">Добавить проект</i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li th:each="p : ${projects}">
|
||||||
|
<a th:href="@{'/project/edit/' + ${p.id}}">
|
||||||
|
<span th:text="${p.name} + ' от ' + ${#dates.format(p.createDate, 'dd.MM.yyyy HH:mm')}"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</html>
|
30
src/main/resources/templates/project/listRules.html
Normal file
30
src/main/resources/templates/project/listRules.html
Normal 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"
|
||||||
|
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>
|
29
src/main/resources/templates/register.html
Normal file
29
src/main/resources/templates/register.html
Normal 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>
|
38
src/main/resources/templates/rule/edit.html
Normal file
38
src/main/resources/templates/rule/edit.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!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="${fuzzyRuleForm}" method="post">
|
||||||
|
<input type="hidden" th:field="*{projectId}">
|
||||||
|
<input type="hidden" th:field="*{id}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content">Правило</label>
|
||||||
|
<input th:field="*{content}"
|
||||||
|
id="content"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Правило">
|
||||||
|
<p th:if="${#fields.hasErrors('content')}"
|
||||||
|
th:class="${#fields.hasErrors('content')}? error">
|
||||||
|
Не может быть пустым
|
||||||
|
</p>
|
||||||
|
</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>
|
55
src/main/resources/templates/variable/edit.html
Normal file
55
src/main/resources/templates/variable/edit.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<!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="@{/variable/save}" th:object="${variableForm}" method="post">
|
||||||
|
<input type="hidden" th:field="*{projectId}">
|
||||||
|
<input type="hidden" th:field="*{id}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Переменная</label>
|
||||||
|
<input th:field="*{name}" id="name" type="text" required class="form-control" placeholder="Переменная">
|
||||||
|
<p th:if="${#fields.hasErrors('name')}" th:class="${#fields.hasErrors('name')} ? error">
|
||||||
|
Не может быть пустым
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input th:field="*{input}" id="input" type="checkbox">
|
||||||
|
<label for="input">Является входной переменной</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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('Удалить запись?')">
|
||||||
|
Удалить
|
||||||
|
</button>
|
||||||
|
<a th:href="@{'/project/edit/' + ${projectId}}" class="btn btn-outline-dark">Отмена</a>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<h4> Список термов</h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row" th:each="t, iter : ${fuzzyTerms}">
|
||||||
|
<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>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a th:href="@{'/fuzzyTerm/edit/' + ${projectId} + '/' + ${variableId}+'/0'}"
|
||||||
|
class="btn btn-outline-dark">Добавить терм</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user