Was ich beim Erstellen eines Servers in Java gelernt habe

Der Text beginnt mit [hier](# Text). Überspringen Sie ihn daher, es sei denn, Sie sind Mitglied des ONCT ICT Committee.

Entschuldigen Sie, aber ich bin immer noch nicht mit Servern und Netzwerken vertraut. ~~ (Studie) ~~ Ich bin nicht damit vertraut. Bitte weisen Sie Fachleute darauf hin.

Beiseite

Warum ich diesen Artikel geschrieben habe

・ Ich wurde gebeten, einen Artikel über genau den gleichen Inhalt zu schreiben ・ Ich konnte meinen Junioren in den langen Ferienstunden in den Vorlesungen nicht so viel beibringen. ・ Vom Vorsitzenden empfohlen Von. Besonders in der Abteilung habe ich nicht viele Erfolge und ich habe nicht viel Ausbildung, deshalb dachte ich, ich müsste hier ein wenig arbeiten.

In der IKT, insbesondere mit dem Wort "Fragen Sie meine Senioren", musste ich plötzlich einen SNS-Server aufbauen (ohne die IP-Adresse zu kennen, geschweige denn AWS), und ich hielt es für notwendig, Wissen auszutauschen. (Es tut mir leid, wenn Sie nicht wissen, dass es geteilt wird)

Danach möchte ich Java noch weiter verbreiten, also hoffe ich, dass Sie es auf Ihrem ersten Server verwenden.

Ich bin fast Autodidakt und kann keine grundlegenden, theoretischen oder systematischen Kenntnisse vermitteln, aber zumindest möchte ich Ihnen genug Code zeigen können, um ein einfaches SNS und DCG auszuführen.

Um ehrlich zu sein, sind weder das Design noch der Code nützlich, aber ich hoffe, dass er verwendet werden kann, um aus der Situation herauszukommen, in der Anfänger die Begriffe für Google nicht kennen und die Mindestsyntax überhaupt nicht kennen.

Text

Zuerst habe ich es begeistert geschrieben, aber als ich mit dem Schreiben fertig war, konnte ich das Ende nicht sehen und meine Motivation nahm ab, so dass ich es grob schrieb. Beschwerden werden in den Kommentaren akzeptiert. Auch in Bezug auf SQL war es diesmal mühsam, ~~ zu schreiben, also habe ich es weggelassen ~~.

Bevor Sie mit dem Einrichten beginnen

Was sollen wir überhaupt mit der Serverentwicklung machen?

Schreiben Sie grundsätzlich ein Programm, das eine Zeichenfolge vom Client empfängt (Betriebsseite (HTML, Android-Anwendung usw.)) und das Verarbeitungsergebnis als Zeichenfolge zurückgibt.

Ich habe nur Java-Programme für Konsolen geschrieben?

Es gibt eine API für die Serverentwicklung namens JavaEE. Wenn Sie einen Webcontainer wie Tomcat verwenden, können Sie ihn veröffentlichen und mit anderen Programmen (oder Computern) interagieren.

Ich habe gehört, dass es verschiedene Kommunikationsmethoden gibt

Dieses Mal werde ich über HTTP und WebSocket (WS) erklären. HTTP gibt grundsätzlich die Verarbeitung zurück, wenn eine Nachricht empfangen wird. (Kommunikation ist unterbrochen) WS behält die Verbindung bei, sobald die Verbindung hergestellt ist, und sendet Nachrichten aneinander. (Kommunikation wird nicht unterbrochen)

Was für ein Programm haben Sie speziell geschrieben?

Die zwei Projekte, die ich erlebt habe, sind wie folgt.

SNS (HTTP-Server)

-Wenn Sie die Post-Taste auf dem Client (Android-App) drücken, wird der Inhalt (ID, Post-Inhalt, Standortinformationen usw.) an den Server gesendet. Speichern Sie ihn daher in SQL. -Wenn Sie die Lesetaste auf dem Client drücken, wird eine Nachricht gesendet, die das Lesen anzeigt. -Der Server liest den Beitrag, der vom Benutzer aus SQL angezeigt werden kann, und sendet ihn zurück.

DCG (WebSocket Server)

-Wenn der Client gestartet wird, stellt er zuerst eine Verbindung zum Server her.

Umgebungseinstellung

Erstens ist die Umgebung wie folgt.

Software(Eine solche)
Entwicklungssprache Java (8 empfohlen)
Servlet-API JavaEE
IDE IntelliJ Community
Webcontainer Tomcat
Werkzeug erstellen Gradle

Ich habe über diese Setups in einem separaten Artikel geschrieben. Bitte fliegen Sie dorthin. (Es tut mir Leid)

Erstellen Sie eine Programmdatei

Klicken Sie mit der rechten Maustaste auf src-> main-> java und klicken Sie auf Neu-> Paket, um das Paket zu erstellen. Klicken Sie dann mit der rechten Maustaste auf den unteren Rand des Pakets und wählen Sie Neu-> Java-Datei, um eine Java-Datei zu erstellen.

Versuch es

Wie im Artikel "Einstellungen" erwähnt, verfügt die IntelliJ-Community nicht über Funktionen zum Serverstart. Daher ersetzen wir die Ausführung durch Gradles Aufgabe. Klicken Sie ganz rechts auf dem Bildschirm auf Gradle, um eine Liste der Aufgaben anzuzeigen. Ich denke, es gibt einen Gegenstand namens Tomcat Run in gretty. Sie können den Server starten, indem Sie darauf doppelklicken.

org.apache.catalina.LifecycleException: Protocol handler initialization failed
	at org.apache.catalina.connector.Connector.initInternal(Connector.java:935)
	at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
	at org.apache.catalina.core.StandardService.initInternal(StandardService.java:530)
	at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
	at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:852)
	at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:136)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:173)
	at org.apache.catalina.startup.Tomcat.start(Tomcat.java:371)
	at org.apache.catalina.startup.Tomcat$start$0.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at org.akhikhl.gretty.TomcatServerManager.startServer(TomcatServerManager.groovy:49)
	at org.akhikhl.gretty.ServerManager$startServer$0.call(Unknown Source)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
	at org.akhikhl.gretty.Runner.run(Runner.groovy:117)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:71)
	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
	at org.akhikhl.gretty.Runner.main(Runner.groovy:44)
Caused by: java.net.BindException: Address already in use: bind
	at sun.nio.ch.Net.bind0(Native Method)
	at sun.nio.ch.Net.bind(Net.java:433)
	at sun.nio.ch.Net.bind(Net.java:425)
	at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
	at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
	at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:227)
	at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:202)
	at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:1043)
	at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:540)
	at org.apache.coyote.http11.AbstractHttp11Protocol.init(AbstractHttp11Protocol.java:74)
	at org.apache.catalina.connector.Connector.initInternal(Connector.java:932)
	... 27 more

http://localhost:8080/ Und lassen Sie uns hier zugreifen スクリーンショット (75).png Wenn Not Found so angezeigt wird, ist dies erfolgreich. Ich habe noch keine Programme geschrieben, daher ist das natürlich. Übrigens, wenn Sie es nicht ausführen, wird ein Fehler beim Laden der Seite usw. angezeigt.

Erstellen Sie zunächst ein HTTP-Servlet

Ein Servlet ist wie das Hauptprogramm eines Servers (entsprechend) Hier werden wir HTTP vor WS vorstellen.

Es gibt eine Methode in HTTP, die je nach Kommunikationsinhalt ordnungsgemäß verwendet wird. Hier wird jedoch nur GET zur Vereinfachung verwendet. (Es tut uns leid) GET ist eine Methode, die Ressourcen usw. vom Server anfordert. Dies geschieht in Form der Weitergabe von Verarbeitung und Daten mithilfe von URLs und Parametern sowie des Empfangs von Ausführungsergebnissen.

Lassen Sie uns zuerst ein Servlet-Programm mit HttpServlet.java erstellen. (Klassenname ist kostenlos)

In Tomcat empfiehlt es sich, eine Einstellungsdatei mit dem Namen web.xml zu schreiben. Es scheint jedoch, dass stattdessen Anmerkungen verwendet werden können. Diesmal werde ich dies tun.

Der Inhalt wird im folgenden Code angezeigt.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.annotation.WebServlet;

//Verpflichtend
//Übergeben Sie den Servlet-Namen im Namen und eine Liste der URLs, die auf urlPatterns treffen.
//Sie können auch einen Platzhalter angeben.
@WebServlet(
        name = "HttpServlet",
        urlPatterns = {"/*"})
@MultipartConfig (
	     fileSizeThreshold= 32768 ,
	     maxFileSize= 5242880 ,
	     maxRequestSize= 27262976
	 )
// javax.servlet.http.Kann durch Erben von HttpServlet als Servlet verwendet werden
public class HttpServlet extends javax.servlet.http.HttpServlet {

	//Die Methode, die aufgerufen wird, wenn die doGet-Methode eine GET-Anforderung empfängt
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response){
		PrintWriter out = null;
		try {
			//Dieser Bereich ist vorerst magisch.
			//Zeichencode und so weiter
			response.setContentType("text/html; charset=UTF-8");
	        response.setHeader("Access-Control-Allow-Origin", "*");
			request.setCharacterEncoding("utf-8");

			//Durch das Abrufen von PrintWiter, System.out.println()Sie können eine solche Zeichenfolge zurückgeben.
			out = response.getWriter();

			// request.getServletPath();Erhält den unten eingegebenen Pfad aus dem Stammverzeichnis dieses Projekts.
			//Verzweigen Sie diesmal entsprechend mit einem Schalter.
			String path = request.getServletPath();
			String str = null;
			switch(path){
				case "/hoge":
				// request.getParameter()Erhalten Sie die Parameter unter.
				// http://localhost:8080/Test/hoge?str=hage&str2=hige
				//URL wie?str=hage&str2=großer Teil
				str = request.getParameter("str");
				break;
				case "/huga":
				str = "huga";
				break;
			}
			//Senden Sie den Inhalt von str zurück.
			out.println(str);
			//Rufen Sie auch Flush richtig auf.
			out.flush();

		} catch (IOException e){
			e.printStackTrace();
		} 
	}


}

Wenn Sie dies tun und auf eine URL wie die folgende klicken, erhalten Sie aaa zurück. [http: // localhost: 8080 / / hoge? Str = aaa](http: // localhost: 8080 / Project / hoge? Str = aaa) Damit wird das auszuführende Programm verzweigt, Daten empfangen und verarbeitet. ~~ Ich habe es benutzt ~~ Es scheint, dass der Anforderungsparameter nur ein Sicherheitsproblem hat, also benutze ihn in der Praxis nicht zu oft. Auch hier habe ich den Prozess direkt in den Fall geschrieben, aber ich denke, es ist besser, ihn in Funktionen zu unterteilen.

Als nächstes schreiben wir ein WebSocket-Servlet

Dieses Mal werde ich ein Servlet schreiben, das WebSocket anstelle von HTTP verwendet. HTTP war eine Methode, die auf die Kommunikation vom (Basis-) Client reagiert (stellt jedes Mal eine neue Verbindung her). WebSocket unterhält die Kommunikation mit dem Client und kommuniziert in beide Richtungen.

package scptcg.server;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;

//Damit wird es zu einem WebSocket-Server
//URL kann ein Platzhalter sein
@ServerEndpoint("/ws")
public final class WSEndPoint {

    // Session(Kommunikation)Karte zum Speichern
    private static Map<String, Session> session = new HashMap<>();

    //Methode beim Verbinden aufgerufen
    @OnOpen
    public void onOpen(final Session client, final EndpointConfig config) {
        String log = client.getId() + " was connected.";
        System.out.println(log);
    }

    //Methode, die beim Trennen aufgerufen wird
    @OnClose
    public void onClose(final Session client, final CloseReason reason) throws IOException {
        String log = client.getId() + " was closed by "
                + reason.getCloseCode() + "[" + reason.getCloseCode().getCode() + "]";
        System.out.println(log);
    }

    //Methode bei Fehler aufgerufen
    @OnError
    public void onError(final Session client, final Throwable error) {
        String log = client.getId() + " was error. [" + error.getMessage() + "]";
        error.printStackTrace();
    }

    //Methode, die aufgerufen wird, wenn eine Nachricht gesendet wird
    @OnMessage
    public void onMessage(final String text, final Session client) throws IOException {
        //Es wird angenommen, dass der Inhalt der Nachricht den Vorgang, die ID und die Daten beschreibt, die durch Zeilenumbrüche getrennt sind.
        String[] t = text.split("\n");
        String event = t[0];
        String id = t[1];
        //Verzweigen Sie für jeden Ereignisinhalt
        switch (event){
            case "login":
                //Speichern Sie die Sitzung in HashMap.
                session.put(id, client);
                //Senden Sie eine Zeichenfolge an die mit id gespeicherte Sitzung.
                session.get(id).getBasicRemote().sendText(id);
                System.out.println(id);
                break;
            case "commit":
                //Übertragung
                for (Session s :session.values()){
                    s.getBasicRemote().sendText(t[2]);
                }
                System.out.println(t[2]);
                break;
            case "close":
                //Aus der Sitzungsliste entfernen
                session.remove(t[1]);
                break;
        }

    }

}

Dies erfolgt in der OnMessage () -Methode. Es scheint, dass es ursprünglich keinen Zweig des Verarbeitungsinhalts gibt, daher denke ich, dass es besser ist, ihn am Anfang des Kommunikationsinhalts zu übergeben. Übrigens, da dies ein Beispiel ist, sind es ~~ verdammte ~~ Daten, die durch Zeilenumbrüche getrennt sind, aber ich benutze normalerweise Gson, um JSON auszutauschen. Anmerkungen wie @OnMessage erkennen die aufgerufene Methode, sodass keine spezielle Klasse geerbt werden muss. ~~ Es ist mühsam, also werde ich auch Gson weglassen.

Ich werde auch den HTML-Code für den Test setzen. Ich habe es jedoch nicht getestet, daher denke ich, dass es besser ist, es selbst zu schreiben.

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Sample</title>
    <script type="text/javascript">
        var uri = "ws://localhost:8080/Project/";

        //WebSocket-Objekt
        var webSocket = null;

        //Erstverarbeitung
        function init() {
            if (webSocket == null) {
                //WebSocket-Initialisierung
                webSocket = new WebSocket(uri);
                //Event-Handler-Einstellungen
                webSocket.onopen = onOpen;
                webSocket.onmessage = onMessage;
                webSocket.onclose = onClose;
                webSocket.onerror = onError;
				webSocket.send("login\n" + document.getElementById('id').innerText);
            }
        }

        function onOpen(event) {
			alert('open');
        }

        //Nachrichtenempfangsereignis
        function onMessage(event) {
            document.getElementById('box').innerText += event;
        }

        //Fehlerereignis
        function onError(event) {
			alert('error');
        }

        //Ereignis trennen
        function onClose(event) {
			alert('close');
            webSocket = null;
        }

		function send(){
			webSocket.send("commit\n" + document.getElementById('txt').innerText);
		}

    </script>
</head>
<body>
	<input type="id" name="name" size="30" maxlength="20" />
	<input type="txt" name="name" size="30" maxlength="20" />
	<hr />
    <input id="box" type="text" data-name="message" size="100" />
	<hr />
	<button id="con" onclick="init()">init</button>
	<button id="send" onclick="send()">send</button>
</body>
</html>

Die URL lautet übrigens [ws: // localhost: 8080 / /](ws: // localhost: 8080 / Project /).

abschließend

Es tut mir leid, dass ich unordentlich geworden bin. Ich werde den SNS- und DCG-Code auf meinen GitHub setzen, also schauen Sie bitte. ~~ (Ich bin überrascht über das Ficken dieses Codes) ~~

Ich habe es ernsthaft geschrieben. Wenn Sie also eine Bitte um Korrektur oder zusätzliche Erklärung haben, sagen Sie es bitte direkt oder auf SNS ~~ und schreiben Sie es in den Kommentar.

Habt alle ein schönes Weihnachtsfest!

Recommended Posts

Was ich beim Erstellen eines Servers in Java gelernt habe
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe (1)
[Anmerkung] Was ich in einem halben Jahr von unerfahrenen (Java) gelernt habe (3)
Was ich in Java gelernt habe (Teil 2) Was sind Variablen?
Ich habe ein PDF mit Java erstellt.
Was ich mit Java Gold gelernt habe
Was ich mit Java Silver gelernt habe
Was ich in Java gelernt habe (Teil 4) Bedingte Verzweigung und Wiederholung
[java] Was ich getan habe, als ich Listen in meiner eigenen Klasse verglichen habe
Was ist eine Klasse in der Java-Sprache (3 /?)
Bei der Suche nach mehreren in einem Java-Array
Was ich in Java gelernt habe (Teil 1) Java-Entwicklungsablauf und Überblick
Über das, was ich beim Erstellen einer CLJ-Datei mit Clojure getan habe
Was ist eine Klasse in der Java-Sprache (1 /?)
Was ist eine Klasse in der Java-Sprache (2 /?)
Was ich gelernt habe
Was ich aus der Java-Geldberechnung gelernt habe
[Rails] Was ich aus einem kleinen Stolperstein bei der Verwendung von Vorfahren gelernt habe
Ich habe ein Programm zur Beurteilung von Primzahlen in Java erstellt
Ein Hinweis, wenn Sie Tupel in Java möchten
Ich wollte (a == 1 && a == 2 && a == 3) in Java wahr machen
Ich habe ein Programm zur Beurteilung von Primzahlen in Java geschrieben
Ich habe ein Janken-Spiel in Java (CLI) gemacht.
Ein kurzer Überblick über Java, das im Unterricht gelernt wurde
Was ich getan habe, als ich Java zu Kotlin konvertiert habe
Ich habe ein Primfaktorisierungsprogramm in Java geschrieben
Zusammenfassung dessen, was ich in Spring Batch gelernt habe
Was mir bei der Verwendung der Schnittstelle einer Funktion mit Standardargumenten in Kotlin aus Java nicht gefällt
Was ich gelernt habe ② ~ Mock ~
Was ich gelernt habe ~ ~ DJUnit ~
Ich habe ein einfaches Berechnungsproblemspiel in Java gemacht
Ein kurzer Überblick über Java, das in Klasse 4 gelernt wurde
Ich habe versucht, eine Clova-Fähigkeit in Java zu erstellen
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Ich habe versucht, Log4j2 auf einem Java EE-Server zu verwenden
Ich habe im Frühjahr einen Restful-Server und -Client erstellt.
Ein kurzer Überblick über Java, das in Klasse 3 gelernt wurde
Ein kurzer Überblick über Java, das in Klasse 2 gelernt wurde
Ich habe versucht herauszufinden, was sich in Java 9 geändert hat
Was ich über Java 8 recherchiert habe
Was ich über Java 6 recherchiert habe
Ich habe ein Roulette in Java gemacht.
Was ich über Java 9 recherchiert habe
Suchen Sie eine Teilmenge in Java
Was ich über Java 7 recherchiert habe
Ich habe versucht, Metaprogrammierung mit Java
Was ich über Kotlin gelernt habe
Was ich über Java 5 recherchiert habe
Aktualisieren Sie Ihre Java-Kenntnisse, indem Sie einen gRPC-Server in Java schreiben (2).
Beheben Sie den CreateProcess-Fehler = 206, wenn Sie Java in einer Windows-Umgebung ausführen
Aktualisieren Sie Ihre Java-Kenntnisse, indem Sie einen gRPC-Server in Java schreiben (1)
Ich wollte nur eine reaktive Eigenschaft in Java erstellen
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben
Ich habe versucht, in Java von einer Zeichenfolge in einen LocalDate-Typ zu konvertieren
Dynamisches Wechseln von JDKs beim Erstellen von Java mit Gradle
Zeigt einen detaillierten Fehler in Logger an, wenn Java auf dem Server ausgeführt wird
Ich habe einen RESAS-API-Client in Java erstellt