JavaRush /Java Blog /Random EN /Java web application
Viacheslav
Level 3

Java web application

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 the priority direction of the web application. Since the early days, Java has been trying to find its way. First, he suggested applets. This has provided many opportunities for developers to create dynamic content (content) on static HTML pages. However, applets fell short of expectations for many reasons: security, overhead, and others. Then the developers of the Java language offered an alternative - Servlet API . And it turned out to be the right decision. The Servlet API is the specification upon which any Java web application is built, whether it's an application with a web interface or a web service that returns information according to a request. Therefore, the path to understanding Java web applications begins with understanding the Servlet API.
Java web application - 2

Servlet API

So, the Servlet API is what the developers of the language 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 (i.e. content). "Based on Java technology" means that a servlet is a Java class compiled into bytecode . Servlets are managed by a servlet container, sometimes referred to as the Servlet Engine. Servlet container is a web server extension, which provides servlet functionality. In turn, servlets provide interaction with the client in the request / response paradigm, which is implemented by the servlet container. The chapter " 1.2 What is a Servlet Container? " says that a servlet container is part of a web serveror an 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 in order to receive requests and send responses. Here I would like to add that MIME is such a standard, a specification that tells how information should be encoded and messages formatted so that they can be sent over the Internet.
Java web application - 3

webserver

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). The 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:
Java web application - 4

Connectors

- At the entrance, 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 for details: " Architecture Overview ". 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 change to work with another.
Web application in Java - 5

Web Application

So, in order for us to be able to run a web application, we need a web server that supports the Servlet API (that is, in which there is an extension component that implements support for the Servlet API for the web server). Fine. What is a web application anyway? According to chapter " 10 Web Applications " of the Servlet API specification, a Web application is a set of servlets, HTML pages, classes, and other resources that make up a final application on a web server. According to chapter " 10.6 Web Application Archive File ", a web application can be packaged in Web ARchive (archive with WAR extension). As it says on the " Glossary-219 " page:
Java web application - 6
That is, WAR is made instead of JAR to show that it is a web application. The next important fact is that we must have a certain directory structure in our WAR archive. In the Servlet API specification in 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 shown directly to the client, but it is available to the servlet code. It also says that 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 kind of web.xml file called deployment descriptor (deployment descriptor). What is it? Deployment descriptor is covered in the chapter " 14. 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 specifies which URLs should be used to access our application, security settings that apply to our application, etc. In chapter " 14.2 Rules for Processing the Deployment" it says that web.xml before our application is configured and launched will be validated according to the scheme (that is, a check will be made that the contents of web.xml are written correctly according to the scheme). And in the chapter " 14.3 Deployment Descriptor " it is indicated that the scheme lies 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:
Java web application - 8
What is the schema for XML files used for? 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, which elements are required, etc. You can compare the schema of an XML document to 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 ready to create our first web application!
Java web application - 9

Create a web application

It is already difficult to imagine working with a modern Java application without the use of automatic project assembly systems. Some of the most popular systems are Maven and Gradle . Let's use Gradle for this review. Gradle installation 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, run the following command: gradle init --type java-application
Java web application - 10
After creating the project, we need to edit the build.gradle file . This is the so-called Build Script (see the Gradle documentation: " Writing Build Scripts " for details). This file describes how to build 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 possibilities of our project. For example, the plugin " java " is used by default . This plugin is always used if we need Java support. But here is the plugin " application"We do not need it, because its description indicates that it is used to create an "executable JVM application", i.e. applications executed by the JVM. We need to create a Web application in the form of a WAR archive. And if we are in the Gradle documentation search for the word WAR, and find " War Plugin " Therefore, specify the following plugins:
plugins {
    id 'java'
    id 'war'
}
Also in " 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 web.xml should be. Let's create such a file. We will fill it out a little later, because we don't have enough information for that yet. In the "dependencies" block, we specify 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 tells us that the dependency doesn't need to be included in our web application WAR, it's only needed for compilation. And when executed, this dependency will be provided by someone else (that is, a web server). Well, we leave in the build script information about which dependency repository we want to use - all the specified dependencies will be downloaded from it:
repositories {
    jcenter()
}
We remove everything else from the build script file. Now let's edit the src\main\java\App.java class. Let's make it a servlet. The Servlet API specification in chapter " CHAPTER 2. The Servlet Interface " says that the Servlet Interface has a base implementation of HttpServlet , which should suffice in most cases and should be enough for developers to inherit from. And the chapter " 2.1.1 HTTP Specific Request Handling Methods " shows the main methods that handle incoming requests. 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 be all set. It remains to correctly write the deployment descriptor. Copy the following text from the schema 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>
As well as the path to the schema, which is specified in it: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Now let's see an example of how web.xml should look like in the Servlet API specification. This example is given in 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 right, we will execute the gradle task gradle war without errors:
Java web application - 11
Java web application - 12

