Spring REST Controller not mapped - java

I'm trying to create à Rest controller that listen on "/login" I have defined the code bellow but when I open http://localhost:8080/login I get a 404 error...
Please help :)
Here is my package structure:
com.my.package
|_ Application.java
|_ controller
|_ LoginController
My Application:
#ComponentScan("com.my.package.controller")
#SpringBootApplication
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
My Rest controller:
#RestController
public class LoginController {
#RequestMapping("/login")
public #ResponseBody String getLogin(){
return "{}";
}
}

The controller class should be in a folder of the Application class or in the lower folder.
So, if the application class is in package com.company.app, then the controller class should be in package com.company.app or in com.company.app.*. Let say the controller class is in com.company.controller, it will not mapped since its not in same package or child package of application class.

You should use this annotations in your init class of your springBoot App
#Configuration
#EnableAutoConfiguration
#ComponentScan("com.my.package")
public class WebAppInitializer{
public static void main(String[] args) throws Exception{
SpringApplication.run(WebAppInitializer.class, args);
}
}

Sometimes, when it makes no sense why the mapping is not working, just change the server port so something different than 8080.
ie. in the application.properties or yml, server.port=8081

Related

Spring : Cannot get value from application.properties

I created Spring project via Spring Initializr with project following struct:
I defined property in application.properties file :
my.prop=testvalue
I inject this value into MyClass as following :
#Component
class MyClass {
#Value("${my.prop}")
private String myProp;
public String getMyProp() {
return myProp;
}
}
ConfigBeans defined as following:
package com.example.propertiesdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigBeans {
#Bean
public MyClass myLitoBean() {
return new MyClass();
}
}
PropertiesdemoApplication.java :
package com.example.propertiesdemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(
ConfigBeans.class);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am expecting that after executing line
System.out.println(myClass.getMyProp());
will be printed value of myprop defined in application.properties (i.e testvalue), but after running (via Netbeans IDE) I get output :
${my.prop}
What was missed / wromg in this code ? Thanks in advance
You are creating MyClass bean twice.
Using #component annotation
using #bean annotation in the config class (use method name lowerCamelCase i.e. in your case myClass())
Create bean only once using any one of the above.
You dont need to create an application context in the main method like this. The presented code is a kind of mixture of "traditional" spring and spring boot. So you're kind of bypassing all the goodies that spring boot offers, among which is automatic application.properties loading.
If you're using spring boot (there is a #SpringBootApplication annotation) then it will create everything by itself.
Usually it should be something like this
public static void main(String[] args) {
SpringApplication.run(PropertiesdemoApplication.class, args);
}
Right, as Navnath Adsul said, you need the bean to be created once, and also, since you are using Spring Boot, you need to raise the context using a special method
#SpringBootApplication
public class PropertiesdemoApplication implements CommandLineRunner {
// Inject Bean
#Autowired
private MyClass myClass;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(PropertiesdemoApplication.class)
.run(args);
// or SpringApplication.run(PropertiesdemoApplication.class, args);
}
#Override
public void run(String[] args) throws Exception {
System.out.println(myClass.getMyProp());
}
}
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertiesdemoApplication.class, args);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}

SpringBoot #WebMvcTest is loading non-dependent beans when #ComponentScan is used along with #SpringBootApplication

I am using SpringBoot 2.3.3.RELEASE and I have following web controllers and Services.
myapp
- controllers
- ProductController
- OrderController
- services
- ProductService
- OrderService
ProductController only depends on ProductService and OrderController only depends on OrderService.
Following is my SpringBoot main entrypoint class:
package com.sivalabs.myapp;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have an #WebMvcTest controller for testing ProductController as follows:
#WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private ProductService productService;
//some tests
}
Everything works perfectly fine with this configuration.
I am trying to use some external library with Spring components which has different package name, so I want to override #ComponentScan as follows:
package com.sivalabs.myapp;
import com.somelib.BeanConfig;
#SpringBootApplication
#ComponentScan(basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I include #ComponentScan on my main entrypoint class and run my #WebMvcTest based test ProductControllerTest then in addition to ProductService SpringBoot is trying to initialise OrderService also. Ideally ProductControllerTest should not load OrderService as ProductController doesn't depend on OrderService. Is it a bug?
Workarounds:
If I use #ComponentScan the way it is used on #SpringBootApplication meta-annotation and include basePackageClasses it is working fine.
package com.sivalabs.myapp;
#SpringBootApplication
#ComponentScan(excludeFilters = { #Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), #Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) },
basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Instead of adding #ComponentScan on main entrypoint class if I add another configuration class and add #ComponentScan on that class then it's working fine.
package com.sivalabs.myapp.config;
#Configuration
#ComponentScan(basePackageClasses = {BeanConfig.class})
public class AppConfig {
}
Is it a bug in component scanning process or is it working as expected?
It working as expected.
#SpringBootAplication already have #ComponentScan with filters, and redeclare it as in workaroud #1 doesn't make sense, right?
Problem With original code is that #ComponentScan overrides exclude filters applied inside #SpringBootApplocation annotation. And stuff is not excluded, so when #WebMvc tries to request part of context using filters it fails, and entire context is loaded.
Just check what beans are initialized for context in each scenario. And stick to solution 2. #SpringBootTest will scan packages where application class is places, and any additional packages should be scanned by configurations. That is even more flixible right? :)

