BlogContacts
BlogGamesContacts

{{item}}

Spring Boot sample

07.08.2018

Java, Spring Boot, Servlet

GitHubSource code
Create one REST controller, several servlets and a custom error handling mechanism.As you know, many Java technologies such as JSP, JSF, JAX-RS are based on generic servlets, and Spring Boot is no exception. In our web-application, we'll create one REST controller, several servlets and our own error handling mechanism - all of which, one way or another, under the hood contains servlets. So we're writing Hello World on Spring Boot..1. Project structure:
spring-boot-sample
│
├── src
│   └── main
│       ├── java
│       │   └── sample
│       │       ├── . . .
│       │       ├── . . .
│       │       ├── . . .
│       │       └── Application.java
│       └── resources
│           ├── templates
│           │   ├── . . .
│           │   ├── . . .
│           │   └── . . .
│           └── application.properties
└── pom.xml
2. Required Maven dependencies: pom.xml
XML
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>spring-boot-sample</groupId>
    <artifactId>spring-boot-sample</artifactId>
    <name>spring-boot-sample</name>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.plugin.version>3.8.0</maven.compiler.plugin.version>
        <spring.boot.version>2.0.4.RELEASE</spring.boot.version>
    </properties>

    <build>
        <defaultGoal>package</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>
</project>
2. Application settings: application.properties
server.port=8080
server.compression.enabled=true
Now let's create the main application file. Spring Boot under the hood has an Embedded Servlet Container (Tomcat by default)- no additional Stand Alone Application Server is needed, so our web-application will be compiled into a jar file with all necessary dependencies and will run with java -jar command.The main feature of Spring Boot is that it looks at those beans that we have configured or overridden, looks for what we have missed and adds these beans on its own. In order to view all of those beans, which Spring Boot loads during initialization process of our web-application, we'll add bean CommandLineRunner in the main method.The standard error handler in Spring Boot, which we'll need to override, is a bean BasicErrorController.3. The main class of the web-application: Application.java
Java
package sample;

@SpringBootApplication
@ServletComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return new CommandLineRunner() {
            @Override
            public void run(String... args) {

                System.out.println("Inspecting the beans provided by Spring Boot:");
                System.out.println("---------------------------------------------");
                String[] beanNames = ctx.getBeanDefinitionNames();
                Arrays.sort(beanNames);
                int i = 0;
                for (String beanName : beanNames) {
                    System.out.println(++i + ". " + beanName);
                }
            }
        };
    }

    @Bean
    public BasicErrorController basicErrorController() {
        return new CustomErrorController(new DefaultErrorAttributes(), new ErrorProperties());
    }
}
Annotation @ServletComponentScan is needed for Embedded Servlet Container to create beans from classes, marked with annotations @WebServlet,@WebFilter,@WebListener. This is a specific of Spring Boot, because Stand Alone Application Server does it automatically.4. Add a custom error handler class: CustomErrorController.java
Java
package sample.controller;

public class CustomErrorController extends BasicErrorController {
    public CustomErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        super(errorAttributes, errorProperties);
    }

    @Override
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        String value = String.valueOf(status.value());
        String reasonPhrase = status.getReasonPhrase();

        try {
            response.getWriter()
                .write(PageConstructor.constructErrorPage("/templates/error.html", value, reasonPhrase));
        } catch (IOException e) {
            return super.errorHtml(request, response);
        }
        return null;
    }
}
5. Now let's create a REST Controller: MainController.java
Java
package sample.controller;

@RestController
public class MainController {
    @RequestMapping({"/", "/index.html"})
    public String index() throws IOException {
        InputStream is = HelloSpace.class.getResourceAsStream("/templates/index.html");
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");

        StringWriter sw = new StringWriter();

        int read;
        while ((read = isr.read()) != -1) {
            sw.write(read);
        }

        return sw.toString();
    }
}
Create servlets - we'll have three of them, which will greet the world, space and the universe.. Therefore the logical beginning for this triad is an abstract class, that unites the common methods of our servlets.6. Abstract class: AbstractServlet.java
Java
package sample.servlet;

public abstract class AbstractServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doResponse(response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doResponse(response);
    }

    abstract void doResponse(HttpServletResponse response) throws IOException;
}
Focus on the doResponse method and compare it to the method index of our REST controller. In response, it will return one greeting line, so there will be one template for all three servlets. The error handler servlet template is built in the same way.7. Servlet template: hello.html
HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello <--greeted--></title>
</head>
<body>
    <p>Hello <--greeted-->!!</p>
</body>
</html>
Accordingly, it would be logical to have a constructor for all three servlets and for errors handling.8. Constructor: PageConstructor.java
Java
package sample.constructor;

public class PageConstructor {

    public static String constructHelloPage(String template, String greeted) throws IOException {
        InputStream is = HelloSpace.class.getResourceAsStream(template);
        InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);

        StringWriter sw = new StringWriter();

        int read;
        while ((read = isr.read()) != -1) {
            sw.write(read);
        }

        return sw.toString().replace("<--greeted-->", greeted);
    }

    public static String constructErrorPage(String template, String value, String reasonPhrase) throws IOException {
        InputStream is = HelloSpace.class.getResourceAsStream(template);
        InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);

        StringWriter sw = new StringWriter();

        int read;
        while ((read = isr.read()) != -1) {
            sw.write(read);
        }

        return sw.toString()
                 .replace("<--value-->", value)
                 .replace("<--reasonPhrase-->", reasonPhrase);
    }
}
For example, consider one servlet - the others look almost the same.9. Servlet: HelloWorld.java
Java
package sample.servlet;

@WebServlet(urlPatterns = "/hello-world.html")
public class HelloWorld extends AbstractServlet {
    @Override
    void doResponse(HttpServletResponse response) throws IOException{
        response.getWriter()
                .write(PageConstructor.constructHelloPage("/templates/hello.html", "World"));
    }
}
Everything is ready - it may be run. See the entire code of this web-application.
Privacy policy
Back to Top