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.
・ 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.
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 ~~.
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.
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).
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)
The two projects I have experienced are as follows.
-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.
-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.
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
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.
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 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.
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 /
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 /
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