Get NOT_FOUND with Spring Boot?

I'm new to Spring framework.
I try to make a simple web server application with Spring but I got 404 Not Found when I call url with Postman.
package com.leoaslan.doctorfinder;
//..import
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#ComponentScan({"com.delivery.request"})
#EntityScan("com.delivery.domain")
#EnableJpaRepositories("com.delivery.repository")
public class DoctorfinderApplication {
public static void main(String[] args) {
SpringApplication.run(DoctorfinderApplication.class, args);
}
}
package com.leoaslan.doctorfinder.controller;
//import
#RestController
#RequestMapping("/api")
public class LoginController {
private final Logger log = LoggerFactory.getLogger(LoginController.class);
#Autowired
LoginService loginService;
#GetMapping("/auth/login")
ResponseEntity<?> login(HttpServletRequest request) {
System.out.println("OK");
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
}
I haven't configured anything yet in application.properties.
Thanks for any helps
Your Controller class is not being scanned, so just try to add the proper package of your controllers on your #ComponentScan
#ComponentScan({"com.delivery.request", "com.leoaslan.doctorfinder.controller"})
Actually, do you really have those packages (com.delivery.request, com.delivery.domain, com.delivery.repository) on your application ? They look suspiciously copy/pasted and they will not do anything unless you change them where your classes really are.

No mapping found on Spring-Boot

I'm new a spring-boot and spring framework. According to me, web app create and deploy very easy with spring-boot but when i run my sample spring web app, application not found "welcome.html" page. I checked all similar question on stackoverflow and not worked me. I cannot see little issue but I didnt find my problem. My application structure and codes are below:
MyApplication class is below:
#SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
WelcomeController class is below:
#Controller
public class WelcomeController {
#RequestMapping(value = "/welcome")
public String welcome() {
return "welcome"; //<- this is your login.html if it is directly in resource/templates folder
}
}
application.properties file is below:
spring.mvc.view.prefix = templates/
spring.mvc.view.suffix = .html
spring.mvc.static-path-pattern=/resources/**
WebMvcAppConfig class is below:
public class WebMvcAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
super.addViewControllers(registry); //To change body of generated methods, choose Tools | Templates.
registry.addViewController("/welcome").setViewName("welcome.html");
}
}
Firstly thanks a lot for quickly response my question #Andy Wilkinson and georges van. I looked for in spring boot reference guide and Serving Web Content with Spring MVC and I learned a lot of information about spring-boot. I removed WebMvcAppConfig because this class not necessary for starter and removed SpringBootServletInitializer. I moved html files into templates as you say. I keep simple and application run without issues.

Spring boot not displaying first view

I'm building a spring boot application. My problem is that when I run the project, my login page is not shown. This is my code:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
I get only a white page and "login" is written in it. When I try to change the #RestController with #Controller I get this GET http://localhost:8080/ 404 (). My login.html page is located under the webapp>tpl>login.html
How can I display my login page?
Edit
This is my application class
#SpringBootApplication
public class ExampleApplication extends SpringBootServletInitializer {
private static Logger logger = LoggerFactory.getLogger(ExampleApplication.class);
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ExampleApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
I dont know your configuration but:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests()
.antMatchers("/**").permitAll();
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
In the Application.properties file add:
spring.mvc.view.suffix: .html
Change #RestController to #Controller for RestLogin class. Also put your html file inside the static folder inside resources folder.
You need an application class with a main method. See this tutorial.
Here's a snippet:
package hello;
import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
}
This is the normal behavior.
New version of Spring web comes with #RestController annotation which nothing but #Controller + #ResponseBody. So when you have a return statement in a method you must use #RestController or annotate your method with #ResponseBody.
Here the problem is that Spring don't know a lot about the http method type, can you please try to use #GetMapping("/") to combinbe path and method at the same time.
According to your posted code and your description, you're getting an expected behavior.
When you annotate your controller with #RestController, that means that your methods on that controller will try to return their result as JSON.
According to your code:
#RestController
public class RestLogin {
#RequestMapping("/")
public String login() {
return "login";
}
}
You're returning the String "login", that's why you're getting empty white page with the word login as JSON
If you will change the #RestController to #Controller then it no longer will return your string as JSON,
but Spring will try to figure out from the that "login" string a view, and for that you'll need to add a view resolver bean to your project.

Categories