How I use Spring Initializr

2020-05-19

Create boilerplate project

Unpack project

Open a terminal and go to your source code directory and unzip the downloaded file:

unzip ~/Downloads/myapp.zip
cd myapp/
git init
git add .
git config user.email me@email.org
git commit -m 'Initial commit'
git clean -fxd

Open project in IntelliJ

Fix name of application class

Rename the main application to give it a less crappy name:

Commit the changes to Git:

git add .
git commit -m 'Rename application class'

Replace its content with the following:

package org.rcook.myapp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@SpringBootApplication
@EnableWebMvc
public class App {
    public App() {
    }

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

Now fix the name of the run configuration:

Add application-level configuration

Create a primary configuration class:

Update the content to the following:

package org.rcook.myapp;

import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
}

Create an MVC landing page

Set its content to the following:

package org.rcook.myapp;

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

@Controller
public class HomeController {
    @RequestMapping("/")
    @ResponseBody
    public String index() {
        return "Hello world";
    }
}

Create a REST API

Set its content to the following:

package org.rcook.myapp;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

import static java.util.Arrays.asList;

@RestController
@RequestMapping("/widgets")
public class WidgetController {
    @RequestMapping("")
    public HashMap<String, Object> getWidgets() {
        return new HashMap<>() ;
    }

    @RequestMapping("/{id}")
    public HashMap<String, Object> getWidget(@PathVariable int id) {
        return new HashMap<>() ;
    }
}

Run the application

Note that the random security password will change on each launch of the app.

Use YAML application properties

Enter some configuration like the following:

db0db:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driverclassname: org.postgresql.Driver
    jdbcurl: jdbc:postgresql://localhost:5432/db0
    username: postgres
    password: mysecretpassword
    leakdetectionthreshold: 10000

Update controller

Replace AppConfig.java with:

package org.rcook.myapp;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class AppConfig {
    @Bean(name = "db0DataSource")
    @ConfigurationProperties(prefix = "db0db.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
}

Replace WidgetController.java with:

package org.rcook.myapp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/widgets")
public class WidgetController {
    @Autowired
    @Qualifier("db0DataSource")
    @SuppressWarnings("initialization.fields.uninitialized")
    private DataSource db0DataSource;

    @RequestMapping("")
    public List<Object> getWidgets() {
        try (final var connection = db0DataSource.getConnection();
             final var stmt = connection.createStatement();
             final var resultSet = stmt.executeQuery("SELECT id, name FROM widgets")) {
            final var widgets = new ArrayList<>();
            while (resultSet.next()) {
                widgets.add(new HashMap<String, Object>() );
            }
            return widgets;
        } catch (final SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @RequestMapping("/{id}")
    public HashMap<String, Object> getWidget(@PathVariable int id) {
        try (final var connection = db0DataSource.getConnection();
             final var stmt = connection.prepareStatement("SELECT id, name FROM widgets WHERE id = ?")) {
            stmt.setInt(1, id);
            try (final var resultSet = stmt.executeQuery()) {
                resultSet.next();
                return new HashMap<String, Object>() ;
            }
        } catch (final SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

Enable more warnings and Checker Framework

Add the following to the end:

checkerFramework {
    checkers = [
            'org.checkerframework.checker.nullness.NullnessChecker'
    ]
}

javadoc {
    options.addStringOption('Xdoclint:all', '-Xwerror')
}

compileJava {
    //options.compilerArgs << "-Astubs=${project.file('stubs')}"
    options.compilerArgs << '-Xlint:unchecked'
    options.compilerArgs << '-Werror'
}

compileTestJava {
    //options.compilerArgs << "-Astubs=${project.file('stubs')}"
    options.compilerArgs << '-Xlint:unchecked'
    options.compilerArgs << '-Werror'
}

Tags

Spring
Java

Content © 2010–2020 Richard Cook. All rights reserved.