java package for writing a server. A simple HTTP server in Java using only the Java SE API


As you probably already know, L2jServer has changed its code update policy and now updates are released approximately once a month, but nevertheless, the code remains open and available to everyone who wants to learn and install Freya.


L2Teon has made almost 150 code adjustments since the release of the last revision of the Lineage 2 Interlude java server. Thanks to this, the security and fault tolerance of the server were increased.
Updated item sharpening protection, fixed spawn list.
Fixed a bug with pets.
Disabled loading AI from the kernel, now only from “\data\scripts\ai\”.
Fixed skills: Curse of Doom, Anchor, Mirage.
Fixed a bug with the warehouse (the FloodProtector data was incorrectly specified).
Fixed a bug with the pet disappearing after death.
Spell Force and Battle Force skills have been fixed.
The possibility of excessive sharpening of objects is closed.
Correction of NPC table entries so that there are no errors in the console.


Java Development The Lineage 2 Gracia Epilogue server or simply Plus continues, and today the next update is available for owners of servers based on L2Open-Team.
Added an option responsible for the chance of raising the level of Soul Crystal.
Fixed the third floor in Steel Citadel, or rather the ability to go to it.
Added mana recovery for Orc Shaman when hit.
Fixed receiving magical support for beginners.
Fixed character invisibility.
Manor seeds from Lineage 2 Gracia Epilogue have been added.
Added new quest Pailaka Injured Dragon (test required).
The engine implements the "Seven Arrow" skill.
Added Events: Last Hero and Base Capture.
The administrator has access to a teleport to all Gracia Raid Bosses.

Once again, an update to the Lineage 2 Epilogue server build from the L2jServer team has been released with revision 4309 for the kernel and 7529 for the datapack.
Fixed display of the action window when performing a transformation.
Possibility to activate caching of all names of existing characters.
Fixed an issue with auto-nipple being disabled on equipped weapons.
Added setting for broadcasting range of events with ships.
A new option is available to enable Champions to spawn on the map.
Implementation of clan airships, correction of the flight path in quests.
Added support for more precise search of double windows.
A Geodvig error that resulted in the display of “Can”t see target” has been fixed.
It is no longer possible to trade in vehicles.
The droplist is checked when the server loads for “left” items.

Last update: 09/20/2018

The Java Bean class must meet a number of restrictions:

    have a constructor that doesn't take any parameters

    define getter and setter methods for all properties that are used in jsp

    The names of getters and setters must follow the conventions: get (for a getter) and set (for a setter) are added before the variable name, and the variable name is capitalized. For example, if a variable is named firstName, then the getter and setter functions should be named getFirstName and setFirstName, respectively.

    However, for boolean variables, the getter function uses the prefix is ​​instead of get. For example, the enabled variable and the isEnabled getter.

    implement the Serializable or Externalizable interface

Let's look at how to use JavaBean classes. Let's say we have the following structure:

In the Java Resources/src folder there is a User class with the following code:

Import java.io.Serializable; public class User implements Serializable ( private static final long serialVersionUID = 2041275512219239990L; private String name; private int age; public User() ( this.name = ""; this.age = 0; ) public User(String name, int age) ( this.name = name; this.age = age; ) public String getName() ( return name; ) public void setName(String name) ( this.name = name; ) public int getAge() ( return age; ) public void setAge(int age) ( this.age = age; ) )

This class represents the user and is a Java Bean class: it implements the Serializable interface, has a parameterless constructor, and its getter and setter methods that provide access to the name and age variables follow the conventions.

A user.jsp page is defined in the WebContent folder. Let's define the following code in it:

User Java Bean Page

Name: $(user.name)

Age: $(user.age)

This jsp page receives a user object from the outside and uses EL syntax to display the values ​​of its properties. It is worth noting that here the variables name and age are referenced, although they are private.

In the Java Resources/src folder, the HelloServlet.java file defines the HelloServlet servlet:

Import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/hello") public class HelloServlet extends HttpServlet ( protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException ( User tom = new User("Tom", 25); request.setAttribute("user", tom); getServletContext() .getRequestDispatcher("/user.jsp") .forward(request, response); ) )

