Compare commits

...

30 Commits

Author SHA1 Message Date
85f0c97e6f Правка БД. 2023-05-26 19:52:53 +04:00
d75c758ee1 Отчёт. 2023-05-26 18:44:06 +04:00
6d178b58aa Мелкие правки (отключил подсветку th как ошибку). LabWork05. 2023-04-24 16:22:59 +04:00
9b72e39432 LabWork05. 2023-04-24 16:20:28 +04:00
167ca7eb82 Второе глобальное промежуточное сохранение. 2023-04-24 14:10:55 +04:00
843ec51b8c Первое глобальное промежуточное сохранение. 2023-04-24 01:03:24 +04:00
9560588d41 Добавление первых HTML файлов. 2023-04-22 10:50:45 +04:00
b4e48f5c5e Начало 5-й лабораторной. 2023-04-22 10:17:18 +04:00
9f643c860d СЮЮЮЮЮДАААААААААААААА ЭТУ БЕБРОЧКУУУУУУУУУ, О ДААААА 2023-04-19 20:25:07 +04:00
4d76a86c8e А теперь я просто хочу сказать 2023-04-19 20:24:33 +04:00
ce8c5ca468 Четвёртая партия фронта. 2023-04-19 20:23:17 +04:00
15b5ebd034 Третья партия фронта. 2023-04-19 20:22:55 +04:00
81f8008aab Вторая партия фронта. 2023-04-19 20:10:05 +04:00
307acf867a Первая партия фронта. 2023-04-19 20:09:25 +04:00
01470af3bb Точечные правки. Всё работает. 2023-04-19 19:57:09 +04:00
a0ff253478 Добавление DTO. Исправление сервисов и некоторых контроллеров. 2023-04-19 19:44:08 +04:00
973e2c6a16 Правка моделей. 2023-04-19 19:35:44 +04:00
8a23075ac6 Промежуточное сохранение. Надеюсь, что будет работать 2023-04-09 13:41:37 +04:00
43cc05427d Промежуточное сохранение. 2023-04-09 12:05:55 +04:00
e2d99cec86 Переименование сущностей и корректировка тестов. 2023-04-09 11:13:33 +04:00
8ecf9e9cab Добавление классов-контроллеров и DOT. 2023-04-09 09:15:24 +04:00
d0f9fb2bd0 Изменение классов-сервисов. 2023-04-08 23:53:17 +04:00
2844d545ce Начало работ над 4-й лабораторной. 2023-04-08 23:01:18 +04:00
c4e3593fa4 Вроде как рабочий проект для 3-й лабы. 2023-04-08 10:29:58 +04:00
8fa5b5f8c4 Промежуточное сохранение. 2023-04-07 11:15:41 +04:00
663fd6ad72 Добавление всех ревисов. 2023-04-07 11:00:17 +04:00
b79d35d1af Промежуточное сохранение. 2023-04-06 21:31:26 +04:00
9297fb06ae Промежуточное сохранение. 2023-03-27 17:51:24 +04:00
438e1ed4d4 3 готовые сущности. Доработка связи многие ко многим и двух сущностей. 2023-03-27 17:34:32 +04:00
eea6638930 Start 03 lab work 2023-03-27 16:00:40 +04:00
125 changed files with 6961 additions and 1338 deletions

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

10
.idea/compiler.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel>
<module name="spring_online_calculator" target="17" />
<module name="spring_online_calculator.main" target="17" />
<module name="spring_online_calculator.test" target="17" />
</bytecodeTargetLevel>
</component>
</project>

8
.idea/discord.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="ASK" />
<option name="nameOverrideEnabled" value="true" />
<option name="description" value="" />
</component>
</project>

19
.idea/gradle.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="true" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$/spring_online_calculator" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$/spring_online_calculator" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,15 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="th:text" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
</profile>
</component>

20
.idea/jarRepositories.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>

6
.idea/jpa-buddy.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="defaultUnitInitialized" value="true" />
</component>
</project>

8
.idea/misc.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="temurin-17" project-jdk-type="JavaSDK" />
<component name="ProjectType">
<option name="id" value="jpab" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/С репозитория.iml" filepath="$PROJECT_DIR$/.idea/С репозитория.iml" />
</modules>
</component>
</project>

124
.idea/uiDesigner.xml Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,13 +1,16 @@
{ {
"name": "online_calculator", "name": "premuim_store",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.3.5",
"cors": "^2.8.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.10.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },

View File

@ -3,9 +3,11 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title> <link href="../src/styles/App.css">
<title>Premium store of our games! :)</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,2 @@
VITE_NODE_ENV=development
VITE_API_URL=http://localhost:8080

View File

@ -0,0 +1,46 @@
import React, {useState} from 'react';
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
import AddLevel from './components/AddLevel';
import MainHead from './components/MainHead';
import AddNation from './components/AddNation';
import AddTank from './components/AddTank';
import AddClient from './components/AddClient';
import PageForChecking from './components/PageForChecking';
function Router(props) {
return useRoutes(props.rootRoute);
}
function App() {
const routes = [
{ index: true, element: <AddLevel /> },
{ path: 'levels', element: <AddLevel />, label: 'Обзор уровней' },
{ path: 'nations', element: <AddNation />, label: 'Обзор наций' },
{ path: 'tanks', element: <AddTank />, label: 'Обзор танков'},
{ path: 'clients', element: <AddClient />, label: 'Обзор клиентов'},
{ path: 'checkPage', element: <PageForChecking />, label: 'Фильтр по танкам'}
];
const links = routes.filter(route => route.hasOwnProperty('label'));
const rootRoute = [
{ path: '/', element: render(links), children: routes }
];
function render(links) {
return (
<div className="App">
<MainHead links={links}/>
<Outlet/>
</div>
);
}
return (
<BrowserRouter>
<Router rootRoute={ rootRoute } />
</BrowserRouter>
);
}
export default App;

View File

@ -0,0 +1,14 @@
.add-client-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}

View File

@ -0,0 +1,113 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import '../styles/App.css';
import ClientList from './items/GameClient/ClientList';
import './AddClient.css';
export default function AddClient() {
const [clientItems, setClientItems] = useState([]);
//для создания нового уровня
const [clientNickName, setClientNickName] = useState();
const [clientEmail, setClientEmail] = useState();
const [clientBalance, setClientBalance] = useState();
//загрузка всех имеющихся уровней при старте
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/client/')
.then((responce) => {
console.log(responce.data);
setClientItems(responce.data)
})
}, [])
//обновить список уровней
function CheckArray(){
console.log('Обращение к БД');
axios.get('http://localhost:8080/client/')
.then((responce) => {
console.log(responce.data);
setClientItems(responce.data)
})
}
//добавление нового уровня
function addNewClient(){
console.log(clientNickName);
console.log(clientEmail);
console.log(clientBalance);
if(clientNickName === ''){
return;
}
else {//http://localhost:8080/client/?nickName=11&email=11&balance=11
axios.post('http://localhost:8080/client/?nickName=' + clientNickName + '&email=' + clientEmail + '&balance=' + clientBalance)
.then((response) => {
CheckArray();
setClientNickName('');
setClientEmail('');
setClientBalance('');
});
}
}
//добавили условную отрисовку
return(
<div>
<div className="Group_create_level">
<h1>Генератор клиентов</h1>
<div>
<p style={{fontWeight: "900", marginTop:"10px"}}>
Введите никнейм клиента:
<input
className="add-client-input"
value={clientNickName}
onChange={e => setClientNickName(e.target.value)}
/>
</p>
<p style={{fontWeight: "900", marginTop:"10px"}}>
Введите почту клиента:
<input
className="add-client-input"
value={clientEmail}
onChange={e => setClientEmail(e.target.value)}
/>
</p>
<p style={{fontWeight: "900", marginTop:"10px"}}>
Введите баланс клиента:
<input
className="add-client-input"
value={clientBalance}
onChange={e => setClientBalance(e.target.value)}
/>
</p>
</div>
<div>
<button className='add-level-button'
onClick={addNewClient}
>
Создать клиента
</button>
<button className='add-level-button'
onClick={CheckArray}
>
Вывести всех клиентов
</button>
</div>
</div>
<div className="Card_list">
{clientItems.length !== 0
?
<ClientList clientItems={clientItems}
/>
:
<h1 style={{textAlign: 'center'}}>В БД отсутствуют какие-либо клиенты!</h1>
}
</div>
</div>
);
}

View File

@ -0,0 +1,14 @@
.add-level-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}

View File

@ -0,0 +1,89 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import '../styles/App.css';
import LevelList from './items/Level/LevelList';
import './AddLevel.css';
//компонент для просмотра, создания и удаления уровней
const AddLevel = () => {
const [levelItems, setLevelItems] = useState([]);
//для создания нового уровня
const [level, setLevel] = useState({level: ''});
//загрузка всех имеющихся уровней при старте
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/level/')
.then((responce) => {
console.log(responce.data);
setLevelItems(responce.data)
})
}, [])
//обновить список уровней
function CheckArray(){
console.log('Обращение к БД');
axios.get('http://localhost:8080/level/')
.then((responce) => {
console.log(responce.data);
setLevelItems(responce.data)
})
}
//добавление нового уровня
function addNewLevel(){
if(level.level === ''){
return;
}
else {
axios.post('http://localhost:8080/level/?Level=' + parseInt(level.level, 10))
.then((response) => {
CheckArray();
setLevel({level: ''});
});
}
}
//добавили условную отрисовку
return(
<div>
<div className="Group_create_level">
<h1>Генератор уровней</h1>
<div>
<p style={{fontWeight: "900"}}>
Введите уровень:
<input
className="add-level-input"
value={level.level}
onChange={e => setLevel({level: e.target.value})}
/>
</p>
</div>
<div>
<button className='add-level-button'
onClick={addNewLevel}
>
Создать уровень
</button>
<button className='add-level-button'
onClick={CheckArray}
>
Вывести все уровни
</button>
</div>
</div>
<div className="Card_list">
{levelItems.length !== 0
?
<LevelList levelItems={levelItems}
/>
:
<h1 style={{textAlign: 'center'}}>В БД отсутствуют какие-либо уровни!</h1>
}
</div>
</div>
);
};
export default AddLevel;

View File

@ -0,0 +1,14 @@
.add-nation-input{
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}

View File

@ -0,0 +1,89 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import '../styles/App.css';
import NationList from './items/Nation/NationList';
import './AddNation.css';
//компонент для просмотра, создания и удаления уровней
const AddNation = () => {
const [nationItems, setNationItems] = useState([]);
//для создания нового уровня
const [nation, setNation] = useState({nation: ''});
//загрузка всех имеющихся уровней при старте
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/nation/')
.then((responce) => {
console.log(responce.data);
setNationItems(responce.data)
})
}, [])
//обновить список уровней
function CheckArray(){
console.log('Обращение к БД');
axios.get('http://localhost:8080/nation/')
.then((responce) => {
console.log(responce.data);
setNationItems(responce.data)
})
}
//добавление нового уровня
function addNewNation(){
if(nation.nation === ''){
return;
}
else {
axios.post('http://localhost:8080/nation/?nation=' + nation.nation)
.then((response) => {
CheckArray();
setNation({nation: ''});
});
}
}
//добавили условную отрисовку
return(
<div>
<div className="Group_create_level">
<h1>Генератор наций</h1>
<div>
<p style={{fontWeight: "900"}}>
Введите нацию:
<input
className="add-nation-input"
value={nation.nation}
onChange={e => setNation({nation: e.target.value})}
/>
</p>
</div>
<div>
<button className='add-level-button'
onClick={addNewNation}
>
Создать нацию
</button>
<button className='add-level-button'
onClick={CheckArray}
>
Вывести все нации
</button>
</div>
</div>
<div className="Card_list">
{nationItems.length !== 0
?
<NationList nationItems={nationItems}
/>
:
<h1 style={{textAlign: 'center'}}>В БД отсутствуют какие-либо нации!</h1>
}
</div>
</div>
);
};
export default AddNation;

View File

@ -0,0 +1,15 @@
.add-tank-input{
margin-top: 10px;
padding-left: 10px;
padding-right: 10px;
border: 3px solid;
border-radius: 10px;
border-color: #505050;
}
.add-level-button{
border-radius: 10px;
border-color: #505050;
background-color: #FFE430;
font-weight: 900;
}

View File

@ -0,0 +1,198 @@
import React, { useState, useEffect, useRef} from 'react';
import axios from 'axios';
import '../styles/App.css';
import TankList from './items/Tank/TankList';
import './AddTank.css';
const AddTank = () => {
const [tankItems, setTankItems] = useState([]);
//для создания нового танка
const [tankName, setTankName] = useState({tankName: ''});
const [tankCost, setTankCost] = useState({tankCost: ''});
const [nationItems, setNationItems] = useState([]);
const [levelItems, setLevelItems] = useState([]);
//храним выбранные нацию и уровень для нового танка
const [chooiceNation, setChooiceNation] = useState();
const [chooiceLevel, setChooiceLevel] = useState();
const [fileByte, setFileByte] = useState(null);
const inputRef = useRef();
//загрузка всех имеющихся танков, а также уровней и наций при старте
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/tank/')
.then((responce) => {
console.log(responce.data);
setTankItems(responce.data)
});
axios.get('http://localhost:8080/level/')
.then((responce) => {
console.log(responce.data);
setLevelItems(responce.data)
});
axios.get('http://localhost:8080/nation/')
.then((responce) => {
console.log(responce.data);
setNationItems(responce.data)
});
}, [])
//обновить список танков
function CheckArray(){
console.log('Обращение к БД');
axios.get('http://localhost:8080/tank/')
.then((responce) => {
console.log(responce.data);
setTankItems(responce.data)
})
}
//добавление нового танка
async function addNewTank(){
console.log(tankName);
console.log(tankCost);
console.log(chooiceNation);
console.log(chooiceLevel);
//console.log(imageURL);
//const header = new Headers({ "Access-Control-Allow-Origin": "*" });
axios.post("http://localhost:8080/tank/?firstName=" + tankName.tankName +
"&id=" + chooiceNation.id + "&nationId=" + chooiceNation + "&levelId=" + chooiceLevel +
"&cost=" + tankCost.tankCost)
.then((response) => {
console.log("Успешное добавление");
console.log(response.data);
CheckArray();
setTankCost({tankCost: ''});
setTankName({tankName: ''});
});
//}*/
}
//хранит картинку для танка
const [imageURL, setImageURL] = useState();
const fileReader = new FileReader();
fileReader.onloadend = () => {
const tempval = fileReader.result
setImageURL(tempval);
};
function handleOnChange(event) {
event.preventDefault();
const file = event.target.files[0];
fileReader.readAsDataURL(file);
}
const getChoiceNation = (newId) => {
setChooiceNation(nationItems[newId - 1].id);
}
const getChoiceLevel = (newId) => {
setChooiceLevel(levelItems[newId - 1].id);
}
//для добавления картинок
/*<p style={{fontWeight: "900", marginTop: "10px"}}>
Выберите изображение:
<input className="add-tank-input" id="formFileSm" type="file"
accept="image/jpeg, image/png, image/jpg"
value=''
style={{marginTop: "10px"}}
//onChange={e => setTank({tankImage: e.target.value})}
//onChange={() => setTank({tankImage: inputRef.current.files[0]})}
onChange={handleOnChange}
//ref={inputRef}
/>
</p>*/
//добавили условную отрисовку
return(
<div>
<div className="Group_create_level">
<h1>Генератор танков</h1>
<div>
<p style={{fontWeight: "900"}}>
Выберите нацию:
<select
onChange={(event) => getChoiceNation(event.target.selectedIndex)}
>
<option selected>Выберите нацию</option>
{nationItems.map((nationItem) =>
<option
value={nationItem.nation}
key={nationItem.id}
>
{nationItem.nation}
</option>
)}
</select>
</p>
<p style={{fontWeight: "900"}}>
Выберите уровень:
<select style={{marginTop: "10px"}}
onChange={(event) => getChoiceLevel(event.target.selectedIndex)}
>
<option selected>Выберите уровень</option>
{levelItems.map((levelItem) =>
<option
value={levelItem.level}
key={levelItem.id}
>
{levelItem.level}
</option>
)}
</select>
</p>
<p style={{fontWeight: "900"}}>
Введите название:
<input
className="add-tank-input"
value={tankName.tankName}
onChange={e => setTankName({tankName: e.target.value})}
/>
</p>
<p style={{fontWeight: "900"}}>
Введите стоимость:
<input
className="add-tank-input"
value={tankCost.tankCost}
onChange={e => setTankCost({tankCost: e.target.value})}
/>
</p>
</div>
<div>
<button className='add-level-button'
onClick={addNewTank}
>
Создать танк
</button>
<button className='add-level-button'
onClick={CheckArray}
>
Вывести все танки
</button>
</div>
</div>
<div className="Card_list">
{tankItems.length !== 0
?
<TankList tankItems={tankItems}
/>
:
<h1 style={{textAlign: 'center'}}>В БД отсутствуют какие-либо танки!</h1>
}
</div>
</div>
);
}
export default AddTank

View File

@ -0,0 +1,41 @@
import React from 'react';
import '../styles/App.css';
import { NavLink } from 'react-router-dom';
//компонент с кнопками навигации по сайту
const MainHead = (props) => {
return(
<div>
<div>
<h1 className="Main-label">Мир танков</h1>
</div>
<form className="collapse navbar-collapse">
<nav className="navbar navbar-expand-lg justify-content-around">
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" style={{backgroundColor: '#379dc2'}}>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="Main_head navbar-nav me-auto align-items-center">
{
props.links.map(route =>
<li key={route.path}
className="nav-item">
<div className="Button_Main_Group container p-2" div="div">
<NavLink className="nav-link btn border border-3 border-dark fs-4 lh-15" role="button"
to={route.path}>
{route.label}
</NavLink>
</div>
</li>
)
}
</ul>
</div>
</nav>
</form>
</div>
)
}
export default MainHead;

View File

@ -0,0 +1,133 @@
import React, { useState, useEffect, useRef} from 'react';
import axios from 'axios';
import '../styles/App.css';
import TankList from './items/Tank/TankList';
import './AddTank.css';
const PageForChecking = () => {
const[tankItems, setTankItems] = useState([]);
const [nationItems, setNationItems] = useState([]);
const [levelItems, setLevelItems] = useState([]);
const [chooiceNation, setChooiceNation] = useState();
const [chooiceFirstLevel, setChooiceFirstLevel] = useState();
const [chooiceSecondLevel, setChooiceSecondLevel] = useState();
//загрузка всех имеющихся танков, а также уровней и наций при старте
useEffect(() => {
axios.get('http://localhost:8080/level/')
.then((responce) => {
console.log(responce.data);
setLevelItems(responce.data)
});
axios.get('http://localhost:8080/nation/')
.then((responce) => {
console.log(responce.data);
setNationItems(responce.data)
});
}, [])
const getChoiceNation = (newId) => {
setChooiceNation(nationItems[newId - 1].nation);
}
const getChooiceFirstLevel = (newId) => {
setChooiceFirstLevel(levelItems[newId - 1].level);
}
const getChooiceSecondLevel = (newId) => {
setChooiceSecondLevel(levelItems[newId - 1].level);
}
function findList(){
console.log(chooiceNation);
console.log(chooiceFirstLevel);
console.log(chooiceSecondLevel);
axios.get('http://localhost:8080/tank/filteredList/?nation=' + chooiceNation + '&firstLevel=' + chooiceFirstLevel + '&secondLevel=' + chooiceSecondLevel)
.then((response) => {
setTankItems(response.data)
});
console.log(tankItems)
}
return(
<div>
<div className="Group_create_level">
<h1>Фильтрация танков</h1>
<div>
<p style={{fontWeight: "900"}}>
Выберите нацию:
<select
onChange={(event) => getChoiceNation(event.target.selectedIndex)}
>
<option selected>Выберите нацию</option>
{nationItems.map((nationItem) =>
<option
value={nationItem.nation}
key={nationItem.id}
>
{nationItem.nation}
</option>
)}
</select>
</p>
<p style={{fontWeight: "900"}}>
Выберите начальный диапазон уровней:
<select style={{marginTop: "10px"}}
onChange={(event) => getChooiceFirstLevel(event.target.selectedIndex)}
>
<option selected>Выберите уровень</option>
{levelItems.map((levelItem) =>
<option
value={levelItem.level}
key={levelItem.id}
>
{levelItem.level}
</option>
)}
</select>
</p>
<p style={{fontWeight: "900"}}>
Выберите конечный диапазон уровней:
<select style={{marginTop: "10px"}}
onChange={(event) => getChooiceSecondLevel(event.target.selectedIndex)}
>
<option selected>Выберите уровень</option>
{levelItems.map((levelItem) =>
<option
value={levelItem.level}
key={levelItem.id}
>
{levelItem.level}
</option>
)}
</select>
</p>
</div>
<button className='add-level-button'
onClick={findList}
>
Найти танки
</button>
</div>
<div className="Card_list">
{tankItems.length !== 0
?
<TankList tankItems={tankItems}
/>
:
<h1 style={{textAlign: 'center'}}>Отсутствуют какие-либо танки при таком фильтре!</h1>
}
</div>
</div>
);
}
export default PageForChecking

