Dario Venneri

From Laravel to Spring Boot: overview to start quickly

Oct 20th 2024

If you are curious about trying Spring Boot but you only have experience in Laravel this article may help you start faster than ever. This is not a tutorial but a very short overview with a little code to get you a controller and a mysql db connection. At the end of the articles you will also find one article and some video that will be really helpful to you as an absolute beginner.

To create a Spring Boot app you go on https://start.spring.io/, give a name to your project, add the dependencies you need (as a beginner, use maven) and you're good to go.

As beginner Spring Boot webdev and for the purpose of this article the dependecy to start are Spring Web, jdbc and the mysql driver.

Routes

Anything you put into src/main/resources/static will be served directly, so if you add a static about.html it will be returned at localhost:8080/about.html. If you want something like Blade there is Thymeleaf, but to be honest I've used Spring Boot as a backend for SPAs.

To have a route you create a class. For example let's say you are serving informations about cats, you can create a CatController class, then you put the @Controller or the @RestController annotation.

You use @Controller when you want to return a view to be resolved by Thymeleaf (or colleagues), otherwise you use @RestController for your REST endopoints. You then put annotations like @GetMapping("/photoz") (for GET requests), @PostMapping("/photoz") (for POST requests), etc on top of the methods you want to be invoked when the user reaches a certain route.

@RestController
public class CatController {

    @GetMapping("/cats")
    public String getCats() {
        //...
    }

    @PostMapping("/photoz")
    public String postCat() {
        //...
    }
}

What should methods of @RestController return?

You could return an object directly and it will be turned into json, but to make things more clean and have more consistency when you want to return a different status code or header, etc you want to use the ResponseEntity class. So your method may look like this:

    @GetMapping("/photo")
    public ResponseEntity<Cat> getOneCat() {
        Cat cat = new Cat();
        return ResponseEntity.ok(Cat);
    }

What about the Models and the Database?

In Laravel you use eloquent as ORM to connect to a database and Laravel will do a lot of magic to match your models and the tables in your database, pull out the columns, etc

In Spring Boot you build your models just by creating a class and then there are many ways to interact with the database.

  • JDBC: it's APIs with drivers to connect and query a database, inlcuding raw queries
  • JPA: it's a Java standard to follow to write ORM. Hibernate for example is then an actual ORM and an implementation of JPA
  • Spring Data: it builds on top of ORMs like Hibernate providing extra stuff

For a very beginner I recommend Spring Data JDBC (which must be added as a dependency in Maven), it's the option with less abstractions and much easier for a beginner. As a Laravel dev you may have familiarity with MySQL, so consider adding the MySQL Driver in the dependencies. When you add dependencies in the maven's pom.xml file your IDE will probably complain. You need to update your dependencies once you added them into the file, there should be a button (or just restart the IDE). Then inform your application on how to connect to MySQL by adding these lines in the application.properties file:

spring.datasource.url=jdbc:mysql://localhost:3306/cats_app_database_name
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

In many tutorials you may hear about H2 Database. It's a very simple in memory SQL database with a web interface. If you can immediately use another database, like MySQL, Postgres or whatever, I think you are already in a much better position than if you were to use H2. Just know it exists.

Assuming a table messages exists, the rawest way to now query the database is something like this:

@RestController
public class ExampleController {

    private JdbcTemplate jdbcTemplate;

    public ExampleController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @GetMapping("hello")
    public ResponseEntity<List<Map<String, Object>>> getHelloMessage() {
        List<Map<String, Object>> messages = jdbcTemplate.queryForList("SELECT * FROM messages");
        return ResponseEntity.ok(messages);
    }
}

In this controller first we inject the jdbc client into the controller via its constructor public ExampleController(JdbcTemplate jdbcTemplate), then we perform the raw query and get back the results using jdbcTemplate.queryForList("SELECT * FROM messages");

By the way with List<Map<String, Object>> I've been very explicit but you can actually just use var if you feel like it, so you could end up doing something like var messages = jdbcTemplate.queryForList("SELECT * FROM messages");

Models

Spamming Object and raw sql queries may not be not productive even for your short term beginner experiments so you may want a model and a better way to query the db. To create a model just create a class:

public class Cat {
    Integer id;
    String name;
    String breed;
    String ownerName;
}

you now have a Cat.java, it is already a model but you probably want to make it match with a table in your db.

Here is the thing. If you were using Spring Data JPA you would be able (but not required) to create the tables and the columns based on the model when the app first boots. I think it's premature as a beginner to follow this way and it's better to just create the tables yourself and then connect the model and the database manually.

To now have Cat interact with a table in the database with the columns id, name, breed and owner_name you use @Table() on top of the class, the @Id annotation on the id and then @Column on the other properties

// warning: no getters and setters defined
@Table("cats")
public class Cat {
    @Id
    Integer id;

    @Column("name")
    String name;

    @Column("breed")
    String breed;

    @Column("owner_name")
    String ownerName;
}

FYI we're being as explicit as possible in this article, using @Column and @Table be skipped in other cases.

Now that we have the Cat model we use a repository to have a clean way to reach the table in the DB. We create an interface, we call it CatRepository and we make it extends CrudRepository. With extending CrudRepository we're using Spring Data JDBC and it will give us some methods to query the table later. We also need to add the @Repository annotation so Spring will pick up the interface

@Repository
public interface CatRepository extends CrudRepository<Cat, Integer> {
}

The model and lombok

If you were to use the Cat model as I've written it now you would not be able to get the data. In Java having to define all getters and setters for properties is a given. The boilerplate code can be generated by your IDE or you can use lombok. Lombok is a dependency you can add and it gives you a set of annotations (like @AllArgsConstructor, @Getter, @Setter) you can use on top of your class so that constructors, getters and setters are generated automatically for you. Having to learn yet another thing may feel cumbersome, but it's gonna require 10 minutes and it's great to speed up your beginner journey. Otherwise just use your IDE option to generate constructor, getters and setters.

Migrations

Flyway or Liquibase are the recommended way to manage migrations in Spring Boot and they are a beast on their own. There is a simple but not clean way to have migration by creating a schema.sql and/or a data.sql file in the resources folder and then adding spring.sql.init.mode=always in the application.properties file. This way every time the app is booted the two sql files will run. Of course by always running they can incur in an error and stop your application from booting, for example if you try to create a table that already exists without setting the proper SQL command for this case. So this options feels more useful as a pedagogical tool than anything more.

schema.sql:

CREATE TABLE IF NOT EXISTS `cats` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `breed` VARCHAR(255) NOT NULL,
    `owner_name` VARCHAR(255) NOT NULL,
    PRIMARY KEY (`id`)
);

Dependency injection with @Autowired vs constructor

When you need to inject a dependency into your class in Spring Boot you can either use @Autowired or the constructor injection. For a beginner they have the same effect, for more expert users the there is a discussion on constructor injection vs @Autowired and personally I also prefer using constructor injection in all cases.

Using @Autowired:

public class CatService { @Autowired private CatRepository catRepository; }

Constructor injection:

public class CatService { private final CatRepository catRepository;

public CatService(CatRepository catRepository) {
    this.catRepository = catRepository;
}

}

(you may have noticed that I could not made the property final when using @Autowired)

Don't forget @Service

put the @Service annotation on top of your service so that the class is picked up automatically by the framework and ready to be injected wherever you want, for example your controller:

@Service
public class CatService {
    private final CatRepository catRepository;

    public CatService(CatRepository catRepository) {
        this.catRepository = catRepository;
    }

    public Iterable<Cat> getAllCats() {
        return catRepository.findAll();
    }
}

Rest Controller:

@RestController
public class CatController {

    private final CatService catService;

    public CatController(CatService catService) {
        this.catService = catService;
    }

    @GetMapping("cats")
    public ResponseEntity<Iterable<Cat>> getAllCats() {
        return ResponseEntity.ok(catService.getAllCats());
    }
}

Here's a few cats you can add on the fly in your db for testing purposes:

INSERT INTO `cats` (`name`, `breed`, `owner_name`) VALUES
    ('Whiskers', 'Maine Coon', 'Alice'),
    ('Mittens', 'Siamese', 'Bob'),
    ('Shadow', 'Persian', 'Charlie'),
    ('Luna', 'Bengal', 'Daisy');

More resources:

There are a lot of resources for Spring and Spring Boot out there but the following are the ones I wish I had at the start of the journey because they don't have any fluff, they practical and with the right level of detail.

Introductory Video

Articles

Books

Use this book as a starting point: Spring Start Here: Learn what you need and learn it well by Laurentiu Spilca