my problem is that i dont know how to specify the path for my Controller package to search for requestmapping annotations inside it in the #componenscan annotation, which is in the main class.
Project structure:
My DemoApplication class:
package com.personalitymeet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Configuration
#EnableAutoConfiguration
#ComponentScan()
#Controller
public class DemoApplication {
#ResponseBody
#RequestMapping("/")
String entry(){
return "bla";
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Usercontroller.java:
package com.personalitymeet.web;
import com.personalitymeet.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by mv on 15.09.2016.
*/
#Controller
public class UserController {
#RequestMapping("/user")
public String user(Model model){
User user = new User();
user.setFirstname("Misi");
user.setLastname("Varga");
model.addAttribute("user",user);
return "userview";
}
}
So, my question is, how can i tell springboots that it should search for #Requestmapping annotation in the Usercontroller class?
You can specify component scan to your configuration file to scan folder com.personalitymeet and it will automatically pick all the classes which has relevant annotations.
Below are basic 3 annotations needed to init application.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.personalitymeet")
Your problem isn't the #ComponentScan, which will search in com.personalitymeet and all subpackages. It's that for some reason you don't have the MVC infrastructure activating.
You should have spring-boot-starter-web as a dependency in your build.gradle file, and you should add #EnableWebMvc to your configuration class.
Can you replace this code:
#Configuration
#EnableAutoConfiguration
#ComponentScan()
#Controller
public class DemoApplication {
...
With this code:
#SpringBootApplication
#Controller
public class DemoApplication {
...
Configure your application to expose the management endpoints:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready
and then hit this endpoint to see the endpoint exposed by the application:
http://localhost:[port]/manage/mappings
Also, I recommend to create a separate controller for the root to keep your startup class uncluttered with application logic.
Related
So I've got a simple spring boot app, #SpringBootApplication, a stub #Configuration and a #RestController all in the same package. Spring-boot-web-starter is there and the webserver comes up fine, actuator endpoints and all. But I cannot for the life of me get the app to pick up the #RestControllers.
enter image description here
Main.class:
package com.iglossolalia.munin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(MuninContext.class, args);
}
}
MuninContext.class:
package com.iglossolalia.munin;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
public class MuninContext {
}
MuninService.class:
package com.iglossolalia.munin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MuninService {
private static final Logger LOG = LoggerFactory.getLogger(MuninService.class);
public MuninService() {
LOG.info("Started MuninService");
}
#GetMapping("/health")
public String healthCheck() {
return "pong";
}
}
Tried explicitly adding the rest controller to the component scan with no luck there.
You have no #ComponentScan annotation in your MuninContext. Actually you can write SpringApplication.run(Main.class, args) in main method as Spring Initializr generate by default, you don't really need your context, because #SpringBootApplication work as configuration and contains #EnableAutoConfiguration, #ComponentScan, and some other annotations. Otherwise, as you pass your config class as argument in SpringApplication.run method, annotation #SpringBootApplication in Main class has no effect
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 3 years ago.
I am developing a spring boot application to send sms notification. This is my class for the purpose.
package org.otp.services;
import org.otp.Configurations;
import com.mashape.unirest.http.HttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
#Component
public class SmsService
{
private static final Logger LOG = LoggerFactory.getLogger(SmsService.class);
public String send(String mobile, String msg)
{
//Code
}
}
And this is the class which uses the above class for sending notification.
package org.otp.controllers;
import org.otp.Constants;
import org.otp.services.EmailService;
import org.otp.services.SmsService;
import org.otp.dto.MessageRequest;
import org.otp.dto.MessageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
#Component
public class MessageController {
private static final Logger LOG = LoggerFactory.getLogger(MessageController.class);
#Autowired
SmsService smsService;
public void sendMessageToAlert(#RequestBody MessageRequest messageRequest)
{
String smsStatus = "FAIL";
MessageResponse messageResponse = new MessageResponse();
//1. Nullpointer
smsStatus = smsService.send(messageRequest.getMobileNo(),messageRequest.getMessage());
}
}
Main Class
package org.otp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
#SpringBootApplication
#EnableAsync
public class OtpServiceApplication implements ApplicationRunner
{
public static void main(String[] args) {
SpringApplication.run(OtpServiceApplication.class, args);
}
}
Problem is, I get a nullpointer exception in the (1) stating that my SmsService object is null. And my main class is in package org.otp so the two classes here falls under sub package so no need of component scan.
Therefore I am confused what to do to solve this. I have tried many answers here like adding a #Component annotation and #ComponentScan in main class but nothing works. Could someone please point out my mistake here.
Thanks in advance.
If your #Autowired annotation is not working and throws NPE ,it means that spring fails to create an instance of the component class in the application context . Try to:
Verify that the classes are in class path for scanning and also check to ensure that all auto-wired classes have the annotation #Component to enable them to be picked up during class path scanning.
Check the spring boot start up logs to verify if there are any errors
during bean creation.
Check to ensure all related classes used in the service layer are auto-wired properly and that the injected classes are annotated with #Component .
For further help please share the main application class along with your project structure.
Since you are using springboot , it is preferable to use the sprinboot stereotype annotations instead of the #Component annotation, if you are building a standard springboot web application.
#Service : for the service layer.
#Controller : for the controller layer . Also,DispatcherServlet will look for #RequestMapping on classes which are annotated using #Controller but not with #Component.
In Springboot application's main class add following annotation
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
While using annotations we should configured with #ComponentScan annotation to tell Spring the packages to scan for annotated components. This should be used in mail class(Which class wants to load first) in your case you are working with spring boot so you should use this annotation in Springboot application's main class. Like below
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
This is the userService class that requires a bean of type com.example.repository.userRepository that could not be found
package com.example.services;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.modal.User;
import com.example.repository.userRepository;
#Service
#Transactional
public class UserService {
#Autowired
private userRepository userRepository;
public UserService() {
super();
}
public UserService(userRepository userRepository)
{
this.userRepository = userRepository;
}
public void saveMyuser(User user) {
userRepository.save(user);
}
}
The error message reads :
Consider defining a bean of type 'com.example.repository.userRepository' in your configuration.
This is the repository:
package com.example.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.example.modal.User;
public interface userRepository extends CrudRepository<User,Integer> {
}
this is the application class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
public class TutorialProjectApplication {
public static void main(String[] args) {
SpringApplication.run(TutorialProjectApplication.class, args);
}
}
Seems like userRepository interface is outside of spring-boot default scanning i.e. package of that repository interface is not same or sub-package of the class annotated with #SpringBootApplication. If so, you need to add #EnableJpaRepositories("com.example.repository") on your main class.
Update:
After looking at your updated post, you need to add #EnableJpaRepositories("com.example.repository") to TutorialProjectApplication class
Always keep the #SpringBootApplication main class outer package so that it will automatically scan all the subpackages.
In your case you have main class in package com.example.demo; but the repository in package com.example.repository; which are different packages.so spring boot is not able to find the repositories.
So you have to make spring boot aware of the repositories location.
So now you have 2 solutions.
1.Either put repository class in subpackges of Main class package.
2.Or use #EnableJpaRepositories("com.example.repository") in main class.
In your repository you need to annotate the class
#Repository
public interface userRepository extends CrudRepository<User,Integer> {
}
Due to project requirements I have to deploy a Spring application to a server incapable of running Tomcat and only capable of running WildFly. When I had a very simple project running on Tomcat and the root URL was hit (localhost:8080) it rendered my index.html. Since migrating to WildFly and refactoring the structure of my project, localhost:8080 no longer renders the index.html but I can still reach other URLs.
I've tried to implement a jboss-web.xml file under BrassDucks/src/main/webapp/WEB-INF/jboss-web.xml like this:
<jboss-web>
<context-root>Brass-Ducks</context-root>
</jboss-web>
Where Brass-Ducks is the artifactID but to no avail.
Consider my ApplicationConfig.java
package brass.ducks;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class ApplicationConfig extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<ApplicationConfig> applicationClass = ApplicationConfig.class;
}
#RestController
class GreetingController {
#RequestMapping("/hello/{name}")
String hello(#PathVariable String name) {
return "Hello, " + name + "!";
}
}
and consider my Controller.java
package brass.ducks.application;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/")
public class Controller {
#RequestMapping("/greet")
#ResponseBody
public String greeting() {
return "Hello, there.";
}
}
And finally should it be relevant, my folder structure:
localhost:8080/greet returns "Hello, there" and localhost:8080/hello/name returns "Hello name". How can I fix this?
Depending on your exact configuration something along the lines of this should work:
#Controller
public class LandingPageController {
#RequestMapping({"/","/home"})
public String showHomePage(Map<String, Object> model) {
return "/WEB-INF/index.html";
}
}
This is going to explicitly map / to index.html.
Is there any configuration option that allows to change base url only for rest controllers, for example if my api's base url is www.example.com/user/{id} becomes www.example.com/rest/user/{id} ?
I am using spring boot v1.3.2
I tried to create custom annotation which extends RestController by adding RequestMapping.
Here is the example, but it does not work.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#RestController
#RequestMapping(value = "/rest", path = "/rest")
public #interface MyRestController { }
Option 1: Custom Annotation
Create a Custom Annotation that declares the base URL and use that in lieu of #RestController.
CustomRestControllerAnnotation.java
package com.example.stackoverflow.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#RestController
#RequestMapping("/rest")
public #interface CustomRestControllerAnnotation {}
FirstRestController.java
package com.example.stackoverflow.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.stackoverflow.config.CustomRestControllerAnnotation;
#CustomRestControllerAnnotation
public class FirstRestController {
#RequestMapping("/first")
public String firstMethod(){
return "First Controller";
}
}
SecondRestController.java
package com.example.stackoverflow.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.stackoverflow.config.CustomRestControllerAnnotation;
#CustomRestControllerAnnotation
public class SecondRestController {
#RequestMapping("/second")
public String secondMethod(){
return "Second Controller";
}
}
Option 2: Base RestController
By creating a Base Controller that serves as a template for all of your actual Controllers, you can effectively manage the root URL from a single location.
BaseRestController.java
package com.example.stackoverflow.controller;
import org.springframework.web.bind.annotation.RequestMapping;
#RequestMapping("/rest")
public class BaseRestController {}
Then you simply extend this class for all of your actual Controllers.
FirstRestController.java
package com.example.stackoverflow.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class FirstRestController extends BaseRestController{
#RequestMapping("/first")
public String firstMethod(){
return "First Controller";
}
}
SecondRestController.java
package com.example.stackoverflow.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class SecondRestController extends BaseRestController{
#RequestMapping("/second")
public String secondMethod(){
return "Second Controller";
}
}
Option 3: Spring Data REST
If your Controllers are serving Data from a Repository, then Spring Data REST can take out much of the boilerplate & solve your initial problem.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
By declaring this dependency, all of your Repositories automatically become REST enabled.
You can control the base URL by using a property file.
application.properties
spring.data.rest.basePath=/rest
Updated config for Spring Boot v2.1.0
In Spring Boot v2.1.0 you can configure base URL in application.properties like
server.servlet.context-path = /baseApiName
Complete property configuration list
Typically you would define a servlet that handles all (or a particular set) of your restful requests. You would then tell that servlet to listen to a particular URL pattern like /rest. The #RequestMapping annotations of your controllers are unaware of that 'top level' pattern.
For instance, when bootstrapping your Spring Web Application, you could create that restful servlet manually and add a mapping. The whole setup is a little too large to be posted here, but find a snippet below to get a notion.
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
...
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
...
ServletRegistration.Dynamic restfulServlet = servletContext.addServlet("myServlet", new DispatcherServlet(rootContext));
restfulServlet.addMapping("/rest/*");
...
}
You should add server.servlet-path=/api on your application.properties file and all requests you should send like domain/api/users/{id}