View File

@ -0,0 +1,37 @@
.client-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.client-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.client-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.client-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,61 @@
import React, { useState } from 'react';
import axios from 'axios';
import './ClientItem.css';
import ModalClient from './ModalClient';
import ModalTankNation from '../Nation/ModalTankNation';
const ClientItem = (data) => {
const [client, setClient] = useState(null);
//состояние для контроля вызова модального окна
const[modal, setModal] = useState(false);
//состояние для вызова окна показа списка танков нации
const[modalNation, setModalNation] = useState(false);
function deleteClient(){
axios.delete('http://localhost:8080/client/' + data.clientItem.id)
.then((response) => {
console.log("Удаление уровня с id " + data.clientItem.id)
});
}
return (
<div className="client-card">
<p className="client-attribute"> id: {data.clientItem.id} </p>
<p className="client-attribute"> Никнейм: {data.clientItem.nickName} </p>
<p className="client-attribute"> Баланс: {data.clientItem.balance} </p>
<p className="client-attribute"> Почта: {data.clientItem.email} </p>
<div className='client-button-group'>
<button className="client-button" type="button"
onClick={() => setModal(true)}
>
Редактировать
</button>
<button className="client-button" type="button"
onClick={deleteClient}
>
Удалить
</button>
<button className="nation-button" type="button"
onClick={() => setModalNation(true)}
>
Список танков
</button>
<ModalClient
data={data.clientItem}
visible={modal}
setVisible={setModal}
/>
<ModalTankNation
data={data.clientItem}
visible={modalNation}
setVisible={setModalNation}
/>
</div>
</div>
);
};
export default ClientItem

View File

@ -0,0 +1,22 @@
import React, { useEffect} from 'react';
import ClientItem from './ClientItem';
const ClientList = (clients) => {
return (
<div>
<div>
<h1 style={{textAlign: 'center', fontFamily: 'courier, monospace', background: '#FF652F', borderRadius: '10px'}}>
Список существующих клиентов:
</h1>
</div>
{clients.clientItems.map((clientItem) =>
<ClientItem
clientItem={clientItem}
key={clientItem.id}
/>
)}
</div>
);
}
export default ClientList;

View File

@ -0,0 +1,106 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import cl from '../GameClient/ModalClient.module.css';
import '../../AddClient.css';
const ModalClient = ({data, visible, setVisible}) => {
//для обновления уровня
const [clientNickName, setClientNickName] = useState(data.nickName);
const [clientEmail, setClientEmail] = useState(data.email);
const [clientBalance, setClientBalance] = useState(data.balance);
const [clientTank, setClientTank] = useState(null);
const [tankItems, setTankItems] = useState([]);
useEffect(() => {
console.log('Обращение к БД');
axios.get('http://localhost:8080/tank/')
.then((responce) => {
console.log(responce.data);
setTankItems(responce.data)
});
}, [])
//для контроля видимости модалки
const rootClasses = [cl.myModal];
if(visible)
{
rootClasses.push(cl.active);
}
//добавление нового уровня
function updateLevel(){
axios.put('http://localhost:8080/client/' + data.id + '?nickName='
+ clientNickName + '&email=' + clientEmail + '&balance=' + clientBalance + '&tankId=' + clientTank)
.then((response) => {
console.log("Обновление клиента с id " + data.id)
});
setVisible(false);
}
const getChoiceNation = (newId) => {
setClientTank(tankItems[newId - 1].id);
}
return (
<div className={rootClasses.join(' ')} onClick={() => setVisible(false)}>
<div className={cl.myModalContent} onClick={(e) => e.stopPropagation()}>
<p style={{marginTop: "10px"}}>
Никнейм:
<input
className="add-client-input"
value={clientNickName}
onChange={e => setClientNickName(e.target.value)}
/>
</p>
<p style={{marginTop: "10px"}}>
Почта:
<input
className="add-client-input"
value={clientEmail}
onChange={e => setClientEmail(e.target.value)}
/>
</p>
<p style={{marginTop: "10px"}}>
Баланс:
<input
className="add-client-input"
value={clientBalance}
onChange={e => setClientBalance(e.target.value)}
/>
</p>
<p style={{fontWeight: "900"}}>
Выберите новый танк:
<select
onChange={(event) => getChoiceNation(event.target.selectedIndex)}
>
<option selected>Выберите танк</option>
{tankItems.map((tankItem) =>
<option
value={tankItem.name}
key={tankItem.id}
>
{tankItem.name}
</option>
)}
</select>
</p>
<button
style={{marginTop: "10px"}}
className={cl.modalButton}
type="button"
onClick={updateLevel}
>
Сохранить
</button>
</div>
</div>
);
}
export default ModalClient

View File

@ -0,0 +1,34 @@
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: inline-block;
padding: 15px;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,37 @@
.level-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.level-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.level-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.level-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,46 @@
import React, { useState } from 'react';
import axios from 'axios';
import './LevelItem.css';
import ModalLevel from './ModalLevel';
//отвечает за отдельно взятый уровень (вывод карточки с ним)
const LevelItem = (data) => {
const [level, setLevel] = useState(null);
//состояние для контроля вызова модального окна
const[modal, setModal] = useState(false);
function deleteLevel(){
axios.delete('http://localhost:8080/level/' + data.levelItem.id)
.then((response) => {
console.log("Удаление уровня с id " + data.levelItem.id)
});
}
return (
<div className="level-card">
<p className="level-attribute"> id: {data.levelItem.id} </p>
<p className="level-attribute"> уровень: {data.levelItem.level} </p>
<div className='level-button-group'>
<button className="level-button" type="button"
onClick={() => setModal(true)}
>
Редактировать
</button>
<button className="level-button" type="button"
onClick={deleteLevel}
>
Удалить
</button>
<ModalLevel
data={data.levelItem}
visible={modal}
setVisible={setModal}
/>
</div>
</div>
);
};
export default LevelItem;

View File

@ -0,0 +1,25 @@
import React, { useEffect} from 'react';
import LevelItem from './LevelItem';
//const host = import.meta.env.VITE_API_URL;
//отвечает за список всех уровней. Передаём сюда пропсом массив уровней
const LevelList = (levels) => {
return (
<div>
<div>
<h1 style={{textAlign: 'center', fontFamily: 'courier, monospace', background: '#FF652F', borderRadius: '10px'}}>
Список существующих уровней:
</h1>
</div>
{levels.levelItems.map((levelItem) =>
<LevelItem
levelItem={levelItem}
key={levelItem.id}
/>
)}
</div>
);
};
export default LevelList;

View File

@ -0,0 +1,49 @@
import React, { useState } from 'react';
import axios from 'axios';
import cl from './ModalLevel.module.css';
import '../../AddLevel.css';
const ModalLevel = ({data, visible, setVisible}) => {
//для обновления уровня
const [level, setLevel] = useState(data.level);
//для контроля видимости модалки
const rootClasses = [cl.myModal];
if(visible)
{
rootClasses.push(cl.active);
}
//добавление нового уровня
function updateLevel(){
setLevel()
axios.put('http://localhost:8080/level/' + data.id + '?Level=' + level)
.then((response) => {
console.log("Обновление уровня с id " + data.id)
});
setVisible(false);
}
return (
<div className={rootClasses.join(' ')} onClick={() => setVisible(false)}>
<div className={cl.myModalContent} onClick={(e) => e.stopPropagation()}>
<input
className="add-level-input"
value={level}
onChange={e => setLevel(e.target.value)}
/>
<button
className={cl.modalButton}
type="button"
onClick={updateLevel}
>
Сохранить
</button>
</div>
</div>
);
};
export default ModalLevel;

View File

@ -0,0 +1,34 @@
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: flex;
padding: 15px;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,50 @@
import React, { useState } from 'react';
import axios from 'axios';
import cl from './ModalNation.module.css';
import '../../AddNation.css';
const ModalNation = ({data, visible, setVisible}) => {
//для обновления уровня
const [nation, setNation] = useState(data.nation);
const nullId = 0;
//для контроля видимости модалки
const rootClasses = [cl.myModal];
if(visible)
{
rootClasses.push(cl.active);
}
//добавление новой нации
function updateLevel(){
setNation()
axios.put('http://localhost:8080/nation/' + data.id + '?nation=' + nation + '&tankId=' + nullId)
.then((response) => {
console.log("Обновление нации с id " + data.id)
});
setVisible(false);
}
return (
<div className={rootClasses.join(' ')} onClick={() => setVisible(false)}>
<div className={cl.myModalContent} onClick={(e) => e.stopPropagation()}>
<input
className="add-nation-input"
value={nation}
onChange={e => setNation(e.target.value)}
/>
<button
className={cl.modalButton}
type="button"
onClick={updateLevel}
>
Сохранить
</button>
</div>
</div>
);
}
export default ModalNation

View File

@ -0,0 +1,34 @@
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: flex;
padding: 15px;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
justify-content: space-between;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,42 @@
import React, { useState, useEffect } from 'react';
import cl from './ModalNation.module.css';
import '../../AddNation.css';
import TankList from '../Tank/TankList';
import { useFetcher } from 'react-router-dom';
const ModalTankNation = ({data, visible, setVisible}) => {
//для обновления уровня
const [nation, setNation] = useState(data.tanks);
//для контроля видимости модалки
const rootClasses = [cl.myModal];
//загрузка всех имеющихся танков, а также уровней и наций при старте
useEffect(() => {
console.log("Загрузка МОДАЛКИ №1")
console.log(nation);
}, [])
if(visible)
{
rootClasses.push(cl.active);
}
return (
<div className={rootClasses.join(' ')} onClick={() => setVisible(false)}>
<div className={cl.myModalContent} onClick={(e) => e.stopPropagation()}>
{nation.length !== 0
?
<TankList
label={"Список танков у нации"}
tankItems={nation}
/>
:
<h1 style={{textAlign: 'center'}}>В БД отсутствуют какие-либо танки данной нации!</h1>
}
</div>
</div>
);
}
export default ModalTankNation

View File

@ -0,0 +1,38 @@
.nation-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.nation-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.nation-button-group{
display: flex;
margin: 10px;
width: 20%;
justify-content: space-around;
align-items: center;
}
.nation-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,59 @@
import React, { useState } from 'react';
import axios from 'axios';
import './NationItem.css';
import ModalNation from './ModalNation';
import ModalTankNation from './ModalTankNation';
//отвечает за отдельно взятую нацию (вывод карточки с ним)
const NationItem = (data) => {
const [nation, setNation] = useState(null);
//состояние для контроля вызова модального окна
const[modal, setModal] = useState(false);
//состояние для вызова окна показа списка танков нации
const[modalNation, setModalNation] = useState(false);
function deleteNation(){
axios.delete('http://localhost:8080/nation/' + data.nationItem.id)
.then((response) => {
console.log("Удаление нации с id " + data.nationItem.id)
});
}
return (
<div className="nation-card">
<p className="nation-attribute"> id: {data.nationItem.id} </p>
<p className="nation-attribute"> нация: {data.nationItem.nation} </p>
<div className='nation-button-group'>
<button className="nation-button" type="button"
onClick={() => setModal(true)}
>
Редактировать
</button>
<button className="nation-button" type="button"
onClick={deleteNation}
>
Удалить
</button>
<button className="nation-button" type="button"
onClick={() => setModalNation(true)}
>
Список танков
</button>
<ModalNation
data={data.nationItem}
visible={modal}
setVisible={setModal}
/>
<ModalTankNation
data={data.nationItem}
visible={modalNation}
setVisible={setModalNation}
/>
</div>
</div>
);
}
export default NationItem

View File

@ -0,0 +1,22 @@
import React from 'react'
import NationItem from './NationItem';
const NationList = (nations) => {
return (
<div>
<div>
<h1 style={{textAlign: 'center', fontFamily: 'courier, monospace', background: '#FF652F', borderRadius: '10px'}}>
Список существующих наций:
</h1>
</div>
{nations.nationItems.map((nationItem) =>
<NationItem
nationItem={nationItem}
key={nationItem.id}
/>
)}
</div>
);
}
export default NationList

View File

@ -0,0 +1,125 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import cl from './ModalTank.module.css';
import '../../AddTank.css';
const ModalTank = ({data, visible, setVisible}) => {
//для обновления танка
const [tankName, setTankName] = useState(data.name);
const [tankCost, setTankCost] = useState(data.cost);
const [chooiceNation, setChoiceNation] = useState(data.nation.id);
const [chooiceLevel, setChoiceLevel] = useState(data.nation.id);
const [nationItems, setNationItems] = useState([]);
const [levelItems, setLevelItems] = useState([]);
//загрузка всех имеющихся танков, а также уровней и наций при старте
useEffect(() => {
axios.get('http://localhost:8080/level/')
.then((responce) => {
console.log(responce.data);
setLevelItems(responce.data)
});
axios.get('http://localhost:8080/nation/')
.then((responce) => {
console.log(responce.data);
setNationItems(responce.data)
});
}, [])
//для контроля видимости модалки
const rootClasses = [cl.myModal];
if(visible)
{
rootClasses.push(cl.active);
}
//добавление нового танка
function updateLevel(){
setTankName()
axios.put('http://localhost:8080/tank/' + data.id + '?firstName=' + tankName + '&nationId='
+ chooiceNation + '&levelId=' + chooiceLevel + '&cost=' + tankCost)
.then((response) => {
console.log("Обновление танка с id " + data.id)
});
setVisible(false);
}
const getChoiceNation = (newId) => {
setChoiceNation(nationItems[newId - 1].id);
}
const getChoiceLevel = (newId) => {
setChoiceLevel(levelItems[newId - 1].id);
}
return (
<div className={rootClasses.join(' ')} onClick={() => setVisible(false)}>
<div className={cl.myModalContent} onClick={(e) => e.stopPropagation()}>
<p>
Название:
<input
className="add-tank-input"
value={tankName}
onChange={e => setTankName(e.target.value)}
/>
</p>
<p>
Стоимость:
<input
className="add-tank-input"
value={tankCost}
onChange={e => setTankCost(e.target.value)}
/>
</p>
<p style={{fontWeight: "900"}}>
Выберите нацию:
<select
onChange={(event) => getChoiceNation(event.target.selectedIndex)}
>
<option selected>Выберите нацию</option>
{nationItems.map((nationItem) =>
<option
value={nationItem.nation}
key={nationItem.id}
>
{nationItem.nation}
</option>
)}
</select>
</p>
<p style={{fontWeight: "900"}}>
Выберите уровень:
<select style={{marginTop: "10px"}}
onChange={(event) => getChoiceLevel(event.target.selectedIndex)}
>
<option selected>Выберите уровень</option>
{levelItems.map((levelItem) =>
<option
value={levelItem.level}
key={levelItem.id}
>
{levelItem.level}
</option>
)}
</select>
</p>
<button
className={cl.modalButton}
type="button"
onClick={updateLevel}
>
Сохранить
</button>
</div>
</div>
);
}
export default ModalTank

View File

@ -0,0 +1,33 @@
.myModal{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: none;
background: rgba(0, 0, 0, 0.8);
}
.myModal.active{
display: flex;
justify-content: center;
align-items: center;
}
.myModalContent{
display: inline-block;
padding: 15px;
background: #FF652F;
border-radius: 16px;
min-width: 300px;
min-height: 100px;
align-items: center;
}
.modalButton{
padding: 5px;
border-radius: 10px;
background-color: #FFE430;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,37 @@
.tank-card{
display: flex;
width: 100%;
padding: 15px;
margin-top: 5px;
border: 5px solid;
border-color: #14A76C;
border-radius: 10px;
justify-content: space-around;
align-items: center;
font-family: Courier, monospace;
font-weight: 900;
}
.tank-attribute{
padding: 5px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
align-items: center;
}
.tank-button-group{
display: flex;
width: 20%;
justify-content: space-around;
align-items: center;
}
.tank-button{
padding: 10px;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: 900;
}

View File

@ -0,0 +1,48 @@
import React, { useState } from 'react';
import axios from 'axios';
import './TankItem.css';
import ModalTank from './ModalTank';
const TankItem = (data) => {
const [tank, setTank] = useState(null);
//состояние для контроля вызова модального окна
const[modal, setModal] = useState(false);
function deleteTank(){
axios.delete('http://localhost:8080/tank/' + data.tankItem.id)
.then((response) => {
console.log("Удаление танка с id " + data.tankItem.id)
});
}
return (
<div className="tank-card">
<p className="tank-attribute"> id: {data.tankItem.id} </p>
<p className="tank-attribute"> название: {data.tankItem.name} </p>
<p className="tank-attribute"> уровень: {data.tankItem.level.level} </p>
<p className="tank-attribute"> нация: {data.tankItem.nation.nation} </p>
<p className="tank-attribute"> стоимость: {data.tankItem.cost} </p>
<div className='tank-button-group'>
<button className="tank-button" type="button"
onClick={() => setModal(true)}
>
Редактировать
</button>
<button className="tank-button" type="button"
onClick={deleteTank}
>
Удалить
</button>
<ModalTank
data={data.tankItem}
visible={modal}
setVisible={setModal}
/>
</div>
</div>
);
}
export default TankItem

View File

@ -0,0 +1,22 @@
import React from 'react'
import TankItem from './TankItem';
const TankList = (tanks) => {
return (
<div>
<div>
<h1 style={{textAlign: 'center', fontFamily: 'courier, monospace', background: '#FF652F', borderRadius: '10px'}}>
Список существующих наций:
</h1>
</div>
{tanks.tankItems.map((tankItem) =>
<TankItem
tankItem={tankItem}
key={tankItem.id}
/>
)}
</div>
);
}
export default TankList;

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

View File

@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
);

View File

@ -0,0 +1,90 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/*#505050*/
#root{
display: flex;
justify-content: center;
background-color: #151719;
background-image: url("../images/wot-is-4.jpg");
background-size: cover;
background-attachment: fixed;
font-family: Courier, monospace;
font-weight: 900;
}
.body{
margin: 0; /* Убираем отступы */
height: 100%; /* Высота страницы */
}
.App{
width: 1200px;
}
.Group_create_level{
display: flex;
padding: 15px;
background-color: #FFE430;
opacity: 0.8;
border-radius: 10px;
margin-top: 15px;
justify-content: space-around;
align-items: center;
}
.Card_list{
padding: 15px;
border: 5px solid;
border-color: #14A76C;
background-color: #151719;
opacity: 0.9;
border-radius: 10px;
margin-top: 15px;
align-items: center;
}
.Main_head{
display: flex;
padding: 15px;
margin-top: 30px;
border: 5px solid;
border-color: #FF652F;
border-radius: 10px;
background-color: #151719;
opacity: 0.9;
justify-content: space-between;
align-items: center;
}
.Button_Main_Group{
padding: 5px;
border-color: #FF652F;
border-radius: 10px;
background-color: #FF652F;
font-family: Courier, monospace;
font-weight: bold;
align-items: center;
}
.add-level-button{
padding: 10px;
margin-right: 15px;
}
.Main-label{
display: flex;
padding-top: 16px;
font-size: 7vw;
font-variant: small-caps;
font-stretch: ultra-expanded;
justify-content: space-around;
align-items: center;
color: #505050;
-webkit-text-stroke-width: 3.0px;
-webkit-text-stroke-color: #000000;
}

View File

@ -1,10 +0,0 @@
import React from 'react';
function App() {
return (
<div className="App">
</div>
);
}
export default App;

View File

@ -1,11 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
//document.getElementById('root'); - для работы этого надо поставит запятую после <App/>
//и делаем import 'react-dom', вместо 'react-dom/client'
);

View File

@ -35,3 +35,5 @@ out/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
*.db

View File

@ -1,10 +1,10 @@
plugins { plugins {
id 'java' id 'org.springframework.boot' version '2.6.5'
id 'org.springframework.boot' version '2.7.8'
id 'io.spring.dependency-management' version '1.0.15.RELEASE' id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java'
} }
group = 'com.example' group = 'ru.ulstu.is'
version = '0.0.1-SNAPSHOT' version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17' sourceCompatibility = '17'
@ -12,9 +12,29 @@ repositories {
mavenCentral() mavenCentral()
} }
jar {
enabled = false
}
dependencies { dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.webjars:bootstrap:5.1.3'
implementation 'org.webjars:jquery:3.6.0'
implementation 'org.webjars:font-awesome:6.1.0'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
} }

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -205,12 +205,6 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

View File

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -75,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL% if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
if %EXIT_CODE% equ 0 set EXIT_CODE=1 exit /b 1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@ -1 +1 @@
rootProject.name = 'spring_online_calculator' rootProject.name = 'premium_store'

View File

@ -1,13 +0,0 @@
package com.example.spring_online_calculator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringOnlineCalculatorApplication {
public static void main(String[] args) {
SpringApplication.run(SpringOnlineCalculatorApplication.class, args);
}
}

View File

@ -0,0 +1,11 @@
package premium_store;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PremiumStoreApplication {
public static void main(String[] args) {
SpringApplication.run(PremiumStoreApplication.class, args);
}
}

View File

@ -0,0 +1,17 @@
package premium_store;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//отключение Cors фильтра - не позволяет организовавыть взаимодействие с разных доменов
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
public static final String REST_API = "/api";
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
}

View File

