Hey everyone and welcome back to Developer Soapbox. In this post, I'd like to share with you some details on how to install and use my new extension, which has some very useful snippets for Spring Boot projects.

Motivation

While Spring Boot is one of my favorite frameworks and has allowed me to be lazy by significantly reducing the amount of setup I have to do, there are still a couple of things which have always bothered me:

  • Boilerplate code, especially for things like controllers and repositories.
  • Having to google JDBC urls every time I need to set up a new database connection.

This extension tries to address that.

What You Need

This extension does require that you already have the following setup:

  • JDK installed (1.8 or later)
  • Visual Studio Code installed

While not required, I also recommend that you install the Spring Initializr extension from Microsoft, which can be found here. This will make project creation significantly easier. If you enjoy my content (which you know you do), I do have a video on how to use that extension here.

Installation

To install the extension, open your Visual Studio Code editor and click on the extensions panel. You can also access this panel with the shortcut Ctrl+Shift+X.

sb-extension_install_select

Once there, search for 'developersoapbox' and this will show you extensions created by yours trully. Select the extension labeled 'Spring Boot Snippets'and click on the 'Install' button. Once installed, simply restart vscode.

sb-extension_header

Usage

Inside of your Spring Boot project, create a new Java file (.java file extension).

REST Controller

To add a controller, simply right-click on the file and start typing 'spring-' and hit ctrl+space for the snippet intellisense to kick in. Select the one labeled 'spring-crudctrl' and you now have a nice controller template with all major CRUD actions implemented. You can tab through the placeholder fields to change each of the values.

package packageName;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/resourceRootPath")
class resourceNameController {

    @Autowired
    repositoryClassName repository;

    @GetMapping
    public ResponseEntity<List<entityClassName>> getAll() {
        try {
            List<entityClassName> items = new ArrayList<entityClassName>();

            repository.findAll().forEach(items::add);

            if (items.isEmpty())
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);

            return new ResponseEntity<>(items, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @GetMapping("{id}")
    public ResponseEntity<entityClassName> getById(@PathVariable("id") entityIdType id) {
        Optional<entityClassName> existingItemOptional = repository.findById(id);

        if (existingItemOptional.isPresent()) {
            return new ResponseEntity<>(existingItemOptional.get(), HttpStatus.OK);
        } else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }

    @PostMapping
    public ResponseEntity<entityClassName> create(@RequestBody entityClassName item) {
        try {
            entityClassName savedItem = repository.save(item);
            return new ResponseEntity<>(savedItem, HttpStatus.CREATED);
        } catch (Exception e) {
            return new ResponseEntity<>(null, HttpStatus.EXPECTATION_FAILED);
        }
    }

    @PutMapping("{id}")
    public ResponseEntity<entityClassName> update(@PathVariable("id") entityIdType id, @RequestBody entityClassName item) {
        Optional<entityClassName> existingItemOptional = repository.findById(id);
        if (existingItemOptional.isPresent()) {
            entityClassName existingItem = existingItemOptional.get();
            System.out.println("TODO for developer - update logic is unique to entity and must be implemented manually.");
            //existingItem.setSomeField(item.getSomeField());
            return new ResponseEntity<>(repository.save(existingItem), HttpStatus.OK);
        } else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }

    @DeleteMapping("{id}")
    public ResponseEntity<HttpStatus> delete(@PathVariable("id") entityIdType id) {
        try {
            repository.deleteById(id);
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED);
        }
    }
}

REST Repository

The repository does not have as much reward as the controller, but will still save you from some typing. Simply start typing 'spring-' and hit ctrl+space for the snippet intellisense to kick in. Select the one labeled 'spring-crudrepo' and the result is a Spring Data repository, which in itself will handle all simple database repository code for you internally.

package packageName;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

//Remove @RepositoryRestResource below to disable auto REST api:
@RepositoryRestResource
public interface repositoryName extends CrudRepository<entityName, entityIdType>{}

Database Configuration Properties

Something I've always struggled with is remembering the url and property names for a specific database to add in my application.properties or application.yaml file. This meant a google search every time. If you have this same issue, fear not. My extension includes property snippets for all of the major databases (postgresql, mysql, oracle, h2, sqlite, sql server).

To use these, open your application.properties file (or application.yaml, which is also supported in the extension), start typing 'spring-' and hit ctrl+space for the snippet intellisense to kick in. Select the snippet for your particular database.

spring.datasource.url=jdbc:mysql://databaseHost:3306/databaseName
spring.datasource.username=username
spring.datasource.password=password
#spring.jpa.hibernate.ddl-auto=update
#spring.jpa.show-sql=true

Your screen now contains all the core necessary properties for the connection. Simply update any placeholders, like for your database name, and you're all set.

Brand New Visual Studio Code Users

If you are brand new to using vscode for Java development, I've got another extension for you. This one is actually an extension pack, which is simply a package full of other useful extensions. It includes a good baseline to get you started and can be found by searching the extension panel in vscode for 'developersoapbox' and installing the extension labeled 'Spring Boot Developer Extension Pack'.

Conclusion

I hope you find this extension useful. I had tons of fun learning about vscode extension development while building this, and will hopefully have more useful extensions for you soon.