22

I am starting to learn Spring Boot. I am struggling to find an example with multiple RestControllers, which indicates to me that I may be doing something wrong. I am trying a very simple example: The goal is to make calls like the following:

localhost:8080/
localhost:8080/employees/bob
localhost:8080/departments

I can only get localhost:8080/ to display. The other calls return response: This application has no explicit mapping for /error, so you are seeing this as a fallback.

com.demo.departments
Department.java
DepartmentController.java

com.demo.employees
Employee.java
EmployeeController.java

com.demo
BootDemoApplication.java

Code:

package com.demo.departments
@RestController
@RequestMapping("/departments")
public class DepartmentController {


@RequestMapping("")
public String get(){
    return "test..";

}

@RequestMapping("/list")
public List<Department> getDepartments(){
    return null;

}

}
--------------------------------------------------------------------
package com.demo.employees
@RestController
@RequestMapping("/employees")
public class EmployeeController {

Employee e =new Employee();

@RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
public Employee getEmployeeInJSON(@PathVariable String name) {

 e.setName(name);
 e.setEmail("[email protected]");

 return e;

}
}
-----------------------------------------------------------------------

package com.demo
@RestController
@SpringBootApplication

public class BootDemoApplication {

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

@RequestMapping("/")
String home(){
    return "<html> This is the home page for Boot Demo.</html>";
}
11
  • I don't think you need the preceeding "/" on the top level controller mappings. Commented May 22, 2016 at 5:57
  • I tried it, it didn't make a difference. Commented May 22, 2016 at 6:06
  • This should work (tested it out). You didn't provide any controller for http://localhost:8080/ though, so perhaps the mistake is there. Commented May 22, 2016 at 12:16
  • 1
    You are returning JSON, but aren't requesting it (the browser expect HTML) so no method for handling the request is found. Commented May 22, 2016 at 14:16
  • Yes I am, Employee is a POJO. Its not calling any of the code in the other 2 classes in the debugger. It complains about mapping, not about results. Commented May 22, 2016 at 15:14

8 Answers 8

27

I'm trying Spring Boot and got same problem, and just fixed it, I post my solution here because I think it maybe helpful for someone.

First, put application class ( which contain main method) at the root of controllers's package:

com.example.demo
              |
              +-> controller
              |      |
              |      +--> IndexController.java
              |      +--> LoginController.java
              |
              +-> Application.java

Application.java

package com.example.demo;

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

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

Spring will scan all the components of sub-packages of demo package

IndexController.java (return index.html view)

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping(value = {""})
public class IndexController {

    @GetMapping(value = {""})
    public ModelAndView index() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("index");
        return modelAndView;
    }

}

LoginController.java (return login.html view)

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping(value = {"/login"})
public class LoginController {
    @GetMapping(value = {""})
    public ModelAndView login() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("login");
        return modelAndView;
    }
}

And now I can enter Index view : http://localhost:8080/demo/ and Login view : http://localhost:8080/demo/login

Sign up to request clarification or add additional context in comments.

Comments

13

Apparently Controllers in different packages can't be seen with @springbootApplication notation in the main class. The solution explained here, https://kamwo.me/java-spring-boot-mvc-ontroller-not-called/.

Comments

5

Make sure that the @SpringBootApplication class is in a package which is a level above all other packages that contain @RestControllers, or in the same package.

Comments

4

For Spring-boot 1.3.x and up, passing a base package to SpringBootApplication should work:

@SpringBootApplication(scanBasePackages = {"com.demo"})
public class DemoBootApplication {
    // code
}

This worked for me on a similar application using spring-boot 1.4.0. For earlier versions of spring-boot, it appears you'll have forego using SpringBootApplication and instead use the following to get same effect as above:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.demo"})
public class DemoBootApplication {
    // code
}

I found this in the comments on this blog post.

Comments

1

ComponentScan annotation works in most cases.

See below example, you could apply similar.
package com.demo;

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

@ComponentScan(basePackages = {"com.demo"})
@SpringBootApplication
public class DemoApplication {

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

Comments

0

Try this

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

@SpringBootApplication
public class Main {

    public static void main(String[] args) {

        Object[] sources = new Object[2];
        sources[0] = Controller1.class;
        sources[1] = Controller2.class;
        SpringApplication.run(sources, args);
    }

}

Comments

0

I'm not sure if this is the right way to do it, but when I changed my 2nd Controllers annotation from @Controller to @RestController it started working.

Comments

-1

Try below:-

@ComponentScan
@Configuration
@EnableAutoConfiguration
public class BootDemoApplication {

public static void main(String[] args) {

    SpringApplication.run(BootDemoApplication.class);
}
}

@RestController
@RequestMapping(value = "test", produces =    MediaType.APPLICATION_JSON_VALUE)
public class TestController {

@RequestMapping(method = RequestMethod.GET)
public String test() {
    return "from test method";
}

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.