The servlet creates a User object. To pass it to the user.jsp page, the "user" attribute is set via the call request.setAttribute("user", tom) . Next, there is a redirect to the user.jsp page. And thus the page will receive data from the servlet.

Is there a way to create a very simple HTTP server (supporting only GET/POST) in Java using only the Java SE API, without writing code to manually parse HTTP requests and manually format HTTP responses? The Java SE API nicely encapsulates HTTP client functionality in HttpURLConnection, but is there similar functionality for an HTTP server?

Just to be clear, the problem I have with a lot of the ServerSocket examples I've seen online is that they do their own request parsing/response algorithm and error handling, which is tedious, error-prone, and unlikely be all-encompassing, and I try to avoid it for these reasons.

As an example of manual HTTP manipulation that I'm trying to avoid:

18 answers

Starting with Java SE 6, the Sun Oracle JRE has a built-in HTTP server. The com.sun.net.httpserver package summary describes the participating classes and provides examples.

Here's a starting example, copied from their docs (however, anyone trying to edit it because it's a terrible piece of code, please don't copy, not mine, moreover, you should never edit quotes unless they've changed in the original source). You can just copy and run it on Java 6+.

package com.stackoverflow.q3732109; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class Test ( public static void main(String args) throws Exception ( HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/test", new MyHandler()); server.setExecutor( null); // creates a default executor server.start(); ) static class MyHandler implements HttpHandler ( @Override public void handle(HttpExchange t) throws IOException ( String response = "This is the response"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); ) ) )

It should be noted that the response.length() part of their example is bad, it should have been response.getBytes().length . Even in this case, the getBytes() method must explicitly specify the encoding, which you then specify in the response header. Alas, although misleading for beginners, it is, after all, just a basic example.

Execute it and go to http://localhost:8000/test and you will see the following response:

Regarding the use of com.sun.* , note that this, contrary to what some developers think, is absolutely not prohibited by the common FAQs. Why developers shouldn't write programs called "solar" packages. This sun.misc.BASE64Encoder FAQ is about the sun.* package (Such as sun.misc.BASE64Encoder) for internal using Oracle JRE (which will thus kill your application if you run it on another JRE), not the com.sun.* package. Sun/Oracle also just develops software on top of the Java SE API like any other company like Apache and so on. The use of com.sun.* is recommended (but not prohibited) when it comes to implementation specific Java API such as GlassFish (Java EE impl), Mojarra (JSF impl), Jersey (JAX-RS impl) etc.,

The com.sun.net.httpserver solution is not portable via the JRE. It's better to use the official web services API in javax.xml.ws to load a minimal HTTP server...

Import java.io._ import javax.xml.ws._ import javax.xml.ws.http._ import javax.xml.transform._ import javax.xml.transform.stream._ @WebServiceProvider @ServiceMode(value=Service .Mode.PAYLOAD) class P extends Provider ( def invoke(source: Source) = new StreamSource(new StringReader("

Hello There!

")); ) val address = "http://127.0.0.1:8080/" Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address) println("Service running at "+address) println( "Type +[C] to quit!") Thread.sleep(Long.MaxValue)

EDIT: this actually works! The above code looks like Groovy or something like that. Here's the Java translation I tested:

Import java.io.*; import javax.xml.ws.*; import javax.xml.ws.http.*; import javax.xml.transform.*; import javax.xml.transform.stream.*; @WebServiceProvider @ServiceMode(value = Service.Mode.PAYLOAD) public class Server implements Provider ( public Source invoke(Source request) ( return new StreamSource(new StringReader("

Hello There!

Look at the "Jetty" Jetty web server. Excellent part software open source that seems to meet all your requirements.

If you insist on rolling your own, look at the "httpMessage" class.

I like this question because this is an area where there is constant innovation and there is always a need to have a lightweight server, especially when it comes to embedded servers on small(er) devices. I think the answers fall into two broad groups.

  • Thin-server: Static content on the server with minimal processing, context or session processing.
  • Small server: supposedly a has many http-like server properties with a small size since you can go away.

Although I might think of HTTP libraries such as: Jetty, Apache Http Components, Netty and others to be more similar to raw HTTP handling facilities. Labeling is very subjective and depends on what you did for small sites. I make this distinction in the spirit of the question, especially the point about...

  • "...without writing code to manually parse HTTP requests and manually respond to HTTP responses..."

These source tools allow you to do this (as described in other answers). They really don't lend themselves to off-the-shelf design, creating a lightweight, embedded or mini server. A mini server is something that can give you similar functionality to a full featured web server (like Tomcat) without the bells and whistles, low volume, good performance 99% of the time. Thin server seems closer to the original phrase, a little more raw, perhaps with a limited feature set, just enough to make you look good 90% of the time. My raw presentation will make me look good 75% - 89% of the time without any additional design or coding. I think if/when you reach the level of WAR files, we left the "small" one for bonsi servers, which looks like everything a large server does.

Thin server options

  • UniRest (multiple languages)
  • NanoHTTPD (just one file)

Mini server parameters:

  • Spark Java... Good things are possible thanks to a lot of helper constructs like filters, templates, etc.
  • MadVoc... strives to be a bonsai and may well be one; -)

Among other things to consider, I would include authentication, validation, internationalization, using something like FreeMaker or another templating tool to render the output page. Otherwise, managing HTML editing and parameterization will likely make working with HTTP look like dreams-n-crosses. Naturally, it all depends on how flexible you are. If it's a menu fax machine, it can be very simple. The more interactions, the “thicker” your structure should be. Good question, good luck!

I was once looking for something similar - a lightweight but fully functional HTTP server that I could easily embed and configure. I found two types of potential solutions:

  • Full servers that are not that light or simple (to the extreme definition of light).
  • Truly lightweight servers that aren't exactly HTTP servers, but glorified ServerSocket examples that don't even support RFC compliance and don't support the basic functionality usually needed.

You can embed it into any project as a single (if quite long) source file or as a ~50KB (~35KB) banner without any dependencies. It strives to be RFC compliant and includes extensive documentation and many useful functions while keeping bloat to a minimum.

Features include: virtual hosts, files from disk, mime type mappings via standard mime.types file, directory index generation, welcome files, support for all HTTP methods, conditional ETags and If-* header support, transfer encoding, gzip/reset compression, basic HTTPS ( as provided by the JVM), partial content (load continuation), multifile/form file handling for file loading, multiple context handlers via API or annotations, parameter parsing (query string or x-www-form-urlencoded body), etc.

I hope others find this useful :-)

It is possible to create an httpsserver that provides basic support for J2EE servlets with just the JDK and servlet api in just a few lines of code.

I have found this very useful for servlets for unit testing as it starts up much faster than other lightweight containers (we use jetty for production).

Most very lightweight httpsservers don't provide servlet support, but we need them, so I thought I'd share.

The example below provides basic servlet support or throws and UnsupportedOperationException for those things that are not yet implemented. It uses com.sun.net.httpserver.HttpServer for basic http support.

Import java.io.*; import java.lang.reflect.*; import java.net.InetSocketAddress; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; @SuppressWarnings("deprecation") public class VerySimpleServletHttpServer ( HttpServer server; private String contextPath; private HttpHandler httpHandler; public VerySimpleServletHttpServer(String contextPath, HttpServlet servlet) ( this.contextPath = contextPath; httpHandler = new HttpHandlerWithServletSupport(servlet); ) public void start (int port) throws IOException ( InetSocketAddress inetSocketAddress = new InetSocketAddress(port); server = HttpServer.create(inetSocketAddress, 0); server.createContext(contextPath, httpHandler); server.setExecutor(null); server.start(); ) public void stop(int secondsDelay) ( server.stop(secondsDelay); ) public int getServerPort() ( return server.getAddress().getPort(); ) ) final class HttpHandlerWithServletSupport implements HttpHandler ( private HttpServlet servlet; private final class RequestWrapper extends HttpServletRequestWrapper ( private final HttpExchange ex; private final Map postData; private final ServletInputStream is; private final Map attributes = new HashMap<>(); private RequestWrapper(HttpServletRequest request, HttpExchange ex, Map postData, ServletInputStream is) ( super(request); this.ex = ex; this.postData = postData; this.is = is; ) @Override public String getHeader(String name) ( return ex.getRequestHeaders().getFirst(name ); ) @Override public Enumeration getHeaders(String name) ( return new Vector (ex.getRequestHeaders().get(name)).elements(); ) @Override public Enumeration getHeaderNames() ( return new Vector (ex.getRequestHeaders().keySet()).elements(); ) @Override public Object getAttribute(String name) ( return attributes.get(name); ) @Override public void setAttribute(String name, Object o) ( this.attributes.put(name, o); ) @Override public Enumeration getAttributeNames() ( return new Vector (attributes.keySet()).elements(); ) @Override public String getMethod() ( return ex.getRequestMethod(); ) @Override public ServletInputStream getInputStream() throws IOException ( return is; ) @Override public BufferedReader getReader() throws IOException ( return new BufferedReader(new InputStreamReader(getInputStream( ))); ) @Override public String getPathInfo() ( return ex.getRequestURI().getPath(); ) @Override public String getParameter(String name) ( String arr = postData.get(name); return arr != null ? (arr.length > 1 ? Arrays.toString(arr) : arr) : null; ) @Override public Map getParameterMap() ( return postData; ) @Override public Enumeration getParameterNames() ( return new Vector (postData.keySet()).elements(); ) ) private final class ResponseWrapper extends HttpServletResponseWrapper ( final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ServletOutputStream servletOutputStream = new ServletOutputStream() ( @Override public void write(int b) throws IOException ( outputStream.write(b); ) ); private final HttpExchange ex; private final PrintWriter printWriter; private int status = HttpServletResponse.SC_OK; private ResponseWrapper(HttpServletResponse response, HttpExchange ex) ( super(response); this.ex = ex; printWriter = new PrintWriter(servletOutputStream); ) @Override public void setContentType(String type) ( ex.getResponseHeaders().add("Content-Type", type); ) @Override public void setHeader(String name, String value) ( ​​ex.getResponseHeaders().add(name, value) ; ) @Override public javax.servlet.ServletOutputStream getOutputStream() throws IOException ( return servletOutputStream; ) @Override public void setContentLength(int len) ( ex.getResponseHeaders().add("Content-Length", len + ""); ) @Override public void setStatus(int status) ( this.status = status; ) @Override public void sendError(int sc, String msg) throws IOException ( this.status = sc; if (msg != null) ( printWriter.write (msg); ) ) @Override public void sendError(int sc) throws IOException ( sendError(sc, null); ) @Override public PrintWriter getWriter() throws IOException ( return printWriter; ) public void complete() throws IOException ( try ( printWriter.flush(); ex.sendResponseHeaders(status, outputStream.size()); if (outputStream.size() > 0) ( ex.getResponseBody().write(outputStream.toByteArray()); ) ex.getResponseBody( ).flush(); ) catch (Exception e) ( e.printStackTrace(); ) finally ( ex.close(); ) ) public HttpHandlerWithServletSupport(HttpServlet servlet) ( this.servlet = servlet; ) @SuppressWarnings("deprecation ") @Override public void handle(final HttpExchange ex) throws IOException ( byte inBytes = getBytes(ex.getRequestBody()); ex.getRequestBody().close(); final ByteArrayInputStream newInput = new ByteArrayInputStream(inBytes); final ServletInputStream is = new ServletInputStream() ( @Override public int read() throws IOException ( return newInput.read(); ) ); Map parsePostData = new HashMap<>(); try ( parsePostData.putAll(HttpUtils.parseQueryString(ex.getRequestURI().getQuery())); // check if any postdata to parse parsePostData.putAll(HttpUtils.parsePostData(inBytes.length, is)); ) catch (IllegalArgumentException e) ( // no postData - just reset inputstream newInput.reset(); ) final Map postData = parsePostData; RequestWrapper req = new RequestWrapper(createUnimplementAdapter(HttpServletRequest.class), ex, postData, is); ResponseWrapper resp = new ResponseWrapper(createUnimplementAdapter(HttpServletResponse.class), ex); try ( servlet.service(req, resp); resp.complete(); ) catch (ServletException e) ( throw new IOException(e); ) ) private static byte getBytes(InputStream in) throws IOException ( ByteArrayOutputStream out = new ByteArrayOutputStream( ); byte buffer = new byte; while (true) ( ​​int r = in.read(buffer); if (r == -1) break; out.write(buffer, 0, r); ) return out.toByteArray( ); ) @SuppressWarnings("unchecked") private static T createUnimplementAdapter(Class httpServletApi) ( class UnimplementedHandler implements InvocationHandler ( @Override public Object invoke(Object proxy, Method method, Object args) throws Throwable ( throw new UnsupportedOperationException("Not implemented: " + method + ", args=" + Arrays.toString(args) ); ) ) return (T) Proxy.newProxyInstance(UnimplementedHandler.class.getClassLoader(), new Class( httpServletApi ), new UnimplementedHandler()); ) )

I highly recommend looking into it, especially if you don't need servlet capabilities and just access to request/response objects. If you need REST, you can put Jersey on top of it if you need to output HTML or similar there Freemarker. I really like what you can do with this combination, and there are relatively few APIs to learn.

This code is better than ours, you only need to add 2 libraries: javax.servelet.jar And org.mortbay.jetty.jar.

Berth class:

Package jetty; import java.util.logging.Level; import java.util.logging.Logger; import org.mortbay.http.SocketListener; import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.ServletHttpContext; public class Jetty ( public static void main(String args) ( try ( Server server = new Server(); SocketListener listener = new SocketListener(); System.out.println("Max Thread:" + listener.getMaxThreads() + " Min Thread:" + listener.getMinThreads()); listener.setHost("localhost"); listener.setPort(8070); listener.setMinThreads(5); listener.setMaxThreads(250); server.addListener(listener); ServletHttpContext context = (ServletHttpContext) server.getContext("/"); context.addServlet("/MO", "jetty.HelloWorldServlet"); server.start(); server.join(); /*//We will create our server running at http://localhost:8070 Server server = new Server(); server.addListener(":8070"); //We will deploy our servlet to the server at the path "/" //it will be available at http://localhost:8070 ServletHttpContext context = (ServletHttpContext) server.getContext("/"); context.addServlet("/MO", "jetty.HelloWorldServlet"); server.start(); */ ) catch ( Exception ex) ( Logger.getLogger(Jetty.class.getName()).log(Level.SEVERE, null, ex); ) ) )




The best way to understand how something works is to do it yourself.

Once interested network technologies and, among other things, servers, I came to the idea that it would be nice to write one such server myself, using Java.

However, most of the Java literature that came across my eyes, if it explained something on the topic, it was only in the most general outline, without going beyond the exchange of text messages between client-server applications. On the Internet, such information was not found much more often, mainly in the form of grains of knowledge on educational sites or fragmentary information from users of various forums.

Thus, having collected this knowledge together and written a digestible server application capable of processing browser requests, I decided to distill this knowledge and describe step by step the process of creating a simple web server in Java.

I hope this article provides some useful knowledge for aspiring Java programmers and other people learning related technologies.

So, since the program assumes the simplest server functions, it will consist of one class without GUI. This class (Server) inherits a stream and has one field - a socket:

Class Server extends Thread ( Socket s; )
In the main method, we create a new ServerSocket and set the port for it (in in this case port 1025 is used) and wait in an endless loop for a connection with the client. If there is a connection, we create a new thread by passing it the corresponding socket. If unsuccessful, we display an error message:

Try ( ServerSocket server = new ServerSocket(1025); while(true) ( ​​new Server(server.accept()); ) ) catch(Exception e) ( System.out.println("Error: " + e); )

In order to do possible creation of a new thread in this way, we naturally must describe the corresponding constructor for it. In the constructor we mark the thread as a daemon and run it here:

Public Server(Socket socket) ( this.socket = socket; setDaemon(true); start(); )
Next, we describe the functionality of the stream in the run() method: first of all, we create a stream of outgoing and incoming data from the socket:

Public void run() ( try ( InputStream input = socket.getInputStream(); OutputStream output = socket.getOutputStream();
To read incoming data, we will use a buffer, which is a byte array of a certain size. Creating such a buffer is not necessary, because it is possible to receive incoming data in other ways, without limiting the amount of information received - but for the simplest web server described here, 64 kB is enough to receive the necessary data from the client.

In addition to the byte array, we also create an int variable that will store the number of bytes actually received by the buffer. This is necessary in order to subsequently create a client request string from the received data in a special way:

Byte buffer = new byte; int bytes = input.read(buffer); String request = new String(buf, 0, r);
The request line will contain the http request from the client. Among other information contained in this request, we will this moment I'm interested in the address of the requested file and its extension.

Without going into details of the structure of the http request, I will only say that the information we need will be in the first line of this request approximately in the following form:

GET /index.html HTTP/1.1
In this example, a page is requested on the server at

/index.html
A page with this address is displayed on most servers by default. Our task is to extract this address from the request using our own written getPath() method. There are many options similar method and there is no point in citing them here. Key moment here is that having received the path to the desired file and writing it to the string variable path, we can try to create a file based on this data and, if successful, return this file, and if unsuccessful, return a specific error message:

String path = getPath(request); File file = new File(path);
We check whether this file directory. If such a file exists and is a directory, then we return the default file mentioned above - index.html:

Boolean exists = !file.exists(); if(!exists) if(file.isDirectory()) if(path.lastIndexOf(""+File.separator) == path.length()-1) ( path = path + "index.html"; ) else ( path = path + File.separator + "index.html"; file = new File(path); exists = !file.exists(); )
If the file at the specified address does not exist, then we create an http response in the response line indicating that the file was not found, adding to in the right order the following headings:

If(exists)( String response = "HTTP/1.1 404 Not Found\n"; response +="Date: " + new Date() + "\n"; response +="Content-Type: text/plain\n "; response +="Connection: close\n"; response +="Server: Server\n"; response +="Pragma: no-cache\n\n"; response += "File " + path + " Not Found!";
After generating the response string, we send them to the client and close the connection:

Output.write(response.getBytes()); socket.close(); return; )
If the file exists, then before generating a response you need to find out its extension and, therefore, MIME type. First, we will find out the index of the point before the file extension and save it into an int variable.

Int ex = path.lastIndexOf(".");
Then we isolate the file extension that comes after it. The list of possible MIME types can be expanded, but in this case you will use only one form of 3 formats: html, jpeg and gif. By default we will use the MIME type for text:

String mimeType = “text/plain”; if(ex > 0) ( String format = path.substring(r); if(format.equalsIgnoreCase(".html")) mimeType = "text/html"; else if(format.equalsIgnoreCase(".jpeg")) mimeType = "image/jpeg"; else if(format.equalsIgnoreCase(".gif")) mimeType = "image/gif";
We formulate a response to the client:

String response = "HTTP/1.1 200 OK\n"; response += "Last-Modified: " + new Date(file.lastModified())) + "\n"; response += "Content-Length: " + file.length() + "\n"; response += "Content-Type: " + mimeType + "\n"; response +="Connection: close\n";
There must be two empty lines at the end of the headers, otherwise the response will not be processed correctly by the client.

Response += "Server: Server\n\n"; output.write(response.getBytes());
To send the file itself, you can use the following construction:

FileInputStream fis = new FileInputStream(path); int write = 1; while(write > 0) ( write = fis.read(buffer); if(write > 0) output.write(buffer, 0, write); ) fis.close(); socket.close(); )
Finally, we complete the try-catch block specified at the beginning.

Catch(Exception e) ( e.printStackTrace(); ) )
Since, as already mentioned, this web server implementation is one of the simplest, it can be easily modified by adding a graphical user interface, the number of supported extensions, a connection limiter, etc. In a word, the scope for creativity remains enormous. Go for it.

You can help and transfer some funds for the development of the site

When I started working in Java EE, the server infrastructure seemed like a mysterious, capricious monster to me. And this despite the fact that I came to programming from an admin background. Filled the ear in Resin, check if it rises? Did you unpack successfully? One day, the admins and I spent half the night trying to understand why, after a seemingly successful deployment, requests were still being answered. old copy applications. With such dancing with a tambourine, the transition to GlassFish seemed good decision, and abandoning ejb is even better. Some of my colleagues rejoiced at the power of Spring, others were looking for something simpler... I wrote servlets under tomcat, and when I did something very small, I simply integrated jetty.
The simpler the better. It is clear that there are non-trivial requirements, there are complex tasks. But let’s face it, how many simple, unloaded services have you implemented using overly powerful and complex tools? “I’m used to this framework and don’t want to lose my skill,” I usually hear. “You will leave and whoever supports this monster code will curse you,” I think in response.
Maybe I didn’t convince you to write simple things. by simple means, but look at how you can make a server-side java application without a server at all. It's interesting after all.

How, without a server at all? Write request processing yourself?

Well, no, what are you talking about? I'm for simple solutions, but not for bicycles. Everything has already been written and, moreover, already installed. The java server is already in your jdk. Just use it)

Import com.sun.net.httpserver.HttpServer; import java.io.IOException ; import java.net.InetSocketAddress ; import java.util.concurrent.Executors; public class Main ( private static final int PORT = 9090 ; public static void main(String args) throws IOException ( int port = PORT; if (args.length > 0 ) ( try ( port = Integer .parseInt (args[ 0 ] ) ; ) catch (Exception e) ( e.printStackTrace () ; ) ) HttpServer server = HttpServer.create (new InetSocketAddress(port) , 0 ) ; server.createContext ("/publish" , new PublishHandler() ) ; server.createContext ("/subscribe" , new SubscribeHandler() ) ; server.setExecutor (Executors.newCachedThreadPool () ) ; server.start () ; System .out .println ( "Server is listening on port"+port); ) )
com.sun.net.HttpServer is all we need. Our application will listen for requests on port 9090 or whatever will be specified java -jar our.jar here. We attach our handlers to contexts before the server starts. Everything is extremely simple. In order to focus on business logic in the handlers, we will create an abstract ancestor for them, where we will solve all the little things like reading the request parameters and logging the request-response pair:

Import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import java.io.IOException ; import java.io.OutputStream ; import java.text.SimpleDateFormat ; import java.util.Date ; import java.util.HashMap ; import java.util.Map ; import java.util.UUID ; public abstract class HttpHandlerBased implements HttpHandler ( protected abstract String doGet(HttpExchange exchange, Map< String , String>params); @Override public void handle(HttpExchange exchange) throws IOException ( String requestMethod = exchange.getRequestMethod () ; if (requestMethod.equalsIgnoreCase ( "GET" ) ) ( String uriStr = exchange.getRequestURI () .getQuery () ; String id = UUID .randomUUID () .toString () .replace ("-" , "" ) ; log(" " + uriStr) ; Map< String , String>pars = new HashMap< String , String>() ; String pairs; if (uriStr != null && uriStr.contains ("=" ) ) ( if (uriStr.contains ("&") ) pairs = uriStr.split ("&" ) ; else pairs = new String ( uriStr) ; for ( String pair : pairs) ( String p = pair.split ("=" ) ; if (p.length == 2 ) ( pars.put (p[ 0 ] , p[ 1 ] ) ; ) ) ) String resp = doGet (exchange, pars) ; log(" " + resp) ; exchange.sendResponseHeaders(200, resp.length()); OutputStream body = exchange.getResponseBody(); body.write(resp.getBytes("UTF-8")); body.close(); ) ) public static void log(String msg) ( System .out .println (new SimpleDateFormat ("HH:mm:ss:SSS dd.MM.yy") .format (new Date () ) + " - " + msg) ; ) )
Having such an ancestor behind us, all we have to do is implement the doGet method in each specific “servlet”. I don’t process the POST method here because I don’t need it. But it’s no more difficult to process, you can try it yourself.

So what do we get?

For the "secret web server", essentially the internal java API, we have very nice tools for working with request data, response headers, etc. All this does not require any installation or configuration; it is right in the box and ready to go. Why not a tool for a simple web service? Of course, when we test our idea and think about production, we can transfer our business logic to “honest” servlets and use the same tomcat or resin. Why not? But if the project does not go into production, we will thank ourselves for not involving admins, not spending days deploying and setting up the environment, but simply going ahead and doing what was needed. And nothing more.







2024 gtavrl.ru.