Last active
November 24, 2025 19:02
-
-
Save sunmeat/91a69bfb92c69a4b3753f45e7ceb05a5 to your computer and use it in GitHub Desktop.
spring boot + php mysql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| WebController.java: | |
| package site.sunmeat.hibernate; | |
| import org.springframework.http.MediaType; | |
| import org.springframework.stereotype.Controller; | |
| import org.springframework.web.bind.annotation.*; | |
| import org.springframework.web.reactive.function.client.WebClient; | |
| import reactor.core.publisher.Mono; | |
| import java.util.List; | |
| import java.util.Map; | |
| @Controller | |
| public class WebController { | |
| private final WebClient webClient; | |
| private static final String ADD_CITIES_URL = "http://sunmeat.atwebpages.com/dotnet/upload.php"; | |
| private static final String GET_CITIES_URL = "http://sunmeat.atwebpages.com/dotnet/get_cities.php"; | |
| public WebController(WebClient.Builder webClientBuilder) { | |
| this.webClient = webClientBuilder.build(); | |
| } | |
| @GetMapping("/") | |
| public String index() { | |
| return "index"; | |
| } | |
| @PostMapping("/api/add-city") | |
| @ResponseBody | |
| public Mono<Map<String, String>> addCity(@RequestParam("city") String city) { | |
| return webClient.post() | |
| .uri(ADD_CITIES_URL) | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .bodyValue(List.of(city)) | |
| .retrieve() | |
| .bodyToMono(String.class) | |
| .map(response -> Map.of( | |
| "title", "Додано!", | |
| "content", "Місто «" + city + "» успішно додано в базу!" | |
| )) | |
| .onErrorReturn(Map.of( | |
| "title", "Помилка", | |
| "content", "Не вдалося додати місто" | |
| )); | |
| } | |
| @GetMapping("/api/get-cities") | |
| @ResponseBody | |
| public Mono<Map<String, String>> getCities() { | |
| return webClient.get() | |
| .uri(GET_CITIES_URL) | |
| .retrieve() | |
| .bodyToMono(String.class) | |
| .map(this::decodeUnicode) // переклад \u5434 в кирилицю нормальну | |
| .map(decoded -> { | |
| String list = decoded | |
| .replaceAll("[\\[\\]\"]", "") | |
| .replace(",", "\n") | |
| .trim(); | |
| int count = list.isEmpty() ? 0 : list.split("\n").length; | |
| return Map.of( | |
| "title", "Міста з бази (" + count + ")", | |
| "content", list.isEmpty() ? "База порожня" : list | |
| ); | |
| }) | |
| .onErrorReturn(Map.of("title", "Помилка", "content", "Сервер не відповів")); | |
| } | |
| // розкодування \u041e\u0434\u0435\u0441\u0430 в "Одеса" | |
| private String decodeUnicode(String input) { | |
| if (input == null) return ""; | |
| StringBuilder result = new StringBuilder(); | |
| int i = 0; | |
| while (i < input.length()) { | |
| char c = input.charAt(i); | |
| if (c == '\\' && i + 5 < input.length() && input.charAt(i + 1) == 'u') { | |
| String hex = input.substring(i + 2, i + 6); | |
| try { | |
| int code = Integer.parseInt(hex, 16); | |
| result.append((char) code); | |
| i += 6; | |
| } catch (NumberFormatException e) { | |
| result.append(c); | |
| i++; | |
| } | |
| } else { | |
| result.append(c); | |
| i++; | |
| } | |
| } | |
| return result.toString(); | |
| } | |
| } | |
| ================================================================================================================== | |
| index.html: | |
| <!DOCTYPE html> | |
| <html lang="uk" xmlns:th="http://www.thymeleaf.org"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Міста</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Playfair+Display:wght@700;900&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" th:href="@{style.css}"> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="add-form"> | |
| <input type="text" id="cityInput" placeholder="Введіть місто (наприклад: Харків)" autocomplete="off"> | |
| <button onclick="addCity()">Додати місто</button> | |
| </div> | |
| <div class="buttons"> | |
| <button onclick="loadData('/api/get-cities')">Показати всі міста з бази</button> | |
| </div> | |
| <div id="result" class="result-card"> | |
| <div class="title" id="resultTitle">Введіть місто та додайте його</div> | |
| <div id="resultContent"></div> | |
| </div> | |
| </div> | |
| <script> | |
| document.querySelectorAll('button').forEach(btn => { | |
| btn.addEventListener('mousemove', e => { | |
| const rect = btn.getBoundingClientRect(); | |
| const x = ((e.clientX - rect.left) / rect.width) * 100 + '%'; | |
| const y = ((e.clientY - rect.top) / rect.height) * 100 + '%'; | |
| btn.style.setProperty('--x', x); | |
| btn.style.setProperty('--y', y); | |
| }); | |
| }); | |
| async function addCity() { | |
| const input = document.getElementById('cityInput'); | |
| const city = input.value.trim(); | |
| if (!city) return showResult("Помилка", "Введіть назву міста!"); | |
| showResult("Відправка...", "Чекайте..."); | |
| const formData = new FormData(); | |
| formData.append('city', city); | |
| try { | |
| const res = await fetch('/api/add-city', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await res.json(); | |
| showResult(data.title, `<pre>${data.content}</pre>`); | |
| input.value = ''; | |
| } catch (err) { | |
| showResult("Помилка", err.message); | |
| } | |
| } | |
| async function loadData(url) { | |
| showResult("Завантаження...", ""); | |
| try { | |
| const res = await fetch(url); | |
| const data = await res.json(); | |
| showResult(data.title, `<pre>${data.content}</pre>`); | |
| } catch (err) { | |
| showResult("Помилка", err.message); | |
| } | |
| } | |
| function showResult(title, content) { | |
| document.getElementById('resultTitle').textContent = title; | |
| document.getElementById('resultContent').innerHTML = content; | |
| document.getElementById('result').style.display = 'block'; | |
| } | |
| document.getElementById('cityInput').addEventListener('keypress', e => { | |
| if (e.key === 'Enter') addCity(); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |
| ================================================================================================================== | |
| style.css: | |
| @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&family=Playfair+Display:wght@700;900&display=swap'); | |
| :root { | |
| --bg: #0F0A05; | |
| --surface: #3D2B1F; | |
| --coffee: #6F4E37; | |
| --coffee-dark: #5D4037; | |
| --gold: #D4AF37; | |
| --gold-light: #E8C56A; | |
| --cream: #D7CCC8; | |
| --text: #EFEBE9; | |
| --shadow: 0 12px 32px rgba(0,0,0,0.45); | |
| --transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); | |
| } | |
| *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} | |
| html{scroll-behavior:smooth} | |
| body{ | |
| font-family:'Cormorant Garamond',serif; | |
| background:var(--bg); | |
| color:var(--text); | |
| min-height:100vh; | |
| padding:60px 20px; | |
| line-height:1.8; | |
| background:linear-gradient(to bottom,#0F0A05,#1A120B) | |
| } | |
| h1{ | |
| font-family:'Playfair Display',serif; | |
| font-size:clamp(3rem,9vw,6.5rem); | |
| text-align:center; | |
| color:var(--gold); | |
| margin:80px 0 100px; | |
| letter-spacing:2px; | |
| text-shadow:0 4px 12px rgba(0,0,0,0.6); | |
| position:relative | |
| } | |
| h1::after{ | |
| content:''; | |
| position:absolute; | |
| left:50%;bottom:-30px; | |
| transform:translateX(-50%); | |
| width:220px; | |
| height:4px; | |
| background:linear-gradient(90deg,transparent,var(--gold),var(--gold-light),var(--gold),transparent); | |
| border-radius:2px; | |
| box-shadow:0 0 12px rgba(212,175,55,0.6) | |
| } | |
| .container{max-width:1360px;margin:0 auto;padding:0 20px} | |
| .buttons{ | |
| display:grid; | |
| grid-template-columns:repeat(auto-fit,minmax(340px,1fr)); | |
| gap:40px; | |
| margin:80px 0 | |
| } | |
| button{ | |
| position:relative; | |
| background:var(--coffee); | |
| color:var(--cream); | |
| border:none; | |
| padding:38px 24px; | |
| font-family:inherit; | |
| font-size:1.58em; | |
| font-weight:600; | |
| letter-spacing:2.5px; | |
| text-transform:uppercase; | |
| border-radius:18px; | |
| cursor:pointer; | |
| overflow:hidden; | |
| box-shadow:var(--shadow); | |
| transition:var(--transition); | |
| transform:translateZ(0); | |
| will-change:transform | |
| } | |
| button::before{ | |
| content:''; | |
| position:absolute; | |
| inset:0; | |
| background:radial-gradient(circle at var(--x,50%) var(--y,50%), | |
| rgba(212,175,55,0.35) 0%, | |
| rgba(212,175,55,0.15) 40%, | |
| transparent 70%); | |
| opacity:0; | |
| transition:opacity .5s cubic-bezier(0.4,0,0.2,1); | |
| pointer-events:none | |
| } | |
| button:hover::before{ | |
| opacity:1 | |
| } | |
| button:hover{ | |
| transform:translateY(-12px); | |
| box-shadow:0 24px 60px rgba(0,0,0,0.6); | |
| background:var(--coffee-dark) | |
| } | |
| button:active{ | |
| transform:translateY(-6px) | |
| } | |
| .result-card{ | |
| background:var(--surface); | |
| border-radius:22px; | |
| padding:56px; | |
| margin:60px auto; | |
| max-width:1200px; | |
| box-shadow:var(--shadow); | |
| border:1px solid rgba(212,175,55,0.18); | |
| display:none; | |
| animation:fadeIn .9s ease-out | |
| } | |
| @keyframes fadeIn{ | |
| from{opacity:0;transform:translateY(40px)} | |
| to{opacity:1;transform:none} | |
| } | |
| .title{ | |
| font-family:'Playfair Display',serif; | |
| font-size:2.9em; | |
| text-align:center; | |
| color:var(--gold); | |
| margin-bottom:44px; | |
| letter-spacing:2px; | |
| position:relative | |
| } | |
| .title::after{ | |
| content:''; | |
| position:absolute; | |
| left:50%;bottom:-22px; | |
| transform:translateX(-50%); | |
| width:140px; | |
| height:3px; | |
| background:linear-gradient(90deg,transparent,var(--gold),var(--gold-light),var(--gold),transparent); | |
| border-radius:2px; | |
| box-shadow:0 0 10px rgba(212,175,55,0.5) | |
| } | |
| pre{ | |
| background:rgba(15,10,5,0.8); | |
| color:var(--cream); | |
| padding:36px; | |
| border-radius:16px; | |
| font-family:'Courier New',monospace; | |
| font-size:1.12em; | |
| line-height:1.9; | |
| border:1px solid rgba(212,175,55,0.22); | |
| overflow-x:auto; | |
| box-shadow:inset 0 8px 24px rgba(0,0,0,0.5) | |
| } | |
| img{ | |
| max-width:100%; | |
| border-radius:16px; | |
| border:6px double var(--gold); | |
| box-shadow:0 20px 50px rgba(0,0,0,0.65); | |
| display:block; | |
| margin:36px auto; | |
| transition:transform .7s ease | |
| } | |
| img:hover{ | |
| transform:scale(1.03) | |
| } | |
| @media (max-width:768px){ | |
| .buttons{grid-template-columns:1fr;gap:32px} | |
| button{padding:32px 20px;font-size:1.45em} | |
| h1{margin:60px 0 80px} | |
| .result-card{padding:40px} | |
| } | |
| .add-form{ | |
| display:flex; | |
| gap:20px; | |
| margin:80px auto; | |
| max-width:800px; | |
| justify-content:center; | |
| flex-wrap:wrap | |
| } | |
| #cityInput{ | |
| padding:20px 28px; | |
| font-size:1.4em; | |
| font-family:inherit; | |
| background:var(--surface); | |
| color:var(--cream); | |
| border:2px solid rgba(212,175,55,0.3); | |
| border-radius:16px; | |
| width:100%; | |
| max-width:500px; | |
| box-shadow:var(--shadow); | |
| transition:var(--transition) | |
| } | |
| #cityInput:focus{ | |
| outline:none; | |
| border-color:var(--gold); | |
| box-shadow:0 0 30px rgba(212,175,55,0.4) | |
| } | |
| .add-form{ | |
| display:flex;gap:24px;margin:80px auto;max-width:900px;justify-content:center;flex-wrap:wrap | |
| } | |
| #cityInput{ | |
| padding:20px 28px;font-size:1.4em;font-family:inherit;background:var(--surface); | |
| color:var(--cream);border:2px solid rgba(212,175,55,0.3);border-radius:16px;width:100%;max-width:520px; | |
| box-shadow:var(--shadow);transition:var(--transition) | |
| } | |
| #cityInput:focus{ | |
| outline:none;border-color:var(--gold);box-shadow:0 0 30px rgba(212,175,55,0.4) | |
| } | |
| ================================================================================================================== | |
| db_connect.php: | |
| <?php | |
| define('HOST', 'fdbXXXX.awardspace.net'); | |
| define('USER', '411YYYY_yourDBlogin'); | |
| define('PASS', '******************'); | |
| define('DB', '411YYYY_yourDBname'); | |
| $con = mysqli_connect(HOST,USER,PASS,DB) or die('unable to connect to db'); | |
| ?> | |
| ================================================================================================================== | |
| upload.php: | |
| <?php | |
| // підключення до бази даних | |
| require_once('db_connect.php'); | |
| // отримуємо дані POST (JSON) | |
| $data = file_get_contents('php://input'); | |
| // декодуємо JSON | |
| $cities = json_decode($data, true); | |
| // перевіряємо, що це масив | |
| if (is_array($cities)) { | |
| foreach ($cities as $city) { | |
| // додаємо кожне місто до бази даних | |
| $name = mysqli_real_escape_string($con, $city); | |
| $sql = "INSERT INTO City (name) VALUES ('$name')"; | |
| if (!mysqli_query($con, $sql)) { | |
| echo "Помилка при додаванні міста: " . mysqli_error($con); | |
| exit; | |
| } | |
| } | |
| echo "Міста успішно додано!"; | |
| } else { | |
| echo "Помилка: Неправильний формат даних."; | |
| } | |
| mysqli_close($con); | |
| ?> | |
| ================================================================================================================== | |
| get_cities.php: | |
| <?php | |
| // підключення до бази даних | |
| require_once('db_connect.php'); | |
| // зчитуємо всі міста з бази даних | |
| $result = mysqli_query($con, "SELECT name FROM City"); | |
| $cityList = []; | |
| while ($row = mysqli_fetch_assoc($result)) { | |
| $cityList[] = $row['name']; // додаємо міста до масиву | |
| } | |
| // відправляємо назад список всіх міст як JSON | |
| echo json_encode($cityList); | |
| mysqli_close($con); | |
| ?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment