JavaRush /Java Blog /Random EN /From Hello World to Spring Web MVC and what does servlets...
Viacheslav
Level 3

From Hello World to Spring Web MVC and what does servlets have to do with it

Published in the Random EN group
From Hello World to Spring Web MVC and what does servlets have to do with it - 1

Introduction

As we know, Java's success came precisely thanks to the evolution of software that strives to connect to the network. Therefore, we will take the usual console application “ Hello World ” as a basis and understand what it needs to become a network application from a console application. So, first you need to create a Java project. Programmers are lazy people. In prehistoric times, when some were hunting mammoths, others sat and tried not to get confused in the whole variety of Java libraries and directory structures. So that the developer can control the process of creating an application, so that he can simply write “I want a library of such and such version 2,” they came up with special tools - build systems. The two most famous ones are Maven and Gradle . For this article we will use Gradle. If earlier we would have had to create the directory structure ourselves, now Gradle, using the Gradle Init Plugin, allows us to create a Java project with a directory structure and a base Main class in one command: gradle init --type java-application This command performs initialization (init) for us a Java application (java-application ) with console Hello World. After completion, a file will appear in the directory - build.gradle . This is our build script - that is, a certain script for creating an application with a description of what actions need to be performed for this. Let's open it and add the line to it: jar.baseName = 'webproject' Gradle allows you to perform various actions on a project and these actions are called tasks . By executing a command (task) a JAR file will be created gradle buildin the /build/libs directory . And, as you guessed, its name will now be webproject.jar . But if we execute java -jar ./build/libs/webproject.jar, we will get an error: no main manifest attribute. This is because for a java application you need to attach a manifest - this is a description of how to work with the application, how to perceive it. Then the JVM, which will execute the java application, will know which class is the entry point to the program and other information (for example, classpath). If we take a closer look at the contents of the build script, we will see the plugins being connected. For example: apply plugin: 'java' If we go to the Gradle Java Plugin page , we can see that we can configure the manifest:
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
The main class, the entry point to the program, was generated for us by Gradle Init Plugin. And it is even specified in the mainClassName parameter. But this did not suit us, because... this setting refers to another plugin, Gradle Application Plugin . So, we have a Java application that displays Hello World on the screen. This Java application is packaged in a JAR (Java ARchive). It is simple, console-based, not up-to-date. How to turn it into a web application?
From Hello World to Spring Web MVC and what does servlets have to do with it - 2

Servlet API

In order for Java to be able to work with the network, a specification called Servlet API appeared back in ancient times . It is this specification that describes client-server interaction, receiving a message from a client (for example, a browser) and sending a response (for example, with the text of a page). Naturally, a lot has changed since then, but the point is that in order for a Java application to become a web application, the Servlet API is used. In order not to speculate unfoundedly, let’s pick up that very specification: JSR-000340 JavaTM Servlet 3.1 . First of all, we are interested in " Chapter 1: Overview ". It describes the basic concepts that we must understand. Firstly, what is a servlet? The chapter " 1.1 What is a Servlet? " says that a Servlet is a Java component that is managed by a container and that generates dynamic content. Like other Java components, a servlet is a Java class that is compiled into bytecode and can be loaded into a web server using Java technology. It is important that servlets interact with a web client (for example, a browser) within the framework of the request/response paradigm, which is implemented by the Servlet Container. It turns out that Servlets live in some kind of Servlet Container. What is this? In the chapter " 1.2 What is a Servlet Container? " it is said that a Servlet Container is some part of a web server or application server that provides network services through which requests are sent and responses are sent. This very Servlet Container manages the life cycle of servlets. All Servlet Containers are required to support the HTTP protocol at a minimum, but may support others. For example, HTTPS. It is also important that the Servlet Container can impose any security-related restrictions on the environment in which servlets are executed. It is also important that according to “ 10.6 Web Application Archive File ” the web application must be packaged in a WAR (Web ARchive) file. That is, now we need to remove our jar and application plugins for something else. And this is the Gradle WAR plugin . And instead of jar.baseName specify war.baseName Because Since we no longer use the jar plugin, we have also removed the manifest settings. When we launched the JAR, the Java Virtual Machine (JVM) needed to be told through the manifest how to work with our application. Because the JVM was running it. The web application, apparently, is executed by some kind of web server. It turns out that he needs to somehow tell him how to work with our web application? And it turns out that yes. Web applications have their own special manifesto. It's called Deployment Descriptor . A whole section is dedicated to it: “ 14. Deployment Descriptor ”. There is an important section: " Chapter 10:". It talks about what a web application is from the point of view of the Servlet API. For example, in the chapter " 10.5 Directory Structure " it is indicated where the Deployment Descriptor should be: /WEB-INF/web.xml. Where to place the WEB-INF? As stated in the Gradle WAR plugin , it adds a new layout : src/main/webapp. Therefore, let's create such a directory, inside we will create a WEB-INF directory, and inside we will create a web.xml file. It is important that the directory is called WEB-INF, and not META-INF! Let's copy it from " 14.5.1 A Basic Example " XML example:
From Hello World to Spring Web MVC and what does servlets have to do with it - 3
As we can see, an XML document is used for configuration. An XML document, in order to be considered valid (Valid), must conform to some “schema”. You can think of this as a kind of interface for an XML document. The schema specifies what elements can be in an XML document, what type of data can define the element, order, requirement, and other aspects. The example copied from the documentation indicates version 2.5, but we want to use version 3.1. Naturally, the specification changed as versions changed, and new features were added. Therefore, you need to use a schema other than the one used for version 2.5 (web-app_2_5.xsd). What scheme should I use for version 3.1? The documentation will help us with this, chapter “ 14.3 Deployment Descriptor ”, which states specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd That is, we need to replace the link to the schema with the specified xsd everywhere, not forgetting to change it version="2.5"to 3.1, and also change the namespace everywhere (xmlns and in xsi:schemaLocation). They indicate within which namespace we will work (to put it very simply, what element names we can use). If you open the schema file, the targetNamespace will contain the same namespace that we should specify:
From Hello World to Spring Web MVC and what does servlets have to do with it - 4
As we remember, in the Manifest of the Jar file we wrote which class we want to use. What to do here? Here we need to specify which servlet class we want to use when we receive a request from a web client. The description can be read in the chapter " 14.4 Deployment Descriptor Diagram ". It will look like this:
From Hello World to Spring Web MVC and what does servlets have to do with it - 5
Everything is simple here. The serverlet is declared, and then it is mapped to a certain template. In this case, on /app. When the template is executed, the servlet method will be executed. For beauty, the App class should be transferred to the package, not forgetting to correct the xml configuration. But that's not all. App must be a servlet. What does it mean to be a servlet? This means that we must inherit from HttpServlet . An example can be seen in the chapter " 8.1.1 @WebServlet ". According to it, our App class will look like this:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("text/html");
		try {
			response.getWriter().println(getGreeting());
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}
}
But our project is not ready yet. Because we now depend on Servlet API version 3.1. This means that in our build script we need to indicate a dependency on the Servlet API. The JVM needs to know that what you wrote in the code is correct and how to use it. As we remember, the specification is essentially just interfaces that describe how it all should work. And the implementations lie on the web server side. Therefore, without the Servlet API there will be a Find the required library on Maven Central: javax.servlet-api . And add an entry to the dependencies block . In the Maven repository, as you saw, it says provided. Before using a dependency, you must specify scope. Gradle doesn't have a scope named "provided", but it does have a " compile only " scope. Therefore, we will indicate: providedCompile 'javax.servlet:javax.servlet-api:3.1.0' Ugh, everything seems to be all right? Gradle Build will build our project into a WAR file. And what should we do next with it? First, we need a Web Server. In Google we write “ web server java list ” and see a list of web servers. Let's choose from this list, for example, TomCat . Go to the Apache Tomcat website , download the latest version (currently version 9) as a zip archive (if for Windows). Unpack it into some directory. Hurray, we have a web server. From the web server directory in the bin subdirectory, we execute catalina from the command line and see the available options. Let's do: catalina start. Each web server has a directory that the web server monitors. If a web application file appears there, the web server begins to install it. This installation is called deployment or deployment . Yes yes, that's why " deployment descriptor ". That is, how to properly deploy the application. In Tomcat this directory is webapps . Let's copy the war that we made using gradle build there. After this, in the log we will see something like: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms To understand even better, in the tomcat directory we will edit the file \conf\tomcat-users.xml, adding the following lines:
From Hello World to Spring Web MVC and what does servlets have to do with it - 6
Now we restart the server (catalina stop, catalina start) and go to the address. http://127.0.0.1:8080/manager Here we will see the paths of all applications. Our webproject was most likely given the path /webproject. What is this path? The specification in the chapter " 10.1 Web Applications Within Web Servers " states that a web application is associated with some path within the application (in this case, /webproject). All requests through this path will be associated with the same ServletContext. This path is also called contextRoot . And according to " 10.2 Relationship to ServletContext ", the servlet container relates the web application and the ServletContext one to one. That is, each web application has its own ServletContext. What is a ServletContext ? As the specification states, a ServletContext is an object that provides servlets with a “view of the application ” in which they are running. Servlet Context is described in more detail in Chapter 4 of the Servlet API specification. Surprisingly, the Servlet API in version 3.1 no longer requires web.xml to be present. For example, you can define a servlet using annotations:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/app2")
public class App2 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.getWriter().println("app2");
    }
}
Also recommended on the topic: " Java EE Interview - JEE Servlet API (Questions and Answers) ". So, we have a Servlet - it is responsible for what response to give to the web client. We have a ServletContainer that receives requests from the user, matches the path that was accessed with the path to the servlet, and if a match is found, executes the Servlet. Fine. What place does Spring occupy in this picture of the world ?

