JavaRush /Java Blog /Random EN /Web application in Java
Viacheslav
Level 3

Web application in Java

Published in the Random EN group
Web application in Java - 1

Introduction

Once upon a time, Java strengthened its position due to the fact that it chose web applications as a priority. Since its early days, Java has struggled to find its way. First, I suggested applets. This has provided many opportunities for developers to create dynamic content (content) on static HTML pages. However, applets did not live up to expectations for many reasons: security, overhead, and others. Then the developers of the Java language proposed an alternative - Servlet API . And it turned out to be the right decision. The Servlet API is the specification on which any Java web application is built, be it a web-based application or a web service that returns information as requested. Therefore, the path to understanding how Java web applications work begins with understanding the Servlet API.
Web application in Java - 2

Servlet API

So, the Servlet API is what the language developers offered to Java developers. The Servlet API is a specification that should answer our main questions. You can find it here: " JSR-000340 JavaTM Servlet 3.1 Final Release for Evaluation ". The chapter " 1.1 What is a Servlet? " says that a servlet is a web component based on Java technology that creates dynamic content (that is, content). "Java-based" means that a servlet is a Java class compiled into bytecode . Servlets are managed by a servlet container, sometimes called the Servlet Engine. A servlet container is a web server extension that provides servlet functionality. In turn, servlets provide interaction with the client in the request/response paradigm, which is implemented by the servlet container. In the chapter " 1.2 What is a Servlet Container? " it is said that a servlet container is part of a web server or application server that provides network services through which requests and responses are sent, MIME-based requests and responses are generated and processed. In addition, servlet containers manage the life cycle of servlets (i.e. decide when to create them, delete them, etc.). All servlet containers must support the HTTP protocol to receive requests and send responses. Here I would like to add that MIME is a standard, a specification that tells how information should be encoded and messages formatted so that they can be sent over the Internet.
Web application in Java - 3

Web-server

A web server is a server that accepts HTTP requests from clients and provides them with HTTP responses (usually along with an HTML page, image, file, or other data). Requested resources are identified by URLs. One of the most popular web servers with Servlet API support is Apache Tomcat . Most web servers are complex machines that are made up of various components, each of which performs specific functions. For example:
Web application in Java - 4

Connectors

— At the input we have Connectors (i.e. connectors) that accept incoming requests from clients. The HTTP connector in Tomcat is implemented using the "Coyote" component. Connectors receive data from the client and pass it on to the Tomcat Engine. Servlet Container - Tomcat Engine, in turn, processes the request received from the client using the "Catalina" component, which is a servlet container. See the Tomcat documentation: " Architecture Overview " for more details. There are other web servers that support the Servlet API specification. For example, " Jetty " or " Undertow ". Their architecture is similar, so understanding the principle of working with one servlet container, you can switch to working with another.
Web application in Java - 5

Web Application

So, in order for us to run a web application, we need a web server that supports the Servlet API (that is, one that has an extension component that implements Servlet API support for the web server). Fine. What is a web application anyway? According to the " 10 Web Applications " chapter of the Servlet API specification, a Web application is a collection of servlets, HTML pages, classes, and other resources that make up a final application on a Web server. According to the chapter " 10.6 Web Application Archive File ", a web application can be packaged in Web ARchive (an archive with a WAR extension). As stated on the " Glossary-219 " page:
Web application in Java - 6
That is, WAR is made instead of JAR to show that this is a web application. The next important fact: we must have a certain directory structure in our WAR archive. In the Servlet API specification in the chapter " 10.5 Directory Structure ". This chapter says that there is a special directory called "WEB-INF". This directory is special in that it is not visible to the client and is not directly shown to it, but it is accessible to servlet code. It also says what the WEB-INF directory can contain:
Web application in Java - 7
From this entire list, we now do not know and do not understand the item about some web.xml file called deployment descriptor . What is it? The chapter " 14. Deployment Descriptor " is devoted to the deployment descriptor. In short, a deployment descriptor is an xml file that describes how to deploy (that is, run) our web application on a web server. For example, the deployment descriptor indicates which URLs should be used to access our application, security settings that relate to our application, etc. are indicated. The chapter " 14.2 Rules for Processing the Deployment " says that web.xml will be schema validated before our application is configured and launched (that is, a check will be made that the contents of web.xml are written correctly according to the schema). And in the chapter " 14.3 Deployment Descriptor " it is indicated that the diagram is here: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd If we look at the contents of the file, we can see:
Web application in Java - 8
What is schema used for XML files? The schemas indicate how to correctly fill out an XML document: what elements can be used, what type of data can be specified in the elements, in what order the elements should go, what elements are required, etc. You can compare the schema of an XML document with an interface in Java, because the schema in Java also specifies how classes that satisfy a given interface (that is, that implement a given interface) should be written. So, we are armed with secret knowledge and are ready to create our first web application!
Web Application in Java - 9

Creating a Web Application

It’s hard to imagine working with a modern Java application without using automatic project build systems. Some of the most popular systems are Maven and Gradle . We will use Gradle for this review. Installation of Gradle is described on the official website . To create a new application, we need a plugin built into Gradle: " Build Init Plugin ". To create a Java application you need to run the following command: gradle init --type java-application
Web application in Java - 10
After creating the project, we will need to edit the build.gradle file . This is the so-called Build Script (for more details, see the Gradle documentation: " Writing Build Scripts "). This file describes how to assemble the project and other aspects of working with a Java project. The plugins block describes which " Gradle plugins " should be used for the current Gradle project. Plugins expand the capabilities of our project. For example, the default plugin is " java ". This plugin is always used if we need Java support. But we don’t need the “ application ” plugin, because... its description states that it is used to create an "executable JVM application", i.e. running JVM applications. We need to create a Web application in the form of a WAR archive. And if we look for the word WAR in the Gradle documentation, we will find “ War Plugin ”. Therefore, we will specify the following plugins:

plugins {
    id 'java'
    id 'war'
}
Also in the " War Plugin Default Settings " it is said that the directory with all the contents of the web application should be "src/main/webapp", there should be the same WEB-INF directory in which the web.xml should be located. Let's create such a file. We will fill it out a little later, because... we don't yet have enough information for this. In the "dependencies" block we indicate the dependencies of our project, that is, those libraries/frameworks without which our application cannot work. In this case, we are writing a web application, which means we cannot work without the Servlet API:

dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    testCompile 'junit:junit:4.12'
}
providedCompile means that the dependency does not need to be included in our WAR archive of the web application: it is needed only for compilation. And when executed, this dependency will be provided by someone else (that is, the web server). Well, we leave information in the build script about which dependency repository we want to use - all specified dependencies will be downloaded from it:

repositories {
    jcenter()
}
We remove everything else from the build script file. Now let's edit the class src\main\java\App.java. Let's make a servlet out of it. The Servlet API specification in the chapter " CHAPTER 2. The Servlet Interface " states that the Servlet Interface has a base implementation of HttpServlet , which should be sufficient in most cases and developers just need to inherit from it. And in the chapter " 2.1.1 HTTP Specific Request Handling Methods " the main methods that process incoming requests are indicated. Thus, let's rewrite the App.java class:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.IOException;

public class App extends HttpServlet {
    public String getGreeting() {
        return "Hello world.";
    }

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 		// https://www.oracle.com/technetwork/java/servlet-142430.html
 		PrintWriter out = resp.getWriter();
 		out.println(this.getGreeting());
 		out.close();
 	}
}
So, we seem to have everything ready. All that remains is to write the deployment descriptor correctly. From the diagram, copy the following text into web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="..."
      version="3.1"> 
      ...
</web-app>
And also the path to the schema that is indicated in it: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Now let's look at an example of what web.xml should look like in the Servlet API specification. This example is given in the chapter " 14.5.1 A Basic Example ". Let's combine what is indicated in the diagram with the example indicated in the specification. We get the following:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
      version="3.1">
      <display-name>A Simple Web Application</display-name>
      <servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>App</servlet-class>
	  </servlet>
	  <servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app</url-pattern>
	  </servlet-mapping>
</web-app>
As you can see, we used the schema and schemaLocation that were specified earlier. And the description of the elements themselves was taken from the example from Chapter 14.5.1. If we did everything correctly, we will execute the gradle war task without errors:
Web application in Java - 11
Web application in Java - 12

Launching a web application

How does a web application launch? Let's deal with the more complex option first. We previously said that there is an Apache Tomcat web server that supports the Servlet API. This means that we can deploy our collected war archive (they also say “deploy”) on this server. On the " Download Tomcat " page, download from the "Binary Distributions" section the delivery type "Core" in zip format. And unpack the downloaded archive into some directory, for example in C:\apache-tomcat-9.0.14. Before starting the server, let's open the file for editing conf\tomcat-users.xmland add the following line to it: <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/> Now, on the command line, go to the bin directory and execute catalina.bat start. By default, the server console will be available at http://localhost:8080/manager. The login and password are the same ones that we specified in tomcat-users.xml. Tomcat has a "webapps" directory, which contains web applications. If we want to deploy our own, we must copy our war archive there. When we previously ran the gradle war command, \build\libs\a war archive was created in the directory. This is what we need to copy. After copying, refresh the page http://localhost:8080/managerand see:
Web application in Java - 13
Having completed http://localhost:8080/javaweb/app, we will turn to our servlet, because We previously “mapped” (that is, mapped) the /app request to the App servlet. There is a faster way to check how the application works. And the assembly system helps us with this again. In the build script of our Gradle project, we can add a new plugin " Gretty " to the plugins section: id "org.gretty" version "2.3.1" And now we can perform a gradle task to run our application:gradle appRun
Web application in Java - 14
See " Add the gretty plugin and run the app " for details.
Web application in Java - 15

Spring and Servlet API

Servlets are the basis of everything. And even the now popular Spring Framework is nothing more than an add-on to the Servlet API. To begin with, the Spring Framework is a new dependency for our project. Therefore, let's add it to the build script in the dependencies block: compile 'org.springframework:spring-webmvc:5.1.3.RELEASE' In the Spring Framework documentation there is a chapter " 1.1. DispatcherServlet ". It says that the Spring Framework is built on the "front controller" pattern - this is when there is a central servlet called " DispatcherServlet ". All requests come to this servlet, and it delegates calls to the necessary components. You see, even here there are servlets. You need to add a listener to the deployment descriptor:

<listener>
	&ltlistener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
This is a servlet context event listener. That is, when the Servlet Context starts, the Spring context (WebApplicationContext) also starts. What is Servlet Context? It is described in the Servle API specification in the chapter " CHAPTER 4. Servlet Context ". A servlet context is a servlet's "view" of the web application within which the servlets are running. Each web application has its own Servlet Context. Next, to enable the Spring Framework, you need to specify context-param - the initialization parameter for the servlet context.

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
And the DispatcherServlet definition completes the configuration :

<servlet>
	<servlet-name>app</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
 		<param-value></param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>app</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
And now we just need to fill out the file specified in contextConfigLocation. How to do this is described in the Spring Framework documentation in the chapter "1.3.1. Declaration":

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="ru.javarush.javaweb"/>
    <mvc:annotation-driven/>
</beans>
It is important here not only to indicate which package to scan, but also that we want annotation-driven, that is, to control the annotations on how Spring will work. All that remains is to create the ru.javarush.javaweb package and place the Spring controller class in it:

package ru.javarush.javaweb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SpringController {
    
    @GetMapping("/app")
    @ResponseBody
    public String getGreeting() {
        return "Hello world.";
    }
}
Now running gradle appRun and going to the address, http://127.0.0.1:8080/javaweb/appwe will get the same Hello World. As you can see, the Spring Framework is closely intertwined with the Servlet API and uses it to work on top of it.
Web application in Java - 16

Annotations

As we've seen, annotations are convenient. And we weren’t the only ones who thought so. Therefore, in the Servlet API specification, starting with version 3.0, the chapter “ CHAPTER 8 Annotations and pluggability ” appeared, which specifies that servlet containers must support the ability to specify what was previously specified in the Deployment Descriptor through annotations. Thus, web.xml can be completely removed from the project, and above the servlet class you can specify the @WebServlet annotation and indicate which path to map the servlet to. Everything seems clear here. But what if we connected Spring to the project, which requires more complex settings? Here everything is a little more complicated. First, the Spring documentation says that to configure Spring without web.xml, you need to use your own class that will implement WebApplicationInitializer. For more details, see the chapter " 1.1. DispatcherServlet ". It turns out that this is a Spring class. How then is the Servlet API used here? In fact, the ServletContainerInitializer was added to the Servlet API 3.0 . Using a special mechanism in Java (called SPI ), Spring specifies its servlet container initializer called SpringServletContainerInitializer. In turn, it already looks for implementations of WebApplicationInitializer and calls the necessary methods and performs the necessary settings. See " How servlet container finds WebApplicationInitializer implementations " for more details. The above settings can be done like this:

package ru.javarush.javaweb.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class AppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        // регистрируем конфигурацию созданую высше
        ctx.register(AppConfig.class);
        // добавляем в контекст слушателя с нашей конфигурацией
        servletContext.addListener(new ContextLoaderListener(ctx));

        ctx.setServletContext(servletContext);

        // настраиваем маппинг Dispatcher Servlet-а
        ServletRegistration.Dynamic servlet =
                servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
    }
}
Now, using " Java-based configuration " we will indicate which package to scan + enable annotations:

package ru.javarush.javaweb.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "ru.javarush.javaweb.controllers")
public class AppConfig {
}
And the SpringController itself was moved to ru.javarush.javaweb.controllers, so that when scanning, the configuration would not find itself, but would only look for controllers.
Web application in Java - 17

Summarizing

I hope this overview has shed some light on how web applications work in Java. This is just the tip of the iceberg, but without understanding the basics, it is difficult to understand how technologies based on this foundation work. The Servlet API is the central part of any Java web application, and we've looked at how other frameworks fit into it. To continue, you can view the following materials: #Viacheslav
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION