Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active November 24, 2025 19:02
Show Gist options
  • Select an option

  • Save sunmeat/91a69bfb92c69a4b3753f45e7ceb05a5 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/91a69bfb92c69a4b3753f45e7ceb05a5 to your computer and use it in GitHub Desktop.
spring boot + php mysql
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