Launching the web application

How does the web application start? 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. And this means that we will be able to deploy our compiled war archive (they also say "deploy") on this server. On the " Download Tomcat " page, download the "Core" distribution type from the "Binary Distributions" section in zip format. And unpack the downloaded archive into some directory, for example, 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, in the command line, go to the bin directory and execute catalina.bat start. By default, the server console will be available athttp://localhost:8080/manager. The login and password are the same ones that we specified in tomcat-users.xml. Tomcat has a "webapps" directory that contains web applications. If we want to deploy our own, we must copy our war archive there. When we ran the gradle war command earlier, \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:
Java web application - 13
After executing http://localhost:8080/javaweb/app, we will turn to our servlet, because the /app call earlier we "mapped" (i.e. mapped) to the App servlet. There is a faster way to check how the application works. And the assembly system helps us in this again. In the build script of our Gradle project, we can add a new " Gretty " plugin to the plugins section : id "org.gretty" version "2.3.1" And now we can execute the gradle task to run our application:gradle appRun
Java web application - 14
See " Add the gretty plugin and run the app " for details.
Java web application - 15

Spring and Servlet API

Servlets are the backbone of everything. And even the now popular Spring Framework is nothing more than an add-on over the Servlet API. For starters, Spring Framework is a new dependency for our project. So let's add it to the build script in the dependencies block: There is a chapter " 1.1. DispatcherServletcompile 'org.springframework:spring-webmvc:5.1.3.RELEASE' " in the Spring Framework documentation . It says that the Spring Framework is built in the "front controller" pattern - this is when there is a central servlet called " DispatcherServlet ". All requests go to this servlet, and it delegates calls to the necessary components. 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 the context servlet 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. Further, to enable the Spring Framework, you must specify context-param - the context servlet initialization parameter.
<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 have to fill in the file specified in the contextConfigLocation. How to do this is described in the Spring Framework documentation in 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="com.codegym.javaweb"/>
    <mvc:annotation-driven/>
</beans>
It is important here not only to specify which package to scan, but also that we want annotation-driven, that is, to manage annotations, how Spring will work. It remains only to create the com.codegym.javaweb package and place the Spring controller class in it:
package ru.codegym.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 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.
Java web application - 16

Annotations

As we have seen, annotations are handy. And we weren't the only ones who thought so. Therefore, in the Servlet API specification since version 3.0, a chapter " CHAPTER 8 Annotations and pluggability " appeared, which indicates that servlet containers should 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 the @WebServlet annotation can be specified above the servlet classand specify which path to "map" the servlet to. Everything seems to be clear here. But what if we have 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 the WebApplicationInitializer. See chapter " 1.1. DispatcherServlet " for details. It turns out that this is a Spring class. How then is the Servlet API used here? Actually, ServletContainerInitializer was added in Servlet API 3.0 . Using a special mechanism in Java (called SPI ), Spring specifies its servlet container initializer, which is calledSpringServletContainerInitializer. In turn, it already looks for WebApplicationInitializer implementations and calls the necessary methods and performs the necessary settings. See " How servlet container finds WebApplicationInitializer implementations " for details. The above settings can be done like this:
package ru.codegym.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, with the help of " Java-based configuration " we specify which package to scan + enable annotations:
package ru.codegym.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 = "com.codegym.javaweb.controllers")
public class AppConfig {
}
And the SpringController itself was moved to com.codegym.javaweb.controllers, so that when scanning, the configuration would not find itself, but only search for controllers.
Java web application - 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 heart of any Java web application, and we've seen how other frameworks fit into it. To continue, you can look at the following materials: #Viacheslav
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION