What I learned when building a server in Java

The text starts with [here](# text), so please skip it unless you are an ONCT ICT committee member.

Excuse me, but I'm still not familiar with servers and networks ~~ (study) ~~ I'm not familiar with it, so I would appreciate it if you could point out to professionals.

Digression

Why i wrote this article

・ I was asked to write an article about exactly the same content ・ I couldn't teach my juniors so much in the lectures during the long vacation hours. ・ Recommended by the chairperson From. Especially in the department, I don't have much achievements and I don't have much education, so I thought I had to do some work here.

In ICT, especially with the word "Ask my seniors", I was forced to build an SNS server suddenly (without even knowing the IP address, let alone AWS), so I thought it was necessary to share knowledge. (I'm sorry if you just don't know it's shared)

After that, I want to spread Java even more, so I hope that you will use it on your first server.

I'm almost self-taught, and I can't teach you basic, theoretical, or systematic knowledge, but at least I'd like to be able to show you enough code to run simple SNS and DCG.

To be honest, neither the design nor the code is useful, but I hope it can be used to get out of the situation where beginners do not know the terms for google and do not know the minimum syntax in the first place.

Text

At first I wrote it enthusiastically, but when I finished writing the digression, I couldn't see the end, and my motivation decreased, so I wrote it roughly. Complaints are accepted in the comments. Also, I omitted SQL this time because it was troublesome to write ~~.

Before you start setting up

What should I do with server development in the first place?

Basically, write a program that receives a character string from the client (operating side (HTML, Android application, etc.)) and returns the processing result as a character string.

I've only written Java programs for consoles?

There is an API for server development called JavaEE. If you use a web container such as Tomcat, you can publish it and interact with other programs (or computers).

I heard that there are various communication methods

This time, I will explain about HTTP and WebSocket (hereinafter referred to as WS). HTTP basically returns processing when a message is received. (Communication is interrupted) WS keeps the connection once connected and sends messages to each other. (Communication is not interrupted)

What kind of program did you write specifically?

The two projects I have experienced are as follows.

SNS (HTTP server)

-When you press the post button on the client (Android application), the content (ID, post content, location information, etc.) will be sent to the server, so save it in SQL. -When you press the read button on the client, a message indicating read is sent. -The server reads the post that the user can view from SQL and sends it back.

DCG (WebSocket server)

-When the client starts, it first connects to the server. -Operations performed by the client are sent to the server one by one. -The server has a game program and operates the game based on the sent data. -When the operation is completed, the processing result is sent to the client, and the client draws based on it.

Environmental setting

First, the environment is as follows.

software(Such)
development language Java (8 recommended)
Servlet API JavaEE
IDE IntelliJ Community
Web container Tomcat
Build tool Gradle

I wrote about these setups in a separate article, so please fly there. (I'm sorry) -Prepare the execution environment of Tomcat in IntelliJ Community

Create a program file

Right-click src-> main-> java and click New-> Package to create the package. Then right-click on the bottom of the package and select New-> Java File to create a .java file.

Try it out

As I mentioned in the Preferences article, the IntelliJ Community doesn't have any server startup related features, so I'll substitute the Gradle task for execution. Click Gradle on the far right of the screen to display a list of tasks. I think there is an item called Tomcat Run in gretty. You can start the server by double-clicking on it.

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/ And let's access here スクリーンショット (75).png If Not Found is displayed like this, it is successful. I haven't written any programs yet, so it's natural. By the way, if you do not execute it, a page load error etc. will be displayed.

First, create an Http Servlet

A Servlet is like the main program of a server (appropriate) Here, we will introduce Http before WS.

There is a method in Http, which is used properly depending on the content of communication, but here only GET is used for simplification. (sorry) GET is a method that requests resources etc. from the server. We will pass the processing and data using the URL and parameters, and receive the execution result.

Let's first create a Servlet program with HttpServlet.java. (Class name is free)

In Tomcat, it is a good practice to write a configuration file called web.xml, but it seems that annotations can be used instead, so this time I will do so.

The contents are shown in the code below.

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;

//Mandatory
//Pass the Servlet name in name and the list of URLs that hit urlPatterns.
//You can also specify a wildcard.
@WebServlet(
        name = "HttpServlet",
        urlPatterns = {"/*"})
@MultipartConfig (
	     fileSizeThreshold= 32768 ,
	     maxFileSize= 5242880 ,
	     maxRequestSize= 27262976
	 )
// javax.servlet.http.Can be used as a Servlet by inheriting HttpServlet
public class HttpServlet extends javax.servlet.http.HttpServlet {

	//Method called when doGet method receives GET request
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response){
		PrintWriter out = null;
		try {
			//This area is magical for the time being.
			//Character code and so on
			response.setContentType("text/html; charset=UTF-8");
	        response.setHeader("Access-Control-Allow-Origin", "*");
			request.setCharacterEncoding("utf-8");

			//By getting PrintWiter, System.out.println()You can return a character string like this.
			out = response.getWriter();

			// request.getServletPath();Receives what path was entered below from the root of this project.
			//This time, branch appropriately with a switch.
			String path = request.getServletPath();
			String str = null;
			switch(path){
				case "/hoge":
				// request.getParameter()Receive the parameter with.
				// http://localhost:8080/Test/hoge?str=hage&str2=hige
				//URL like?str=hage&str2=hige part
				str = request.getParameter("str");
				break;
				case "/huga":
				str = "huga";
				break;
			}
			//Send back the contents of str.
			out.println(str);
			//Also call flush properly.
			out.flush();

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


}

If you do this and step on a URL like the one below, you'll get aaa. [http: // localhost: 8080 / / hoge? Str = aaa](http: // localhost: 8080 / Project / hoge? Str = aaa) Using this, the program to be executed is branched, data is received, and processing is performed. ~~ I used it ~~ Request parameters seem to have only security problems, so don't use them too much in practice. Also, here I wrote the process directly in the case, but I think it is better to separate it into functions as well.

Next, let's write a WebSocket Servlet

This time, I will write a Servlet that uses WebSocket instead of Http. Http was a method that responds to communication from (basic) clients (makes a new connection every time), WebSocket maintains communication with the client and communicates in both directions.

package scptcg.server;

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

//With this it becomes a WebSocket server
//URL can be wildcard
@ServerEndpoint("/ws")
public final class WSEndPoint {

    // Session(communication)Map for saving
    private static Map<String, Session> session = new HashMap<>();

    //Method called when connecting
    @OnOpen
    public void onOpen(final Session client, final EndpointConfig config) {
        String log = client.getId() + " was connected.";
        System.out.println(log);
    }

    //Method called when disconnecting
    @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);
    }

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

    //Method called when a message is sent
    @OnMessage
    public void onMessage(final String text, final Session client) throws IOException {
        //It is assumed that the content of the message describes the operation, id, and data separated by line breaks.
        String[] t = text.split("\n");
        String event = t[0];
        String id = t[1];
        //Branch for each event content
        switch (event){
            case "login":
                //Save Session in HashMap.
                session.put(id, client);
                //Send the string to the session saved by id.
                session.get(id).getBasicRemote().sendText(id);
                System.out.println(id);
                break;
            case "commit":
                //broadcast
                for (Session s :session.values()){
                    s.getBasicRemote().sendText(t[2]);
                }
                System.out.println(t[2]);
                break;
            case "close":
                //Removed from session list
                session.remove(t[1]);
                break;
        }

    }

}

This is done in the OnMessage () method. It seems that there is no branch of the processing content originally, so I think it is better to pass it at the beginning of the communication content. By the way, since this is a sample, it is ~~ shit ~~ data separated by line breaks, but I usually use Gson to exchange JSON. Annotations such as @OnMessage recognize the method being called, so there is no need to inherit a special class. ~~ It's troublesome, so I'll omit Gson as well.

I will also put the HTML for testing. However, I haven't tested it, so I think it's better to write it yourself.

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

        //WebSocket object
        var webSocket = null;

        //Initial processing
        function init() {
            if (webSocket == null) {
                //WebSocket initialization
                webSocket = new WebSocket(uri);
                //Event handler settings
                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');
        }

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

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

        //Disconnect event
        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>

By the way, the URL is [ws: // localhost: 8080 / /](ws: // localhost: 8080 / Project /).

in conclusion

I'm sorry I got messy. I'll put the SNS and DCG code on my GitHub so please take a look. ~~ (I'm surprised at the shit of that code) ~~

I wrote it seriously, so if you have a request for correction or additional explanation, please write it in the comment ~~ directly or on SNS ~~.

Have a nice Christmas everyone!

Recommended Posts

What I learned when building a server in Java
[Note] What I learned in half a year from inexperienced (Java)
[Note] What I learned in half a year from inexperienced (Java) (1)
[Note] What I learned in half a year from inexperienced (Java) (3)
What I learned in Java (Part 2) What are variables?
I created a PDF in Java.
What I learned with Java Gold
What I learned with Java Silver
What I learned in Java (Part 4) Conditional branching and repetition
[java] What I did when comparing Lists in my own class
What is a class in Java language (3 /?)
When seeking multiple in a Java array
What I have learned in Java (Part 1) Java development flow and overview
About what I did when creating a .clj file in Clojure
What is a class in Java language (1 /?)
What is a class in Java language (2 /?)
What i learned
What I learned from Java monetary calculation
[Rails] What I learned from a little stumbling block when using ancestry
I made a primality test program in Java
A note when you want Tuple in Java
I wanted to make (a == 1 && a == 2 && a == 3) true in Java
I wrote a primality test program in Java
I made a rock-paper-scissors game in Java (CLI)
A quick review of Java learned in class
What I did when I converted java to Kotlin
I wrote a prime factorization program in Java
Summary of what I learned in Spring Batch
What I don't like when using interface of a function with default arguments in Kotlin from Java
What I learned ② ~ Mock ~
What I learned ① ~ DJUnit ~
I made a simple calculation problem game in Java
A quick review of Java learned in class part4
I tried to create a Clova skill in Java
I tried to make a login function in Java
I tried using Log4j2 on a Java EE server
I made a Restful server and client in Spring.
A quick review of Java learned in class part3
[Rilas] What I learned in implementing the pagination function.
A quick review of Java learned in class part2
I tried to find out what changed in Java 9
What I researched about Java 8
What I researched about Java 6
I made roulette in Java.
What I researched about Java 9
Find a subset in Java
What I researched about Java 7
I tried metaprogramming in Java
What I learned about Kotlin
What I researched about Java 5
Update your Java knowledge by writing a gRPC server in Java (2)
Implementing a large-scale GraphQL server in Java with Netflix DGS
Resolve CreateProcess error = 206 when running Java in a Windows environment
Update your Java knowledge by writing a gRPC server in Java (1)
I just wanted to make a Reactive Property in Java
What happens when I do new => build => save! In ActiveRecord
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I tried to convert a string to a LocalDate type in Java
How to dynamically switch JDK when building Java in Gradle
Show detailed error in Logger when running Java on server
I tried to make a client of RESAS-API in Java