Java Spring Rest does not work with separate packages

Asked

Viewed 105 times

1

Personal my spring Rest application only works when I put the classes(models,controllers) all in the same application class package, this way it works but imagine the disorganization of it !!

https://i.stack.Imgur.com/Fyiav.png

*This way it does not work, the server goes up to port 8080 but does not return my method, only if I put the controller inside the application package

CONTROLLER

package com.camila.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClienteController {
    @GetMapping("/clientes")
    public String listar() {
        return "TESTE ";
     }
}

APPLICATION

package com.camila.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

POM.XML

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <groupId>com.camila.web</groupId>
    <artifactId>Spring_API</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Spring_API</name>
    <description>Demo project for Spring Boot</description>
    
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.1</spring-cloud.version>
    </properties>
    
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>dev.miku</groupId>
            <artifactId>r2dbc-mysql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.r2dbc</groupId>
            <artifactId>r2dbc-h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • Thanks for the tip, the site has already helped me a lot to solve other problems but never actually asked question here

  • only this with a command to change the port "server.port = 8090"

1 answer

2


In accordance with the spring boot documentation the annotation @SpringBootApplication, among other things, defines the root of the application. That is, by convention the class annotated with @SpringBootApplication should be in the most external package of the class hierarchy of your application.

In practice the annotation @SpringBootApplication "tag" the application package (as well as all packages within that package) to be scanned for annotated Spring components.

Weighing that your class SpringApiApplication is in the package com.camila.web Spring Boot can find components inside any subcase of com.camila.web, for example:

  • com.camila.web
  • com.camila.web.controller
  • com.camila.web.meupacote.meuoutropacote

Like ClienteController is not inside the package com.camila.web Spring Boot doesn’t know how to find him.

A solution to your problem, which respects the Spring Boot convention without making a mess, is to move the package controller into com.camila.web.

package com.camila.web.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClienteController {
    @GetMapping("/clientes")
    public String listar() {
        return "TESTE ";
     }
}

Note that you can organize your components as and in as many packages as you want without breaching the Spring Boot convention, as long as all packages are inside com.camila.web.

If you really need to use components in other packages, the annotation @SpringBootApplication has optional elements scanBasePackages and scanBasePackageClasses used to make Spring Boot search for components in other packages. For example, considering your current package structure you could modify the class SpringApiApplication as follows:

package com.camila.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = {"com.camila.controller", "meu.outro.pacote"})
public class SpringApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringApiApplication.class, args);
    }
}

With that your class ClienteController, as well as any other components in the packages com.camila.controller and meu.outro.pacote are found by Spring.

Reading the Springbootapplication class code it is clear that all this "magic" happens because the note @SpringBootApplication is in turn noted with the annotation @ComponentScan (this is an example of meta annotation). Consequently the annotation @ComponentScan can also be used directly to get the same result:

@ComponentScan(basePackages = {"com.camila.controller", "meu.outro.pacote"})

That said, it is recommended to follow the Spring conventions to avoid having to make unnecessary manual settings. For example, if you come to work with JPA, Spring Boot automatically detects entities and repositories within your root package. If your entities are not inside the root package you will need to use @EntityScan to indicate to Spring where to find its entities and @EnableJpaRepositories to indicate where to find the repositories. This principle is called Configuration convention and is especially valid in Opinionated frameworks like Spring Boot.

  • Anthony, thank you very much for the time, the information you provide helps a lot. But it looks strange, when I click on the com.camila.web and ask to create another package, which would be a subpackage of the same, it creates one inside of com.camila.web as planned and one outside as if it were a mirror, good testing again still does not work , will I am creating sub package the wrong way, follows picture

  • I did it ! It was this way that I explained kind of "mirroring" and after some reboots worked out (will understand ne rs), thank you very much for the help!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.