Spring Web MVC

Great, we have a web application. Now we need to connect Spring. How can we do this? First, you need to figure out how to properly connect Spring to your project. It turns out that earlier it was possible to do this in accordance with the documentation of the Spring platform project , but now “ The Platform will reach the end of its supported life on April 9, 2019 ”, that is, it is not advisable to use it, because it will soon no longer be supported. The only way out is " Users of the Platform are encouraged to start using Spring Boot's dependency management ". Therefore, let's move on to the Spring Boot documentation . Let me clarify that we do not use Spring Boot itself, but only Dependency Management from Spring Boot. That is, the Spring Boot project can provide knowledge about which versions of libraries to use (including Spring MVC). There we will find 3.2. Using Spring Boot's dependency management in isolation . According to the documentation, add the following to the build script:
plugins {
    id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
And
dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}
As you can see, we indicated apply false, i.e. We don’t use Spring Boot itself, but we use dependency management from there. This dependency management is also called BOM - " Bill Of Materials ". Now we are ready to connect the Spring Web MVC project itself. Spring Web MVC is part of the Spring Framework project and we are interested in the " Web Servlet " section. Let's add the dependency to the build script: compile 'org.springframework:spring-webmvc'. As we can see, we set scope compile, because the web server doesn't provide us with Spring. Our project is forced to include the Spring library inside itself. Next, it is important for us to read the section " 1.2. DispatcherServlet ", where it is said that Spring MVC is built around the " Front controller " pattern, where there is some kind of central servlet that provides configuration and delegation to other components. Dispatcher can be translated as dispatcher. So, first of all, in web.xml we declare:
From Hello World to Spring Web MVC and what does servlets have to do with it - 7
As we can see, this is actually a regular Listener defined in the Servlet API specification. To be more precise, this is a ServletContextListener, that is, it is triggered to initialize the Servlet Context for our web application. Next, you need to specify a setting that will tell Spring where its special xml config with settings is located:
From Hello World to Spring Web MVC and what does servlets have to do with it - 8
As you can see, this is just a regular setting that is stored at the Servlet Context level, but which will be used by Spring when initializing the Application Context. Now you need to declare, instead of all servlets, one single dispatcher that distributes all other requests.
From Hello World to Spring Web MVC and what does servlets have to do with it - 9
And there is no magic here. If we look, it's an HttpServlet, just where Spring does a lot of things that make it a framework. All that remains is to correlate (map) a specific URL template with the servlet:
From Hello World to Spring Web MVC and what does servlets have to do with it - 10
Everything is as we did before. Now let's create something that our web server should display. For example, let's create a pages subdirectory in our WEB-INF, and there will be a file hello.jsp. The content can be the most primitive. For example, inside html tags there is an h1 tag with the text " Hello World ". And don’t forget to create the file applicationContext.xmlthat we specified earlier. Let's take an example from the Spring documentation: " 1.10.3. Automatically detecting classes and registering bean definitions ".
From Hello World to Spring Web MVC and what does servlets have to do with it - 11
Because we enable autodetection in this way, we can now create 2 classes (they will be considered Spring Beans due to the use of special Spring annotations), which Spring will now create itself and customize our application with their help:
  1. Web configuration for example Java style configuration:

    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            registry.jsp("/WEB-INF/pages/", ".jsp");
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    }

    This example is described in the Spring Framework documentation: " 1.11. MVC Config ".

    Here we register a ViewResolver, which will help determine where the jsp pages are located. The second method ensures that the " Default servlet " is enabled.

    You can read more about this here: " What is the need and use of default-servlet-handler ".

  2. HelloController controller for describing the mapping of requests to a specific JSP

    @Controller
    public class HelloController {
        @GetMapping("/hello")
        public String handle(Model model) {
            return "hello";
        }
    }

    Here we have used the @Controller annotation described in the documentation in the chapter " 1.4. Annotated Controllers ".

Now, when our application is deployed, when we send a request /webproject/hello(where /webproject is the context root), the DispatcherServlet will be processed first. He, as the main dispatcher, will determine that we /* matches the current request, which means that the DispatcherServlet must do something. Then it will go through all the mappings it finds. It will see that there is a HelloController with a handle method that is mapped to /hello and will execute it. This method will return the text "hello". This text will be received by the ViewResolver, which will tell the server where to look for the jsp files that need to be displayed to the client. Thus, the client will ultimately receive that very cherished page.

Conclusion

I hope it will be clear from the article that the word “context” is not scary. That specifications turn out to be very useful. And documentation is our friend, not our enemy. I hope it will be clear what Spring is based on, how it connects, and what the Servlet API has to do with it.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION