Initial commit
This commit is contained in:
281
Java/WebServer/src/main/java/de/craftix/WebServer.java
Normal file
281
Java/WebServer/src/main/java/de/craftix/WebServer.java
Normal file
@@ -0,0 +1,281 @@
|
||||
package de.craftix;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import de.craftix.api.RequestMethod;
|
||||
import de.craftix.api.Route;
|
||||
import de.craftix.api.SetMethod;
|
||||
import de.craftix.api.WebApi;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebServer implements HttpHandler {
|
||||
private static WebServer instance;
|
||||
|
||||
public static void start(int port, File contentRoot, boolean enableApiTester) {
|
||||
instance = new WebServer(port, contentRoot, enableApiTester);
|
||||
}
|
||||
|
||||
public static void addApi(WebApi api) {
|
||||
if (!api.getClass().isAnnotationPresent(Route.class)) throw new IllegalStateException("API does not have a Route");
|
||||
String route = api.getClass().getAnnotation(Route.class).value();
|
||||
|
||||
for (Method m : api.getClass().getMethods()) {
|
||||
if (m.getParameters().length == 0) continue;
|
||||
if (!m.getParameters()[0].getType().equals(HttpExchange.class)) continue;
|
||||
String r = route + (m.isAnnotationPresent(Route.class) ? m.getAnnotation(Route.class).value() : "");
|
||||
instance.apis.put(r, m);
|
||||
instance.apiObjects.put(m, api);
|
||||
}
|
||||
}
|
||||
|
||||
private String contentRoot;
|
||||
private boolean enableApiTester;
|
||||
private File webRoot;
|
||||
|
||||
private final Map<String, Method> apis = new HashMap<>();
|
||||
private final Map<Method, WebApi> apiObjects = new HashMap<>();
|
||||
|
||||
private WebServer(int port, File contentRoot, boolean enableApiTester) {
|
||||
try {
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
|
||||
this.contentRoot = contentRoot.getAbsolutePath();
|
||||
this.enableApiTester = enableApiTester;
|
||||
|
||||
//install typescript converter
|
||||
System.out.println("Creating enviroment...");
|
||||
this.webRoot = new File("webserver");
|
||||
webRoot.delete();
|
||||
webRoot.mkdirs();
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.directory(webRoot);
|
||||
builder.command("cmd.exe", "/c", "npm install typescript");
|
||||
Process p = builder.start();
|
||||
monitorProcess(p);
|
||||
p.waitFor();
|
||||
|
||||
server.createContext("/", this);
|
||||
server.start();
|
||||
System.out.println("HttpServer started successfully on Port: " + server.getAddress().getPort());
|
||||
}catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
String path = exchange.getRequestURI().getPath();
|
||||
if (enableApiTester && path.equalsIgnoreCase("/apitester")) {
|
||||
byte[] response = getApiTester();
|
||||
exchange.sendResponseHeaders(200, response.length);
|
||||
OutputStream out = exchange.getResponseBody();
|
||||
out.write(response);
|
||||
out.close();
|
||||
}
|
||||
if (apis.containsKey(path)) {
|
||||
Method api = apis.get(path);
|
||||
String method = api.isAnnotationPresent(SetMethod.class) ? api.getAnnotation(SetMethod.class).value().toString() : RequestMethod.GET.toString();
|
||||
if (!exchange.getRequestMethod().equals(method)) {
|
||||
byte[] response = enableApiTester ? getApiTester() : getFileContent("/index.html");
|
||||
exchange.sendResponseHeaders(200, response.length);
|
||||
OutputStream out = exchange.getResponseBody();
|
||||
out.write(response);
|
||||
out.close();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
api.invoke(apiObjects.get(api), exchange);
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
} else {
|
||||
byte[] response = getFileContent(path);
|
||||
exchange.sendResponseHeaders(200, response.length);
|
||||
OutputStream out = exchange.getResponseBody();
|
||||
out.write(response);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getFileContent(String fileName) {
|
||||
try {
|
||||
if (fileName.endsWith("/")) return getFileContent(fileName + "index.html");
|
||||
if (fileName.endsWith(".ts")) {
|
||||
String out = webRoot.getAbsolutePath() + getFileName(fileName).replace(".ts", ".js");
|
||||
String src = contentRoot + fileName;
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
builder.directory(webRoot);
|
||||
builder.command("cmd.exe", "/c", "npx tsc", src, "--outFile", out);
|
||||
Process p = builder.start();
|
||||
monitorProcess(p);
|
||||
p.waitFor();
|
||||
System.out.println(out + 1);
|
||||
return readFile(out);
|
||||
}
|
||||
return readFile(fileName);
|
||||
}catch (Exception e) {
|
||||
System.err.println("Client tried to access invalid path: " + fileName);
|
||||
}
|
||||
return enableApiTester ? getApiTester() : getFileContent("/index.html");
|
||||
}
|
||||
|
||||
private byte[] readFile(String fileName) {
|
||||
try {
|
||||
return Files.readAllBytes(new File(contentRoot + fileName).toPath());
|
||||
}catch (Exception e) {
|
||||
System.err.println("Client tried to access invalid path: " + fileName);
|
||||
}
|
||||
return enableApiTester ? getApiTester() : getFileContent("/index.html");
|
||||
}
|
||||
|
||||
private void monitorProcess(Process p) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String str;
|
||||
while ((str = br.readLine()) != null) {
|
||||
System.out.println(str);
|
||||
}
|
||||
}catch (Exception ignored) {}
|
||||
}).start();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
String str;
|
||||
while ((str = br.readLine()) != null) {
|
||||
System.out.println(str);
|
||||
}
|
||||
}catch (Exception ignored) {}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private String getFileName(String path) {
|
||||
path = path.replaceAll("//", "/");
|
||||
String[] dirs = path.split("/");
|
||||
return dirs[dirs.length - 1];
|
||||
}
|
||||
|
||||
public static byte[] getBytesFromStream(InputStream in) {
|
||||
try {
|
||||
if (in == null) throw new NullPointerException("InputStream cannot be null");
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while ((nRead = in.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
|
||||
return buffer.toByteArray();
|
||||
}catch (Exception e) { e.printStackTrace(); }
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public static byte[] getApiTester() {
|
||||
return ("<!DOCTYPE html>\n" +
|
||||
"<html lang=\"en\">\n" +
|
||||
"<head>\n" +
|
||||
" <meta charset=\"UTF-8\">\n" +
|
||||
" <title>Http Request</title>\n" +
|
||||
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3\" crossorigin=\"anonymous\">\n" +
|
||||
" <script src=\"https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js\" integrity=\"sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB\" crossorigin=\"anonymous\"></script>\n" +
|
||||
" <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js\" integrity=\"sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13\" crossorigin=\"anonymous\"></script>\n" +
|
||||
"\n" +
|
||||
" <style>\n" +
|
||||
" .hover:hover {\n" +
|
||||
" cursor: pointer;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" .unselectable {\n" +
|
||||
" -webkit-touch-callout: none;\n" +
|
||||
" -webkit-user-select: none;\n" +
|
||||
" -moz-user-select: none;\n" +
|
||||
" -ms-user-select: none;\n" +
|
||||
" user-select: none;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" #url_start {\n" +
|
||||
" border-top-right-radius: 0;\n" +
|
||||
" border-bottom-right-radius: 0;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" #url {\n" +
|
||||
" border-top-left-radius: 0;\n" +
|
||||
" border-bottom-left-radius: 0;\n" +
|
||||
" }\n" +
|
||||
" </style>\n" +
|
||||
"<body>\n" +
|
||||
"\n" +
|
||||
"<section style=\"margin-top: 20px\" id=\"options\">\n" +
|
||||
" <p class=\"text-center unselectable\" style=\"font-size: 50px\">Send Http Request</p>\n" +
|
||||
"\n" +
|
||||
" <form class=\"container\">\n" +
|
||||
" <div class=\"row\">\n" +
|
||||
" <div class=\"col\">\n" +
|
||||
" <label for=\"url\">URL</label>\n" +
|
||||
" <div class=\"input-group mb-3\">\n" +
|
||||
" <div class=\"input-group-prepend\">\n" +
|
||||
" <span class=\"input-group-text\" id=\"url_start\"></span>\n" +
|
||||
" </div>\n" +
|
||||
" <input type=\"text\" class=\"form-control\" id=\"url\" aria-describedby=\"url_start\">\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" <div class=\"dropdown col col-md-2\">\n" +
|
||||
" <label for=\"method\" class=\"unselectable\">Select Method</label>\n" +
|
||||
" <input class=\"btn btn-secondary dropdown-toggle form-control unselectable\" type=\"button\" id=\"method\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\" value=\"GET\">\n" +
|
||||
" <ul class=\"dropdown-menu\" aria-labelledby=\"method\">\n" +
|
||||
" <li><a class=\"dropdown-item hover unselectable\" id=\"GET\">GET</a></li>\n" +
|
||||
" <li><a class=\"dropdown-item hover unselectable\" id=\"POST\">POST</a></li>\n" +
|
||||
" <li><a class=\"dropdown-item hover unselectable\" id=\"PUT\">PUT</a></li>\n" +
|
||||
" <li><a class=\"dropdown-item hover unselectable\" id=\"DELETE\">DELETE</a></li>\n" +
|
||||
" </ul>\n" +
|
||||
" </div>\n" +
|
||||
" </div>\n" +
|
||||
" <br>\n" +
|
||||
" <div class=\"mb-3\">\n" +
|
||||
" <label class=\"form-check-label unselectable\" for=\"body\">Body</label>\n" +
|
||||
" <textarea id=\"body\" class=\"form-control\" style=\"height: 200px\"></textarea>\n" +
|
||||
" </div>\n" +
|
||||
" <button type=\"button\" class=\"btn btn-primary unselectable\" id=\"send\">Send</button>\n" +
|
||||
" </form>\n" +
|
||||
"</section>\n" +
|
||||
"\n" +
|
||||
"<br><br>\n" +
|
||||
"\n" +
|
||||
"<section id=\"response\" class=\"container\"></section>\n" +
|
||||
"\n" +
|
||||
"<script>\n" +
|
||||
" const url = new URL(window.location.href);\n" +
|
||||
" const startUrl = url.protocol + \"//\" + url.hostname + \":\" + url.port + \"/\";\n" +
|
||||
" document.getElementById(\"url_start\").innerHTML = startUrl;\n" +
|
||||
"\n" +
|
||||
" let method = \"GET\";\n" +
|
||||
"\n" +
|
||||
" const dropdowns = document.getElementsByClassName(\"dropdown-item\");\n" +
|
||||
" for (let i = 0; i < dropdowns.length; i++) {\n" +
|
||||
" const dropdown = dropdowns[i];\n" +
|
||||
" dropdown.onclick = function () {\n" +
|
||||
" method = dropdown.id;\n" +
|
||||
" document.getElementById(\"method\").value = method;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" document.getElementById(\"send\").onclick = function () {\n" +
|
||||
" const url = startUrl + document.getElementById(\"url\").value;\n" +
|
||||
" const body = document.getElementById(\"body\").value;\n" +
|
||||
" const Http = new XMLHttpRequest();\n" +
|
||||
" Http.open(method, url, true);\n" +
|
||||
" Http.onreadystatechange = function () {\n" +
|
||||
" document.getElementById(\"response\").innerHTML = this.responseText;\n" +
|
||||
" }\n" +
|
||||
" Http.send(body);\n" +
|
||||
" }\n" +
|
||||
"</script>\n" +
|
||||
"\n" +
|
||||
"</body>\n" +
|
||||
"</html>").getBytes();
|
||||
}
|
||||
}
|
||||
20
Java/WebServer/src/main/java/de/craftix/api/HttpQuery.java
Normal file
20
Java/WebServer/src/main/java/de/craftix/api/HttpQuery.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package de.craftix.api;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpQuery {
|
||||
private final Map<String, String> variables = new HashMap<>();
|
||||
|
||||
public HttpQuery(HttpExchange exchange) {
|
||||
if (!exchange.getRequestURI().toString().contains("?")) return;
|
||||
String raw = exchange.getRequestURI().getQuery();
|
||||
String[] vars = raw.split("&");
|
||||
for (String var : vars)
|
||||
variables.put(var.split("=")[0].toLowerCase(), var.split("=")[1]);
|
||||
}
|
||||
|
||||
public String getVariable(String name) { return variables.get(name.toLowerCase()) != null ? variables.get(name.toLowerCase()) : ""; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.craftix.api;
|
||||
|
||||
public enum RequestMethod {
|
||||
GET("GET"),
|
||||
POST("POST"),
|
||||
PUT("PUT"),
|
||||
DELETE("DELETE");
|
||||
|
||||
private final String type;
|
||||
|
||||
RequestMethod(String type) { this.type = type; }
|
||||
|
||||
public String getType() { return type; }
|
||||
|
||||
@Override
|
||||
public String toString() { return type; }
|
||||
}
|
||||
12
Java/WebServer/src/main/java/de/craftix/api/Route.java
Normal file
12
Java/WebServer/src/main/java/de/craftix/api/Route.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.craftix.api;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface Route {
|
||||
String value();
|
||||
}
|
||||
12
Java/WebServer/src/main/java/de/craftix/api/SetMethod.java
Normal file
12
Java/WebServer/src/main/java/de/craftix/api/SetMethod.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.craftix.api;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface SetMethod {
|
||||
RequestMethod value() default RequestMethod.GET;
|
||||
}
|
||||
32
Java/WebServer/src/main/java/de/craftix/api/WebApi.java
Normal file
32
Java/WebServer/src/main/java/de/craftix/api/WebApi.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package de.craftix.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.craftix.WebServer;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class WebApi {
|
||||
|
||||
protected void sendDataAsJson(HttpExchange exchange, Serializable data) {
|
||||
if (data instanceof String) sendData(exchange, ((String) data).getBytes());
|
||||
else sendData(exchange, new Gson().toJson(data).getBytes());
|
||||
}
|
||||
|
||||
protected void sendData(HttpExchange exchange, byte[] data) {
|
||||
try {
|
||||
exchange.sendResponseHeaders(200, data.length);
|
||||
OutputStream out = exchange.getResponseBody();
|
||||
out.write(data);
|
||||
out.close();
|
||||
}catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
protected <T> T getDataFromBody(HttpExchange exchange, Type type) {
|
||||
byte[] data = WebServer.getBytesFromStream(exchange.getRequestBody());
|
||||
Gson gson = new Gson();
|
||||
return gson.fromJson(new String(data), type);
|
||||
}
|
||||
}
|
||||
12
Java/WebServer/src/test/java/de/craftix/test/Main.java
Normal file
12
Java/WebServer/src/test/java/de/craftix/test/Main.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.craftix.test;
|
||||
|
||||
import de.craftix.WebServer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
WebServer.start(40, new File("src/test/resources/assets"), true);
|
||||
WebServer.addApi(new TestAPI());
|
||||
}
|
||||
}
|
||||
59
Java/WebServer/src/test/java/de/craftix/test/TestAPI.java
Normal file
59
Java/WebServer/src/test/java/de/craftix/test/TestAPI.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package de.craftix.test;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import de.craftix.WebServer;
|
||||
import de.craftix.api.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Route("/api/test")
|
||||
public class TestAPI extends WebApi {
|
||||
|
||||
public void sendWorkData(HttpExchange exchange) {
|
||||
sendData(exchange, "<h1>Test API works!</h1>".getBytes());
|
||||
}
|
||||
|
||||
@Route("/time")
|
||||
public void getTime(HttpExchange exchange) {
|
||||
sendData(exchange, String.valueOf(System.currentTimeMillis()).getBytes());
|
||||
}
|
||||
|
||||
@Route("/user")
|
||||
public void getUser(HttpExchange exchange) {
|
||||
sendDataAsJson(exchange, new User("Leon", "Hoppe", "leon.hoppe", "admin@leon-hoppe.de"));
|
||||
}
|
||||
|
||||
@Route("/del")
|
||||
@SetMethod(RequestMethod.DELETE)
|
||||
public void delUser(HttpExchange exchange) {
|
||||
sendData(exchange, "user deleted!".getBytes());
|
||||
}
|
||||
|
||||
@Route("/users")
|
||||
public void getUsers(HttpExchange exchange) {
|
||||
HttpQuery query = new HttpQuery(exchange);
|
||||
sendData(exchange, query.getVariable("userId").getBytes());
|
||||
}
|
||||
|
||||
@Route("/add")
|
||||
@SetMethod(RequestMethod.POST)
|
||||
public void addUser(HttpExchange exchange) {
|
||||
String body = new String(WebServer.getBytesFromStream(exchange.getRequestBody()));
|
||||
sendData(exchange, body.getBytes());
|
||||
}
|
||||
|
||||
private static class User implements Serializable {
|
||||
public String firstName;
|
||||
public String lastName;
|
||||
public String username;
|
||||
public String email;
|
||||
|
||||
public User(String firstName, String lastName, String username, String email) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
51
Java/WebServer/src/test/resources/assets/contact.html
Normal file
51
Java/WebServer/src/test/resources/assets/contact.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kontakt</title>
|
||||
<link rel="stylesheet" type="text/css" href="src/css/styles.css">
|
||||
<link rel="stylesheet" type="text/css" href="src/css/contact.css">
|
||||
<link rel="icon" href="src/img/white_small.png">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-dark@3/dark.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9/dist/sweetalert2.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="navigation select">
|
||||
<img src="src/img/white.png" alt="Logo">
|
||||
<nav>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="products.html">Produkte</a>
|
||||
<a href="contact.html">Kontakt</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="contact">
|
||||
<div class="info">
|
||||
<h1 class="select">Meine Kontaktdaten:</h1>
|
||||
<span>
|
||||
E-Mail: admin@leon-hoppe.de<br>
|
||||
Telefon: +49 1575 8839776
|
||||
</span>
|
||||
<img src="src/img/white.png" alt="Logo" class="select">
|
||||
</div>
|
||||
<div class="email">
|
||||
<span class="select">Sende mir eine Nachricht!</span>
|
||||
<input id="user" type="text" placeholder="Name">
|
||||
<input id="email" type="email" placeholder="Deine E-Mail">
|
||||
<textarea id="message" placeholder="Nachricht"></textarea>
|
||||
<input id="submit" type="button" value="Absenden" class="select">
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.getElementById("submit").onclick = function() {
|
||||
Swal.fire('Nachricht gesendet!', '', 'success')
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
51
Java/WebServer/src/test/resources/assets/index.html
Normal file
51
Java/WebServer/src/test/resources/assets/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Startseite</title>
|
||||
<link rel="stylesheet" type="text/css" href="src/css/styles.css">
|
||||
<link rel="stylesheet" type="text/css" href="src/css/index.css">
|
||||
<link rel="icon" href="src/img/white_small.png">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="navigation select">
|
||||
<img src="src/img/white.png" alt="Logo">
|
||||
<nav>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="products.html">Produkte</a>
|
||||
<a href="contact.html">Kontakt</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="select">
|
||||
<h1>Seiten</h1>
|
||||
<div class="buttons">
|
||||
<button class="button" id="https://admin.leon-hoppe.de">Webmin</button>
|
||||
<button class="button" id="https://cloud.leon-hoppe.de">Nextcloud</button>
|
||||
<button class="button" id="https://mail.leon-hoppe.de">Webmail</button>
|
||||
<button class="button load" id="https://panel.leon-hoppe.de">Gameserver Panel</button>
|
||||
<button class="button" id="https://paste.leon-hoppe.de">Paste Server</button>
|
||||
<button class="button" id="https://pma.leon-hoppe.de">PhpMyAdmin</button>
|
||||
<button class="button load" id="https://leon-hoppe.de/test/">HTML Tests</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const buttons = document.getElementsByClassName("button")
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
const button = buttons[i];
|
||||
|
||||
if (button.classList.contains("load")) {
|
||||
button.onclick = function() {
|
||||
location.href = "https://leon-hoppe.de/load.html?href=" + button.id;
|
||||
}
|
||||
}else {
|
||||
button.onclick = function() {
|
||||
location.href = button.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
Java/WebServer/src/test/resources/assets/load.html
Normal file
31
Java/WebServer/src/test/resources/assets/load.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Startseite</title>
|
||||
<link rel="stylesheet" type="text/css" href="src/css/styles.css">
|
||||
<link rel="stylesheet" type="text/css" href="src/css/load.css">
|
||||
<link rel="icon" href="src/img/white_small.png">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="navigation select">
|
||||
<img src="src/img/white.png" alt="Logo">
|
||||
<nav>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="products.html">Produkte</a>
|
||||
<a href="contact.html">Kontakt</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<iframe id="page"></iframe>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const parameters = new URLSearchParams(window.location.search);
|
||||
const href = parameters.get('href');
|
||||
document.getElementById('page').src = href;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
131
Java/WebServer/src/test/resources/assets/products.html
Normal file
131
Java/WebServer/src/test/resources/assets/products.html
Normal file
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Produkte</title>
|
||||
<link rel="stylesheet" type="text/css" href="src/css/styles.css">
|
||||
<link rel="stylesheet" type="text/css" href="src/css/products.css">
|
||||
<link rel="icon" href="src/img/white_small.png">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-dark@3/dark.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@9/dist/sweetalert2.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="navigation select">
|
||||
<img src="src/img/white.png" alt="Logo">
|
||||
<nav>
|
||||
<a href="index.html">Home</a>
|
||||
<a href="products.html">Produkte</a>
|
||||
<a href="contact.html">Kontakt</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="select">
|
||||
<h1 id="title">Webspace Mieten</h1>
|
||||
<div class="packets">
|
||||
<div class="packet" id="packet1">
|
||||
<h1>Basic Paket</h1>
|
||||
<div class="specs-container">
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">512 MB Speicher</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">1 MySQL Datenbank</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Eigene Subdomain</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Unlimited Traffic</span>
|
||||
</div>
|
||||
</div>
|
||||
<input class="buttons" type="button" value="Bestellen">
|
||||
</div>
|
||||
<div class="packet" id="packet2">
|
||||
<h1>Premium Paket</h1>
|
||||
<div class="specs-container">
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">5 GB Speicher</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">10 MySQL Datenbanken</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Eigene Subdomain</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Unlimited Traffic</span>
|
||||
</div>
|
||||
</div>
|
||||
<input class="buttons" type="button" value="Bestellen">
|
||||
</div>
|
||||
<div class="packet" id="packet3">
|
||||
<h1>Enterprise Paket</h1>
|
||||
<div class="specs-container">
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">10 GB Speicher</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">100 MySQL Datenbanken</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Eigene Subdomain</span>
|
||||
</div>
|
||||
<div class="spec">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.95 15.88" class="spec-img">
|
||||
<path fill="none" stroke="#feb600" stroke-linecap="square" stroke-width="3.5" d="M19.47 2.47l-11.68 11-5.32-5"></path>
|
||||
</svg>
|
||||
<span class="spec-info">Unlimited Traffic</span>
|
||||
</div>
|
||||
</div>
|
||||
<input class="buttons" type="button" value="Bestellen">
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const buttons = document.getElementsByClassName("buttons")
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
const button = buttons[i];
|
||||
button.onclick = function() {
|
||||
Swal.fire('Fehler', 'Diese funktion ist noch nicht verfügbar!', 'error')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
98
Java/WebServer/src/test/resources/assets/src/css/contact.css
Normal file
98
Java/WebServer/src/test/resources/assets/src/css/contact.css
Normal file
@@ -0,0 +1,98 @@
|
||||
.contact {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 1200px;
|
||||
height: 600px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.info {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
padding-left: 30px;
|
||||
background-color: #191919;
|
||||
}
|
||||
|
||||
.info h1 {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info span {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.info img {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 70px;
|
||||
width: auto;
|
||||
margin-top: 40px;
|
||||
top: 77%;
|
||||
}
|
||||
|
||||
|
||||
.email {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 700px;
|
||||
height: 600px;
|
||||
left: 500px;
|
||||
background-color: #292929;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.email * { display: block; }
|
||||
|
||||
.email span {
|
||||
font-size: 30px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.email input, textarea {
|
||||
background: none;
|
||||
border: 2px solid #3498db;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.email #user {
|
||||
margin-top: 20px;
|
||||
width: 300px;
|
||||
height: 30px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.email #email {
|
||||
margin-top: 20px;
|
||||
width: 400px;
|
||||
height: 30px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.email #message {
|
||||
margin-top: 20px;
|
||||
width: 600px;
|
||||
height: 300px;
|
||||
font-size: 15px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.email #submit {
|
||||
margin-top: 20px;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
font-size: 18px;
|
||||
transition: 200ms;
|
||||
}
|
||||
|
||||
.email #submit:hover {
|
||||
background-color: #3498db;
|
||||
cursor: pointer;
|
||||
}
|
||||
36
Java/WebServer/src/test/resources/assets/src/css/index.css
Normal file
36
Java/WebServer/src/test/resources/assets/src/css/index.css
Normal file
@@ -0,0 +1,36 @@
|
||||
h1 {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 80px;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 70px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
background: none;
|
||||
border: 2px solid #2ecc71;
|
||||
border-radius: 35px;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
transition-duration: 250ms;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #2ecc71;
|
||||
}
|
||||
13
Java/WebServer/src/test/resources/assets/src/css/load.css
Normal file
13
Java/WebServer/src/test/resources/assets/src/css/load.css
Normal file
@@ -0,0 +1,13 @@
|
||||
main {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
iframe {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#title {
|
||||
text-align: center;
|
||||
font-size: 70px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.packets {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
width: 1600px;
|
||||
height: 600px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.packet {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 500px;
|
||||
height: 550px;
|
||||
background-color: #191919;
|
||||
border: 3px solid #292929;
|
||||
border-radius: 20px;
|
||||
margin: 25px;
|
||||
}
|
||||
|
||||
.packet h1 {
|
||||
text-align: center;
|
||||
transform: translate(0, -50%);
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
.specs-container {
|
||||
position: absolute;
|
||||
width: 370px;
|
||||
left: 50%;
|
||||
top: 25%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.spec {
|
||||
width: 400px;
|
||||
height: 25px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.spec-img {
|
||||
width: auto;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.spec-info {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin-left: 10px;
|
||||
bottom: 25%;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.packet input {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 230px;
|
||||
height: 60px;
|
||||
border: 2px solid #2ecc71;
|
||||
border-radius: 30px;
|
||||
font-size: 30px;
|
||||
transition: 200ms;
|
||||
background: none;
|
||||
color: white;
|
||||
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
transform: translate(-50%, -150%);
|
||||
}
|
||||
|
||||
.packet input:hover {
|
||||
cursor: pointer;
|
||||
background-color: #2ecc71;
|
||||
}
|
||||
91
Java/WebServer/src/test/resources/assets/src/css/styles.css
Normal file
91
Java/WebServer/src/test/resources/assets/src/css/styles.css
Normal file
@@ -0,0 +1,91 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,400;0,700;1,400&display=swap');
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
background-color: #34495e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: dodgerblue;
|
||||
}
|
||||
|
||||
.select {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* === Header === */
|
||||
|
||||
.navigation {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #3498db;
|
||||
}
|
||||
|
||||
.navigation img {
|
||||
position: relative;
|
||||
width: auto;
|
||||
height: 40px;
|
||||
top: 5px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.navigation nav {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
left: 100%;
|
||||
transform: translate(-200%, -50%);
|
||||
}
|
||||
|
||||
.navigation a {
|
||||
position: relative;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
margin: 5px;
|
||||
text-decoration: none;
|
||||
transition: 200ms;
|
||||
}
|
||||
|
||||
.navigation a:hover {
|
||||
cursor: pointer;
|
||||
color: #2ecc71;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* === Main === */
|
||||
|
||||
main {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 50px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* === Alert === */
|
||||
.swal2-popup {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
BIN
Java/WebServer/src/test/resources/assets/src/img/white.png
Normal file
BIN
Java/WebServer/src/test/resources/assets/src/img/white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
Java/WebServer/src/test/resources/assets/src/img/white_small.png
Normal file
BIN
Java/WebServer/src/test/resources/assets/src/img/white_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
13
Java/WebServer/src/test/resources/assets/test.html
Normal file
13
Java/WebServer/src/test/resources/assets/test.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="button" value="Submit" id="submit">
|
||||
<br>
|
||||
<section id="body"></section>
|
||||
</body>
|
||||
<script type="text/javascript" src="test.ts"></script>
|
||||
</html>
|
||||
Reference in New Issue
Block a user