@ -0,0 +1,72 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.GameClient;
import java.util.List;
//класс, который соединяет танки клиента в одну строчку (нам так захотелось)
public class ClientDTO {
private long id;
private String nickName;
private String email;
private Integer balance;
private List<TankDTO> tanks;
public ClientDTO(){ }
public ClientDTO(GameClient gameClient){
this.id = gameClient.getId();
this.nickName = gameClient.getNickName();
this.email = gameClient.getEmail();
this.balance = gameClient.getBalance();
this.tanks = gameClient.getTanks().stream()
.map(TankDTO::new)
.toList();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public long getId(){
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNickName(){
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getEmail(){
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getBalance(){
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public List<TankDTO> getTanks(){
return tanks;
}
public Long getIdLastTanks(){
return tanks.get(tanks.size() - 1).getId();
}
public void setTanks(List<TankDTO> tanks) {
this.tanks = tanks;
}
}

View File

@ -0,0 +1,47 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.Nation;
import java.util.List;
public class FullNationDTO {
public Long id;
public String nation;
public List<TankDTO> tanks;
public FullNationDTO(){ }
public FullNationDTO(Nation nation){
this.id = nation.getId();
this.nation = nation.getNation();
this.tanks = nation.getTanksOfThisNation().stream()
.map(TankDTO::new)
.toList();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public List<TankDTO> getTanksOfThisNation() {
return tanks;
}
public void setTanks(List<TankDTO> tanks) {
this.tanks = tanks;
}
}

View File

@ -0,0 +1,33 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.TankLevel;
public class LevelDTO {
private Long id;
private int level;
public LevelDTO(){}
public LevelDTO(TankLevel level){
this.id = level.getId();
this.level = level.getLevel();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
public int getLevel(){
return level;
}
public void setLevel(int level) {
this.level = level;
}
}

View File

@ -0,0 +1,33 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.Nation;
public class SimpleNationDTO {
private Long id;
private String nation;
public SimpleNationDTO(){}
public SimpleNationDTO(Nation nation){
this.id = nation.getId();
this.nation = nation.getNation();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
public String getNation(){
return nation;
}
public void setNation(String nation){
this.nation = nation;
}
}

View File

@ -0,0 +1,39 @@
package premium_store.controller.DTO;
public class SortDTO {
private String nation;
private int firstLevel;
private int secondLevel;
public SortDTO(){}
public SortDTO(String nation, int firstLevel, int secondLevel){
this.nation = nation;
this.firstLevel = firstLevel;
this.secondLevel = secondLevel;
}
public String getNation(){
return nation;
}
public int getFirstLevel() {
return firstLevel;
}
public int getSecondLevel() {
return secondLevel;
}
public void setNation(String nation){
this.nation = nation;
}
public void setFirstLevel(int firstLevel){
this.firstLevel = firstLevel;
}
public void setSecondLevel(int secondLevel) {
this.secondLevel = secondLevel;
}
}

View File

@ -0,0 +1,72 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.GameClient;
import java.util.List;
//класс, который соединяет танки клиента в одну строчку (нам так захотелось)
public class SupportClientDTO {
private long id;
private String nickName;
private String email;
private Integer balance;
private Long tankId;
public SupportClientDTO(){ }
public SupportClientDTO(GameClient gameClient){
this.id = gameClient.getId();
this.nickName = gameClient.getNickName();
this.email = gameClient.getEmail();
this.balance = gameClient.getBalance();
if(gameClient.getTanks().size() >= 1){
this.tankId = gameClient.getTanks().get(gameClient.getTanks().size() - 1).getId();
}
else {
this.tankId = null;
}
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public long getId(){
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNickName(){
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getEmail(){
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getBalance(){
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public Long getTankId(){
return tankId;
}
public void setTankId(Long tankId) {
this.tankId = tankId;
}
}

View File

@ -0,0 +1,63 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.Tank;
public class SupportTankDTO {
private long id;
private String name;
private Long nationId;
private Long levelId;
private int cost;
public SupportTankDTO(){}
public SupportTankDTO(Tank tank){
this.id = tank.getId();
this.nationId = tank.getNation().getId();
this.levelId = tank.getLevel().getId();
this.name = tank.getName();
this.cost = tank.getCost();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId(){
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getNationId(){
return nationId;
}
public void setNationId(Long nationId) {
this.nationId = nationId;
}
public Long getLevelId(){
return levelId;
}
public void setLevelId(Long levelId) {
this.levelId = levelId;
}
public int getCost(){
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
}

View File

@ -0,0 +1,63 @@
package premium_store.controller.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import premium_store.model.Tank;
public class TankDTO {
private long id;
private String name;
private SimpleNationDTO nation;
private LevelDTO level;
private int cost;
public TankDTO(){}
public TankDTO(Tank tank){
this.id = tank.getId();
this.nation = new SimpleNationDTO(tank.getNation());
this.level = new LevelDTO(tank.getLevel());
this.name = tank.getName();
this.cost = tank.getCost();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public long getId(){
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public SimpleNationDTO getNation(){
return nation;
}
public void setNation(SimpleNationDTO nation) {
this.nation = nation;
}
public LevelDTO getLevel(){
return level;
}
public void setLevel(LevelDTO level) {
this.level = level;
}
public int getCost(){
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
}

View File

@ -0,0 +1,91 @@
package premium_store.controller.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import premium_store.controller.DTO.*;
import premium_store.service.GameClientService;
import premium_store.service.TankService;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequestMapping("/client")
public class ClientMvcController {
private final GameClientService gameClientService;
private final TankService tankService;
public ClientMvcController(GameClientService gameClientService, TankService tankService){
this.gameClientService = gameClientService;
this.tankService = tankService;
}
@GetMapping
public String getClients(Model model){
model.addAttribute("clients",
gameClientService.findAllClients().stream()
.map(ClientDTO::new)
.toList());
return "client";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editClient(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("supportClientDTO", new SupportClientDTO());
}
else {
model.addAttribute("clientId", id);
model.addAttribute("supportClientDTO", new SupportClientDTO(gameClientService.findClient(id)));
}
List<TankDTO> tanks = tankService.findAllTanks().stream()
.map(TankDTO::new)
.toList();
model.addAttribute("tanks", tanks);
return "client-edit";
}
@GetMapping(value = {"/tanksOfClient", "/tanksOfClient/{id}"})
public String editTanksOfClient(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("clientDTO", new ClientDTO());
}
else {
model.addAttribute("clientId", id);
model.addAttribute("clientDTO", new ClientDTO(gameClientService.findClient(id)));
}
return "tanks-of-client-edit";
}
@PostMapping(value = {"", "/{id}"})
public String saveClient(@PathVariable(required = false) Long id,
@ModelAttribute @Valid SupportClientDTO clientDTO,
BindingResult bindingResult,
Model model){
if(bindingResult.hasErrors()){
model.addAttribute("errors", bindingResult.getAllErrors());
return "client-edit";
}
if(id == null || id <= 0){
gameClientService.addClient(clientDTO.getNickName(), clientDTO.getNickName(), clientDTO.getBalance());
} else {
gameClientService.updateClient(clientDTO);
}
return "redirect:/client";
}
@PostMapping("/delete/{id}")
public String deleteClient(@PathVariable Long id){
gameClientService.deleteClient(id);
return "redirect:/tank";
}
}

View File

@ -0,0 +1,56 @@
package premium_store.controller.controller;
import org.springframework.web.bind.annotation.*;
import premium_store.WebConfiguration;
import premium_store.controller.DTO.ClientDTO;
import premium_store.service.GameClientService;
import premium_store.service.TankService;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/client")
public class GameClientController {
private final GameClientService gameClientService;
private final TankService tankService;
public GameClientController(GameClientService gameClientService, TankService tankService){
this.gameClientService = gameClientService;
this.tankService = tankService;
}
//аннотация PathVariable связывает значения id из URL и Long id
@GetMapping("/{id}")
public ClientDTO getClient(@PathVariable Long id) {
return new ClientDTO(gameClientService.findClient(id));
}
//с помощью Java Stream преобразуем набор пришедших данных в объекты StudentDto
@GetMapping("/")
public List<ClientDTO> getClients() {
return gameClientService.findAllClients().stream()
.map(ClientDTO::new)
.toList();
}
@PostMapping("/")
public ClientDTO createClient(@RequestParam("nickName") String nickName,
@RequestParam("email") String email,
@RequestParam("balance") Integer balance) {
return new ClientDTO(gameClientService.addClient(nickName, email, balance));
}
@PutMapping("/{id}")
public ClientDTO updateClient(@PathVariable Long id,
@RequestParam("nickName") String nickName,
@RequestParam("email") String email,
@RequestParam("balance") Integer balance,
@RequestParam("tankId") Long tankId) {
return new ClientDTO(gameClientService.updateClient(id, nickName, email, balance, tankService.findTank(tankId)));
}
@DeleteMapping("/{id}")
public ClientDTO deleteClient(@PathVariable Long id) {
return new ClientDTO(gameClientService.deleteClient(id));
}
}

View File

@ -0,0 +1,71 @@
package premium_store.controller.controller;
import net.bytebuddy.implementation.bind.MethodDelegationBinder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import premium_store.controller.DTO.FullNationDTO;
import premium_store.controller.DTO.LevelDTO;
import premium_store.controller.DTO.SimpleNationDTO;
import premium_store.service.NationService;
import premium_store.service.TankLevelService;
import javax.validation.Valid;
@Controller
@RequestMapping("/level")
public class LevelMvcController {
private final TankLevelService levelService;
public LevelMvcController(TankLevelService levelService){
this.levelService = levelService;
}
@GetMapping
public String getLevels(Model model){
model.addAttribute("levels",
levelService.findAllLevels().stream()
.map(LevelDTO::new)
.toList());
return "level";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editLevel(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("levelDTO", new LevelDTO());
}
else {
model.addAttribute("levelId", id);
model.addAttribute("levelDTO", new LevelDTO(levelService.findLevel(id)));
}
return "level-edit";
}
@PostMapping(value = {"", "/{id}"})
public String saveLevel(@PathVariable(required = false) Long id,
@ModelAttribute @Valid LevelDTO levelDTO,
BindingResult bindingResult,
Model model){
if(bindingResult.hasErrors()){
model.addAttribute("errors", bindingResult.getAllErrors());
return "level-edit";
}
if(id == null || id <= 0){
levelService.addLevel(levelDTO.getLevel());
} else {
levelService.updateLevel(id, levelDTO.getLevel());
}
return "redirect:/level";
}
@PostMapping("/delete/{id}")
public String deleteLevel(@PathVariable Long id){
levelService.deleteLevel(id);
return "redirect:/level";
}
}

View File

@ -0,0 +1,57 @@
package premium_store.controller.controller;
import org.springframework.web.bind.annotation.*;
import premium_store.WebConfiguration;
import premium_store.controller.DTO.FullNationDTO;
import premium_store.service.NationService;
import premium_store.service.TankService;
import java.util.List;
//привязываем наш контроллер к придуманному корневому URL благодаря аннотациям
//здесь происходит внедрение зависимости нашего сервиса
//так же здесь прописываем вызовы методов CRUD в привязке к URL
@RestController
@CrossOrigin
@RequestMapping(WebConfiguration.REST_API + "/nation")
public class NationController {
private final NationService nationService;
private final TankService tankService;
public NationController(NationService nationService, TankService tankService){
this.nationService = nationService;
this.tankService = tankService;
}
//аннотация PathVariable связывает значения id из URL и Long id
@GetMapping("/{id}")
public FullNationDTO getNation(@PathVariable Long id) {
return new FullNationDTO(nationService.findNation(id));
}
//с помощью Java Stream преобразуем набор пришедших данных в объекты StudentDto
@GetMapping("/")
public List<FullNationDTO> getNations() {
return nationService.findAllNations().stream()
.map(FullNationDTO::new)
.toList();
}
@PostMapping("/")
public FullNationDTO createNation(@RequestParam("nation") String nation) {
return new FullNationDTO(nationService.addNation(nation));
}
@PutMapping("/{id}")
public FullNationDTO updateNation(@PathVariable Long id,
@RequestParam("nation") String nation,
@RequestParam(value = "tankId", required = false) Long tankId ) {
return new FullNationDTO(nationService.updateNation(id, nation, (tankId > 0) ? tankService.findTank(tankId) : null));
}
@DeleteMapping("/{id}")
public FullNationDTO deleteNation(@PathVariable Long id) {
return new FullNationDTO(nationService.deleteNation(id));
}
}

View File

@ -0,0 +1,82 @@
package premium_store.controller.controller;
import net.bytebuddy.implementation.bind.MethodDelegationBinder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import premium_store.controller.DTO.FullNationDTO;
import premium_store.controller.DTO.SimpleNationDTO;
import premium_store.service.NationService;
import javax.validation.Valid;
@Controller
@RequestMapping("/nation")
public class NationMvcController {
private final NationService nationService;
public NationMvcController(NationService nationService){
this.nationService = nationService;
}
@GetMapping
public String getNations(Model model){
model.addAttribute("nations",
nationService.findAllNations().stream()
.map(FullNationDTO::new)
.toList());
return "nation";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editNation(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("simpleNationDTO", new SimpleNationDTO());
}
else {
model.addAttribute("nationId", id);
model.addAttribute("simpleNationDTO", new SimpleNationDTO(nationService.findNation(id)));
}
return "nation-edit";
}
@GetMapping(value = {"/editTank", "/editTank/{id}"})
public String editTankNation(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("fullNationDTO", new FullNationDTO());
}
else {
model.addAttribute("nationId", id);
model.addAttribute("fullNationDTO", new FullNationDTO(nationService.findNation(id)));
}
return "nation-tank-edit";
}
@PostMapping(value = {"", "/{id}"})
public String saveNation(@PathVariable(required = false) Long id,
@ModelAttribute @Valid SimpleNationDTO simpleNationDTO,
BindingResult bindingResult,
Model model){
if(bindingResult.hasErrors()){
model.addAttribute("errors", bindingResult.getAllErrors());
return "nation-edit";
}
if(id == null || id <= 0){
nationService.addNation(simpleNationDTO.getNation());
} else {
nationService.updateNation(id, simpleNationDTO.getNation(), null);
}
return "redirect:/nation";
}
@PostMapping("/delete/{id}")
public String deleteNation(@PathVariable Long id){
nationService.deleteNation(id);
return "redirect:/nation";
}
}

View File

@ -0,0 +1,72 @@
package premium_store.controller.controller;
import org.springframework.web.bind.annotation.*;
import premium_store.WebConfiguration;
import premium_store.controller.DTO.TankDTO;
import premium_store.service.NationService;
import premium_store.service.TankLevelService;
import premium_store.service.TankService;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping(WebConfiguration.REST_API + "/tank")
public class TankController {
private final TankService tankService;
private final TankLevelService tankLevelService;
private final NationService nationService;
public TankController(TankService tankService, TankLevelService tankLevelService, NationService nationService){
this.tankService = tankService;
this.tankLevelService = tankLevelService;
this.nationService = nationService;
}
//аннотация PathVariable связывает значения id из URL и Long id
@GetMapping("/{id}")
public TankDTO getTank(@PathVariable Long id) {
return new TankDTO(tankService.findTank(id));
}
//с помощью Java Stream преобразуем набор пришедших данных в объекты TankDTO
@GetMapping("/")
public List<TankDTO> getTanks() {
return tankService.findAllTanks().stream()
.map(TankDTO::new)
.toList();
}
@GetMapping("/filteredList/")
public List<TankDTO> getFilteredTanks(@RequestParam("nation") String nation,
@RequestParam("firstLevel") int firstLevel,
@RequestParam("secondLevel") int secondLevel) {
return tankService.findListTank(nation, firstLevel, secondLevel).stream()
.map(TankDTO::new)
.toList();
}
@PostMapping("/")
public TankDTO createTank(@RequestParam("firstName") String name,
@RequestParam("nationId") Long nationId,
@RequestParam("levelId") Long tankLevelId,
@RequestParam("cost") int cost
) {
return new TankDTO(tankService.addTank(name, nationService.findNation(nationId), tankLevelService.findLevel(tankLevelId), cost));
}
@PutMapping("/{id}")
public TankDTO updateTank(@PathVariable Long id,
@RequestParam("firstName") String name,
@RequestParam("nationId") Long nationId,
@RequestParam("levelId") Long tankLevelId,
@RequestParam("cost") int cost
) {
return new TankDTO(tankService.updateTank(id, name, nationService.findNation(nationId), tankLevelService.findLevel(tankLevelId), cost));
}
@DeleteMapping("/{id}")
public TankDTO deleteTank(@PathVariable Long id) {
return new TankDTO(tankService.deleteTank(id));
}
}

View File

@ -0,0 +1,51 @@
package premium_store.controller.controller;
import org.springframework.web.bind.annotation.*;
import premium_store.WebConfiguration;
import premium_store.controller.DTO.LevelDTO;
import premium_store.service.TankLevelService;
import java.util.List;
//привязываем наш контроллер к придуманному корневому URL благодаря аннотациям
//здесь происходит внедрение зависимости нашего сервиса
//так же здесь прописываем вызовы методов CRUD в привязке к URL
@RestController
@RequestMapping(WebConfiguration.REST_API + "/level")
public class TankLevelController {
private final TankLevelService tankLevelService;
public TankLevelController(TankLevelService tankLevelService){
this.tankLevelService = tankLevelService;
}
//аннотация PathVariable связывает значения id из URL и Long id
@GetMapping("/{id}")
public LevelDTO getLevel(@PathVariable Long id) {
return new LevelDTO(tankLevelService.findLevel(id));
}
//с помощью Java Stream преобразуем набор пришедших данных в объекты StudentDto
@GetMapping("/")
public List<LevelDTO> getLevels() {
return tankLevelService.findAllLevels().stream()
.map(LevelDTO::new)
.toList();
}
@PostMapping("/")
public LevelDTO createLevel(@RequestParam("Level") int level) {
return new LevelDTO(tankLevelService.addLevel(level));
}
@PutMapping("/{id}")
public LevelDTO updateLevel(@PathVariable Long id,
@RequestParam("Level") int level) {
return new LevelDTO(tankLevelService.updateLevel(id, level));
}
@DeleteMapping("/{id}")
public LevelDTO deleteLevel(@PathVariable Long id) {
return new LevelDTO(tankLevelService.deleteLevel(id));
}
}

View File

@ -0,0 +1,113 @@
package premium_store.controller.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import premium_store.controller.DTO.*;
import premium_store.service.NationService;
import premium_store.service.TankLevelService;
import premium_store.service.TankService;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequestMapping("/tank")
public class TankMvcController {
private final TankService tankService;
private final NationService nationService;
private final TankLevelService tankLevelService;
public TankMvcController(TankService tankService, NationService nationService, TankLevelService tankLevelService){
this.tankService = tankService;
this.nationService = nationService;
this.tankLevelService = tankLevelService;
}
@GetMapping
public String getTanks(Model model){
model.addAttribute("tanks",
tankService.findAllTanks().stream()
.map(TankDTO::new)
.toList());
List<SimpleNationDTO> nations = nationService.findAllNations().stream()
.map(SimpleNationDTO::new)
.toList();
model.addAttribute("nations", nations);
List<LevelDTO> levels = tankLevelService.findAllLevels().stream()
.map(LevelDTO::new)
.toList();
model.addAttribute("levels", levels);
model.addAttribute("sortDTO", new SortDTO());
return "tank";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editTank(@PathVariable(required = false) Long id, Model model){
if(id == null || id <= 0){
model.addAttribute("supportTankDTO", new SupportTankDTO());
}
else {
model.addAttribute("tankId", id);
model.addAttribute("supportTankDTO", new SupportTankDTO(tankService.findTank(id)));
}
List<SimpleNationDTO> nations = nationService.findAllNations().stream()
.map(SimpleNationDTO::new)
.toList();
model.addAttribute("nations", nations);
List<LevelDTO> levels = tankLevelService.findAllLevels().stream()
.map(LevelDTO::new)
.toList();
model.addAttribute("levels", levels);
return "tank-edit";
}
@GetMapping("/filteredList")
public String getFilteredTanks(@ModelAttribute SortDTO sortDTO,
Model model) {
List<TankDTO> tanks = tankService.findListTank(sortDTO.getNation(), sortDTO.getFirstLevel(), sortDTO.getSecondLevel()).stream()
.map(TankDTO::new)
.toList();
model.addAttribute("tanks", tanks);
return "filter";
}
@PostMapping(value = {"", "/{id}"})
public String saveTank(@PathVariable(required = false) Long id,
@ModelAttribute @Valid SupportTankDTO tankDTO,
BindingResult bindingResult,
Model model){
if(bindingResult.hasErrors()){
model.addAttribute("errors", bindingResult.getAllErrors());
return "tank-edit";
}
if(id == null || id <= 0){
tankService.addTank(tankDTO);
} else {
tankService.updateTank(tankDTO);
}
return "redirect:/tank";
}
@PostMapping("/delete/{id}")
public String deleteTank(@PathVariable Long id){
tankService.deleteTank(id);
return "redirect:/tank";
}
}

View File

@ -0,0 +1,103 @@
package premium_store.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Entity
@Table(name = "GAMECLIENTS")
public class GameClient {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "nickName", nullable = false, length = 255)
private String nickName;
@Column(name = "email", nullable = false, length = 255)
private String email;
@Column(name = "balance")
private Integer balance;
@ManyToMany(fetch = FetchType.EAGER)
private List<Tank> tanks = new ArrayList<>();
public GameClient(){ }
public GameClient(String nickName, String email, Integer balance){
this.nickName = nickName;
this.email = email;
this.balance = balance;
}
public Long getId(){
return id;
}
public String getNickName(){
return nickName;
}
public void setNickName(String nickName){
this.nickName = nickName;
}
public String getEmail(){
return email;
}
public void setEmail(String email){
this.email = email;
}
public Integer getBalance(){
return balance;
}
public void setBalance(Integer balance){
this.balance = balance;
}
public List<Tank> getTanks(){
return tanks;
}
public void setTanks(Tank tank){
this.tanks.add(tank);
}
//метод для сравнения
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
GameClient gameClient = (GameClient) o;
return Objects.equals(id, gameClient.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
//преобразование данных по объекту в строчку
@Override
public String toString() {
return "Client{" +
"id=" + id +
", nickName='" + nickName + '\'' +
", email='" + email + '\'' +
", balance='" + balance + '\'' +
", tanks='" + tanks.stream().map(Object::toString).collect(Collectors.joining(", ")) + '\'' +
'}';
}
}

View File

@ -0,0 +1,78 @@
package premium_store.model;
import javax.persistence.*;
import java.util.*;
import java.util.stream.Collectors;
@Entity
@Table(name = "NATIONS")
public class Nation {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "nation")
private String nation;
@OneToMany(mappedBy = "nation", fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
private List<Tank> tanksOfThisNation = new ArrayList<>();
public Nation() {
}
public Nation(String nation) {
this.nation = nation;
}
//возвращает id
public Long getId() {
return id;
}
//возвращает нацию
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public List<Tank> getTanksOfThisNation(){
return tanksOfThisNation;
}
public void setTanksOfThisNation(Tank newTank){
this.tanksOfThisNation.add(newTank);
}
//метод для сравнения
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Nation nation = (Nation) o;
return Objects.equals(id, nation.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
//преобразование данных по объекту в строчку
@Override
public String toString() {
return "Nation{" +
"id=" + id +
", nation='" + nation + '\'' +
", tanksOfThisNation='" + tanksOfThisNation.stream().map(Object::toString).collect(Collectors.joining(", ")) + '\'' +
'}';
}
}

View File

@ -0,0 +1,101 @@
package premium_store.model;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "TANKS")
public class Tank {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "nation")
private Nation nation;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "tankLevel")
private TankLevel tankLevel;
@Column(nullable = false)
private int cost;
public Tank() {
}
public Tank(String name, Nation nation, TankLevel tankLevel, int cost) {
this.name = name;
this.nation = nation;
this.tankLevel = tankLevel;
this.cost = cost;
}
public Long getId(){
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public TankLevel getLevel() {
return tankLevel;
}
public void setLevel(TankLevel tankLevel) {
this.tankLevel = tankLevel;
}
public Nation getNation() {
return nation;
}
public void setNation(Nation nation) {
this.nation = nation;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tank tank)) return false;
return Objects.equals(getId(), tank.getId()) && Objects.equals(getName(), tank.getName())
&& Objects.equals(getCost(), tank.getCost())
&& Objects.equals(getLevel(), tank.getLevel());
}
@Override
public int hashCode() {
return Objects.hash(id);
}
//преобразование данных по объекту в строчку
@Override
public String toString() {
return "Tank{" +
"id=" + id +
", name='" + name + '\'' +
", nation='" + nation.getNation() + '\'' +
", level='" + tankLevel.getLevel() + '\'' +
", cost='" + cost + '\'' +
'}';
}
}

View File

@ -0,0 +1,64 @@
package premium_store.model;
import javax.persistence.*;
import java.util.*;
@Entity
@Table(name = "TANKLEVELS")
public class TankLevel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "level", nullable = false)
private int level;
public TankLevel() {
}
public TankLevel(int level) {
this.level = level;
}
//возвращает id
public Long getId() {
return id;
}
//возвращает нацию
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
//метод для сравнения
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TankLevel tankLevel = (TankLevel) o;
return Objects.equals(id, tankLevel.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
//преобразование данных по объекту в строчку
@Override
public String toString() {
return "Level{" +
"id=" + id +
", level='" + level + '}';
}
}

View File

@ -0,0 +1,7 @@
package premium_store.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import premium_store.model.GameClient;
public interface GameClientRepository extends JpaRepository<GameClient, Long> {
}

View File

@ -0,0 +1,9 @@
package premium_store.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import premium_store.model.Nation;
//класс для взаимодействия с БД вместо низкоуровневого EntityManager
//передаём тип класса и тип id его элементов
public interface NationRepository extends JpaRepository<Nation, Long> {
}

View File

@ -0,0 +1,9 @@
package premium_store.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import premium_store.model.TankLevel;
//класс для взаимодействия с БД вместо низкоуровневого EntityManager
//передаём тип класса и тип id его элементов
public interface TankLevelRepository extends JpaRepository<TankLevel, Long> {
}

View File

@ -0,0 +1,17 @@
package premium_store.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import premium_store.model.Tank;
import java.util.List;
public interface TankRepository extends JpaRepository<Tank, Long> {
@Query("SELECT t FROM Tank t WHERE t.nation.nation = :nation AND t.tankLevel.level BETWEEN :llevelid AND :l2levelid")
List<Tank> checkNationAndLevel(
@Param("nation") String nation,
@Param("llevelid") int levelOne,
@Param("l2levelid") int levelTwo);
}

View File

@ -0,0 +1,109 @@
package premium_store.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import premium_store.controller.DTO.ClientDTO;
import premium_store.controller.DTO.SupportClientDTO;
import premium_store.model.GameClient;
import premium_store.model.Tank;
import premium_store.repository.GameClientRepository;
import premium_store.repository.TankRepository;
import premium_store.service.exception.ClientNotFoundException;
import premium_store.util.validation.ValidatorUtil;
import java.util.List;
import java.util.Optional;
@Service
public class GameClientService {
private final GameClientRepository gameClientRepository;
private final TankRepository tankRepository;
private final ValidatorUtil validatorUtil;
public GameClientService(GameClientRepository gameClientRepository, TankRepository tankRepository, ValidatorUtil validatorUtil){
this.gameClientRepository = gameClientRepository;
this.tankRepository = tankRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public GameClient addClient(String newNickName, String newEmail, Integer newBallance) {
final GameClient gameClient = new GameClient(newNickName, newEmail, newBallance);
validatorUtil.validate(gameClient);
return gameClientRepository.save(gameClient);
}
@Transactional(readOnly = true)
public GameClient findClient(Long id) {
final Optional<GameClient> client = gameClientRepository.findById(id);
return client.orElseThrow(() -> new ClientNotFoundException(id));
}
@Transactional(readOnly = true)
public List<GameClient> findAllClients() {
return gameClientRepository.findAll();
}
@Transactional
public GameClient updateClient(Long id, String newNickName, String newEmail, Integer newBalance, Tank newTank) {
if (id <= 0) {
throw new IllegalArgumentException("Invalid id");
}
final GameClient currentGameClient = findClient(id);
if (StringUtils.hasText(newNickName)){
currentGameClient.setNickName(newNickName);
}
if(StringUtils.hasText(newEmail)){
currentGameClient.setEmail(newEmail);
}
if(newBalance != null){
currentGameClient.setBalance(newBalance);
}
if(newTank != null){
currentGameClient.setTanks(newTank);
}
return gameClientRepository.save(currentGameClient);
}
@Transactional
public GameClient updateClient(SupportClientDTO clientDTO) {
if (clientDTO.getId() <= 0) {
throw new IllegalArgumentException("Invalid id");
}
final GameClient currentGameClient = findClient(clientDTO.getId());
currentGameClient.setNickName(clientDTO.getNickName());
currentGameClient.setEmail(clientDTO.getEmail());
currentGameClient.setBalance(clientDTO.getBalance());
if(clientDTO.getTankId() != null){
currentGameClient.setTanks(tankRepository.getById(clientDTO.getTankId()));
}
return gameClientRepository.save(currentGameClient);
}
@Transactional
public GameClient deleteClient(Long id) {
final GameClient currentGameClient = findClient(id);
gameClientRepository.delete(currentGameClient);
return currentGameClient;
}
//прямой sql-запрос на удаление всех записей в таблице
@Transactional
public void deleteAllClients() {
gameClientRepository.deleteAll();
}
}

View File

@ -0,0 +1,78 @@
package premium_store.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import premium_store.model.Nation;
import premium_store.model.Tank;
import premium_store.repository.NationRepository;
import premium_store.service.exception.NationNotFoundException;
import premium_store.util.validation.ValidatorUtil;
import java.util.List;
import java.util.Optional;
@Service
public class NationService {
private final NationRepository nationRepository;
private final ValidatorUtil validatorUtil;
public NationService(NationRepository nationRepository, ValidatorUtil validatorUtil){
this.nationRepository = nationRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public Nation addNation(String nameNation){
final Nation nation = new Nation(nameNation);
validatorUtil.validate(nation);
return nationRepository.save(nation);
}
//здесь используем Optional - спец. тип данных, позволяющий определять, вернулось ли что-то при вызове метода, или вернулся null
@Transactional(readOnly = true)
public Nation findNation(Long id){
final Optional<Nation> nation = nationRepository.findById(id);
//благодаря Optional можем вызвать orElseThrow, который в случае null сделает проброс кастомного исключения
return nation.orElseThrow(() -> new NationNotFoundException(id));
}
@Transactional(readOnly = true)
public List<Nation> findAllNations() {
return nationRepository.findAll();
}
@Transactional
public Nation updateNation(Long id, String newNation, Tank newTank) {
if(id <= 0){
throw new IllegalArgumentException(String.format("Incorrect id: [%s]", id));
}
final Nation currentNation = findNation(id);
if (StringUtils.hasText(newNation)) {
currentNation.setNation(newNation);
}
if(newTank != null){
currentNation.setTanksOfThisNation(newTank);
}
return nationRepository.save(currentNation);
}
@Transactional
public Nation deleteNation(Long id) {
final Nation currentNation = findNation(id);
nationRepository.delete(currentNation);
return currentNation;
}
@Transactional
public void deleteAllNations() {
nationRepository.deleteAll();
}
}

View File

@ -0,0 +1,68 @@
package premium_store.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import premium_store.model.TankLevel;
import premium_store.repository.TankLevelRepository;
import premium_store.service.exception.LevelNotFoundException;
import premium_store.util.validation.ValidatorUtil;
import java.util.List;
import java.util.Optional;
//сервис после удаления EntityManager и добавления нашего репозитория. То есть у него уже все методы работы с полями прописаны за нас?
@Service
public class TankLevelService {
private final TankLevelRepository tankLevelRepository;
private final ValidatorUtil validatorUtil;
public TankLevelService(TankLevelRepository tankLevelRepository, ValidatorUtil validatorUtil){
this.tankLevelRepository = tankLevelRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public TankLevel addLevel(int newLevel) {
final TankLevel tankLevel = new TankLevel(newLevel);
validatorUtil.validate(tankLevel);
return tankLevelRepository.save(tankLevel);
}
//здесь используем Optional - спец. тип данных, позволяющий определять, вернулось ли что-то при вызове метода, или вернулся null
@Transactional(readOnly = true)
public TankLevel findLevel(Long id) {
final Optional<TankLevel> level = tankLevelRepository.findById(id);
//благодаря Optional можем вызвать orElseThrow, который в случае null сделает проброс кастомного исключения
return level.orElseThrow(() -> new LevelNotFoundException(id));
}
@Transactional(readOnly = true)
public List<TankLevel> findAllLevels() {
return tankLevelRepository.findAll();
}
@Transactional
public TankLevel updateLevel(Long id, int newLevel) {
final TankLevel currentTankLevel = findLevel(id);
currentTankLevel.setLevel(newLevel);
validatorUtil.validate(currentTankLevel);
return tankLevelRepository.save(currentTankLevel);
}
@Transactional
public TankLevel deleteLevel(Long id) {
final TankLevel currentTankLevel = findLevel(id);
tankLevelRepository.delete(currentTankLevel);
return currentTankLevel;
}
@Transactional
public void deleteAllLevels() {
tankLevelRepository.deleteAll();
}
}

View File

@ -0,0 +1,126 @@
package premium_store.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import premium_store.controller.DTO.SupportTankDTO;
import premium_store.controller.DTO.TankDTO;
import premium_store.model.TankLevel;
import premium_store.model.Nation;
import premium_store.model.Tank;
import premium_store.repository.NationRepository;
import premium_store.repository.TankLevelRepository;
import premium_store.repository.TankRepository;
import premium_store.service.exception.TankNotFoundException;
import premium_store.util.validation.ValidatorUtil;
import java.util.List;
import java.util.Optional;
@Service
public class TankService {
private final TankRepository tankRepository;
private final NationRepository nationRepository;
private final TankLevelRepository levelRepository;
private final ValidatorUtil validatorUtil;
public TankService(TankRepository tankRepository, NationRepository nationRepository, TankLevelRepository levelRepository, ValidatorUtil validatorUtil){
this.tankRepository = tankRepository;
this.nationRepository = nationRepository;
this.levelRepository = levelRepository;
this.validatorUtil = validatorUtil;
}
@Transactional
public Tank addTank(String newName, Nation newNation, TankLevel newTankLevel, int newCost) {
final Tank tank = new Tank(newName, newNation, newTankLevel, newCost);
validatorUtil.validate(tank);
return tankRepository.save(tank);
}
@Transactional
public Tank addTank(SupportTankDTO tankDTO) {
final Tank tank = new Tank(tankDTO.getName(), nationRepository.getById(tankDTO.getNationId()),
levelRepository.getById(tankDTO.getLevelId()), tankDTO.getCost());
validatorUtil.validate(tank);
return tankRepository.save(tank);
}
@Transactional(readOnly = true)
public Tank findTank(Long id) {
final Optional<Tank> tank = tankRepository.findById(id);
return tank.orElseThrow(() -> new TankNotFoundException(id));
}
@Transactional(readOnly = true)
public List<Tank> findAllTanks() {
return tankRepository.findAll();
}
@Transactional
public Tank updateTank(Long id, String newName, Nation newNation,
TankLevel newLevel, int newCost) {
if (id <= 0) {
throw new IllegalArgumentException("Invalid id");
}
final Tank currentTank = findTank(id);
if (StringUtils.hasText(newName)){
currentTank.setName(newName);
}
if(newNation != null){
currentTank.setNation(newNation);
}
if(newLevel != null){
currentTank.setLevel(newLevel);
}
if(newCost > 0){
currentTank.setCost(newCost);
}
return tankRepository.save(currentTank);
}
@Transactional
public Tank updateTank(SupportTankDTO tankDTO) {
if (tankDTO.getId() <= 0) {
throw new IllegalArgumentException("Invalid id");
}
final Tank currentTank = findTank(tankDTO.getId());
currentTank.setName(tankDTO.getName());
currentTank.setNation(nationRepository.getById(tankDTO.getNationId()));
currentTank.setLevel(levelRepository.getById(tankDTO.getLevelId()));
currentTank.setCost(tankDTO.getCost());
return tankRepository.save(currentTank);
}
@Transactional
public Tank deleteTank(Long id) {
final Tank currentTank = findTank(id);
tankRepository.delete(currentTank);
return currentTank;
}
//запрос на удаление всех записей в таблице
@Transactional
public void deleteAllTanks() {
tankRepository.deleteAll();
}
@Transactional(readOnly = true)
public List<Tank> findListTank(String nationName, int levelFirst, int levelSecond) {
return tankRepository.checkNationAndLevel(nationName, levelFirst, levelSecond);
}
}

View File

@ -0,0 +1,7 @@
package premium_store.service.exception;
public class ClientNotFoundException extends RuntimeException {
public ClientNotFoundException(Long id) {
super(String.format("Client with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,10 @@
package premium_store.service.exception;
//класс-обработчик ошибки, когда вытаемся вытащить студента из бд по некорректному id
//наследуем от RuntimeException, т. к. он позволяет его проще вызывать
public class LevelNotFoundException extends RuntimeException {
public LevelNotFoundException(Long id) {
super(String.format("Level with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,7 @@
package premium_store.service.exception;
public class NationNotFoundException extends RuntimeException {
public NationNotFoundException(Long id) {
super(String.format("Nation with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,7 @@
package premium_store.service.exception;
public class TankNotFoundException extends RuntimeException {
public TankNotFoundException(Long id) {
super(String.format("Tank with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,51 @@
package premium_store.util.error;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import premium_store.service.exception.ClientNotFoundException;
import premium_store.service.exception.LevelNotFoundException;
import premium_store.service.exception.NationNotFoundException;
import premium_store.service.exception.TankNotFoundException;
import premium_store.util.validation.ValidationException;
import java.util.stream.Collectors;
//контроллер для обработки разнообразных ошибок при работе с запросами к БД
@ControllerAdvice(annotations = RestController.class)
public class AdviceController {
//метод handleException будет вызываться при возникновении исключений типа LevelNotFoundException и т. д.
@ExceptionHandler({
LevelNotFoundException.class,
NationNotFoundException.class,
ClientNotFoundException.class,
TankNotFoundException.class,
ValidationException.class
})
public ResponseEntity<Object> handleException(Throwable e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
//при исключении автоматической валидации данных
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleBindException(MethodArgumentNotValidException e) {
final ValidationException validationException = new ValidationException(
e.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toSet()));
return handleException(validationException);
}
//обработка неизвестных ошибок
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleUnknownException(Throwable e) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View File

@ -0,0 +1,10 @@
package premium_store.util.validation;
import java.util.Set;
//класс для передачи списка ошибок, если они возникают
public class ValidationException extends RuntimeException {
public ValidationException(Set<String> errors) {
super(String.join("\n", errors));
}
}

Some files were not shown because too many files have changed in this diff Show More