I am creating a project that functions like an ecommerce website, and my base page http://localhost:8080 opens up, but if I try adding "/admin" or any of the other mappings in the controller class, I get the 404 Whitelabel page.
How can I make any of the other mappings appear properly?
I tried changing the #ComponentScan in the main class to
"#ComponentScan(basePackages = {"com.ecommerce.website.service.*", "com.ecommerce.website.controller.*", "com.ecommerce.website.repository.*" })"
but that did not solve the issue.
Main class
#SpringBootApplication
#EnableJpaRepositories("com.ecommerce.website.repository.*")
#ComponentScan("com.ecommerce.website.service.*")
#EntityScan("com.ecommerce.website.model.*")
public class EcommerceWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceWebsiteApplication.class, args);
}
}
Controller class
package com.ecommerce.website.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import com.ecommerce.website.model.Category;
import com.ecommerce.website.service.CategoryService;
//Category ID still having issues
//Need to add methods for Category delete and update methods
#Controller
public class AdminController {
//Injecting dependency
#Autowired
CategoryService categoryService;
//This method maps for /admin endpoint. It shows the adminHome.html page. The method is #GetMapping because you are getting information
//#return the adminHome page
#GetMapping("/admin")
public String adminHome() {
//Display html page
return "adminHome";
}
//This method maps for /admin/categories endpoint. It shows the categories.html page. The method is #GetMapping because you are getting information
//#return the categories page
#GetMapping("/admin/categories")
public String getCat(Model model) {
model.addAttribute("categories", categoryService.getAllCategories());
//Display html page
return "categories";
}
//This method maps for /admin/categories endpoint. It shows the categoriesAdd.html page, but before that, it creates
//a model that is sent to the html file via Thymeleaf. The categoriesAdd.html page is a form for adding a category
//The method is #GetMapping because you are getting information
//#param model will hold the category object so that the form can add information to it
//#return the categoriesAdd page
#GetMapping("/admin/categories/add")
public String getCatAdd(Model model) {
//Adding the model name "category", and creating a new Category object and putting it in the model
model.addAttribute("category", new Category());
//Display html page
return "categoriesAdd";
}
//This method maps for /admin/categories endpoint. It allows the user to add a category to the list of categories
//The method is #PostMapping because you are sending information
//#param category gets its value from the ModelAttribute, which gets its value from the form
//#return the categories page
#PostMapping("/admin/categories/add")
public String postCatAdd(#ModelAttribute("category") Category category) {
//Calling categoryService to add the category
categoryService.addCategory(category);
//Redirecting to page that shows all categories
return "redirect:/admin/categories";
}
Service
package com.ecommerce.website.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ecommerce.website.model.Category;
import com.ecommerce.website.repository.CategoryRepository;
#Service
public class CategoryService {
//Injecting dependency
#Autowired
CategoryRepository categoryRepository;
//This method calls categoryRepository to add a category to the database
//#param category is the category that is being added
public void addCategory(Category category) {
//Saving the category to the database
categoryRepository.save(category);
}
//This method calls categoryRepository to retrieve a list of categories
//#return the list of categories
public List<Category> getAllCategories() {
return categoryRepository.findAll();
}
}
Repository
package com.ecommerce.website.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.ecommerce.website.model.Category;
#Repository
public interface CategoryRepository extends JpaRepository<Category, Integer> {
}
POJO
package com.ecommerce.website.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;
import org.springframework.data.annotation.Id;
#Entity
#Table
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "category_id")
private int id;
private String name;
public Category() {
}
public Category(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:file:./db
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
server.port=8080
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>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ecommerce</groupId>
<artifactId>ecommerce-website</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ecommerce-website</name>
<description>Ecommerce website using Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.0.0</version>
</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-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.0.0</version>
</dependency>-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EDIT
I removed all annotations from the main class, except for #SpringBootApplication and #ComponentScan, so now it looks like this:
#SpringBootApplication
#ComponentScan(basePackages={"com.ecommerce.website.service.*", "com.ecommerce.website.controller.*", "com.ecommerce.website.repository.*" })
public class EcommerceWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceWebsiteApplication.class, args);
}
}
Currently what is being shown in my console
2022-12-27T22:43:35.202-06:00 INFO 5656 --- [ main] c.e.website.EcommerceWebsiteApplication : Starting EcommerceWebsiteApplication using Java 17.0.2 with PID 5656 (C:\Users\sohaib\eclipse-workspace\mongoDB-spring-boot\ecommerce-website-h2\target\classes started by sohaib in C:\Users\sohaib**strong text**\eclipse-workspace\mongoDB-spring-boot\ecommerce-website-h2)
2022-12-27T22:43:35.208-06:00 INFO 5656 --- [ main] c.e.website.EcommerceWebsiteApplication : No active profile set, falling back to 1 default profile: "default"
2022-12-27T22:43:36.611-06:00 INFO 5656 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2022-12-27T22:43:36.709-06:00 INFO 5656 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 87 ms. Found 1 JPA repository interfaces.
2022-12-27T22:43:37.831-06:00 INFO 5656 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-12-27T22:43:37.844-06:00 INFO 5656 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-12-27T22:43:37.844-06:00 INFO 5656 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.1]
2022-12-27T22:43:37.989-06:00 INFO 5656 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-12-27T22:43:37.992-06:00 INFO 5656 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2658 ms
2022-12-27T22:43:38.033-06:00 INFO 5656 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2022-12-27T22:43:38.299-06:00 INFO 5656 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:file:./db user=SA
2022-12-27T22:43:38.301-06:00 INFO 5656 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2022-12-27T22:43:38.314-06:00 INFO 5656 --- [ main] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:file:./db'
2022-12-27T22:43:38.475-06:00 INFO 5656 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2022-12-27T22:43:38.549-06:00 INFO 5656 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.1.5.Final
2022-12-27T22:43:38.770-06:00 WARN 5656 --- [ main] org.hibernate.orm.deprecation : HHH90000021: Encountered deprecated setting [javax.persistence.sharedCache.mode], use [jakarta.persistence.sharedCache.mode] instead
2022-12-27T22:43:38.926-06:00 INFO 5656 --- [ main] SQL dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2022-12-27T22:43:39.774-06:00 INFO 5656 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-12-27T22:43:39.782-06:00 INFO 5656 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-12-27T22:43:39.847-06:00 WARN 5656 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2022-12-27T22:43:40.038-06:00 INFO 5656 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2022-12-27T22:43:40.576-06:00 INFO 5656 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-12-27T22:43:40.587-06:00 INFO 5656 --- [ main] c.e.website.EcommerceWebsiteApplication : Started EcommerceWebsiteApplication in 5.879 seconds (process running for 6.41)
2022-12-27T22:47:31.683-06:00 INFO 5656 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-12-27T22:47:31.684-06:00 INFO 5656 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-12-27T22:47:31.685-06:00 INFO 5656 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
Your controllers are simply not scanned by spring because you explicitly asked it to scan only the com.ecommerce.website.service.* package
However, your controllers are in com.ecommerce.website.controller.*
Why do you want to tell spring which scanner component?
Unless you have a good reason to do so, you should let it scan all the packages in your project.
Just put:
#SpringBootApplication
public class EcommerceWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceWebsiteApplication.class, args);
}
}
More information on #ComponentScan : https://www.baeldung.com/spring-component-scanning
I am working on a Spring Boot application trying to use Spring Data JPA and Hibernate but I am finding some difficulties trying to insert a new record into an example table.
This is my application pom.xml file content:
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.easydefi</groupId>
<artifactId>GET-USER-WS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>GET-USER-WS</name>
<description>Microservice that retrieves users from DB</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
This is my application.properties file content:
spring.datasource.url = jdbc:postgresql://172.21.0.2:5432/EasyDefiDB
spring.datasource.username = postgres
spring.datasource.password = MY_PSWD
spring.datasource.driver-class-name = org.postgresql.Driver
spring.jpa.hibernate.ddl-auto = none
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Then into my Postgres I created a DB named EasyDefiDB containing this very simple Example table that I am using to perform some experiment:
CREATE TABLE IF NOT EXISTS public."Example"
(
id bigint NOT NULL,
test character varying(50) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT "Example_pkey" PRIMARY KEY (id)
)
So I created this Example entity class:
package com.easydefi.users.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name = "Example")
#Data
public class Example implements Serializable {
private static final long serialVersionUID = -2878723722630662986L;
#Id
#Column(name = "id")
private int id;
#Column(name = "test")
private String test;
public Example(String test) {
super();
this.test = test;
}
public Example() {
super();
}
}
Then I created this ExampleRepository extenting JpaRepository interface:
public interface ExampleRepository extends JpaRepository<Example, Integer> {
}
At the moment this interface is empty because I am only trying to save a new record using the JpaRepository save() method.
Finnally I created this unit test class in order to test the saving behavior:
#SpringBootTest()
#ContextConfiguration(classes = GetUserWsApplication.class)
#TestMethodOrder(OrderAnnotation.class)
public class ExampleRepositoryTest {
#Autowired
private ExampleRepository exampleRepository;
#Test
#Order(1)
public void TestInsertExample()
{
Example example = new Example("TEST");
exampleRepository.save(example);
assertTrue(true);
}
}
The problem is that running this method, when the save() method is called it give me the following error in my stacktrace:
2021-11-03 17:10:59.059 INFO 15054 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-11-03 17:10:59.416 WARN 15054 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2021-11-03 17:11:00.453 INFO 15054 --- [ main] c.e.users.GetUserWsApplicationTests : Started GetUserWsApplicationTests in 5.067 seconds (JVM running for 6.686)
2021-11-03 17:11:00.812 INFO 15054 --- [ main] o.s.t.c.support.AbstractContextLoader : Could not detect default resource locations for test class [com.easydefi.users.tests.RepositoryTests.ExampleRepositoryTest]: no resource found for suffixes {-context.xml, Context.groovy}.
2021-11-03 17:11:00.818 INFO 15054 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
2021-11-03 17:11:00.818 INFO 15054 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener#703eead0, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener#674fd531, org.springframework.test.context.event.ApplicationEventsTestExecutionListener#7f53b345, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener#76ee7301, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener#71817f66, org.springframework.test.context.support.DirtiesContextTestExecutionListener#68feca3a, org.springframework.test.context.transaction.TransactionalTestExecutionListener#ad585fb, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener#fa689db, org.springframework.test.context.event.EventPublishingTestExecutionListener#75a6bd06, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener#6b170692, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener#4d4bac56, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener#76980c75, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener#3696d12d, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener#656672fb, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener#75df4b1d]
Hibernate:
insert
into
example
(test, id)
values
(?, ?)
2021-11-03 17:11:09.867 WARN 15054 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42P01
2021-11-03 17:11:09.869 ERROR 15054 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: relation "example" does not exist
Position: 13
So basically the problem seems that, for some reason that I cannot uderstand, it is trying to insert into the example table and not into the Example (as it is defined in my DB, with the first uppercase char).
Renaming my table from Example to example it works fine, the new record is correctly inserted into this table.
But why? How can I change this behaviour allowing me to correctly insert into a table starting with an uppercase letter?
I've a very simple Spring cloud aws project. I'm using Java 11.
here is the pom:
<?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.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo.arf</groupId>
<artifactId>testsqs-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>testsqs-boot</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Config class:
package com.demo.arf.testsqsboot;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder;
import org.springframework.beans.factory.annotation.Value;
//import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.cloud.aws.messaging.config.SimpleMessageListenerContainerFactory;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
//import com.amazonaws.services.sqs.AmazonSQSAsync;
//import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder;
#Configuration
public class SQSConfig {
#Value("${cloud.aws.region.static}")
private String region;
#Value("${cloud.aws.credentials.access-key}")
private String awsAccessKey;
#Value("${cloud.aws.credentials.secret-key}")
private String awsSecretKey;
#Bean
public QueueMessagingTemplate queueMessagingTemplate() {
return new QueueMessagingTemplate(amazonSQSAsync());
}
public AmazonSQSAsync amazonSQSAsync() {
return AmazonSQSAsyncClientBuilder.standard().withRegion(Regions.US_EAST_1)
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(awsAccessKey, awsSecretKey)))
.build();
}
#Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSQS){
SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
factory.setAmazonSqs(amazonSQS);
factory.setMaxNumberOfMessages(10);
return factory;
}
}
the controller class which send/receive message:
package com.demo.arf.testsqsboot.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class SQSController {
#Autowired
private QueueMessagingTemplate queueMessagingTemplate;
private static final Logger LOG = LoggerFactory.getLogger(SQSController.class);
#GetMapping("/send-sqs-message")
public String sendMessage() {
String sqsEndPoint= "https://sqs.us-east-2.amazonaws.com/1234567879/my_queue";
queueMessagingTemplate.convertAndSend(sqsEndPoint, MessageBuilder.withPayload("hello from Spring Boot").build());
return "Hello SQS";
}
#SqsListener("my_queue")
public void getMessage(String message) {
LOG.info(" *********** Message from SQS Queue - "+message);
}
}
application.yml:
server:
port: 9001
cloud:
aws:
region:
static: us-east-1
auto: false
credentials:
access-key: "asdmnasdn"
secret-key: "sfkjsdjksdkj"
end-point:
uri: https://sqs.us-east-2.amazonaws.com/1234567879/my_queue
I can get the send working fine. but when I add the listener, I get the following error during startup and listener does not receive messages:
2020-03-15 01:02:00.677 INFO 15423 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3853 ms
2020-03-15 01:02:01.109 INFO 15423 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
**WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.amazonaws.util.XpathUtils (file:/Users/arf/.m2/repository/com/amazonaws/aws-java-sdk-core/1.11.415/aws-java-sdk-core-1.11.415.jar) to method com.sun.org.apache.xpath.internal.XPathContext.getDTMManager()
WARNING: Please consider reporting this to the maintainers of com.amazonaws.util.XpathUtils
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2020-03-15 01:02:01.749 WARN 15423 --- [ main]**
s.c.a.m.l.SimpleMessageListenerContainer : Ignoring queue with name 'my_queue': The queue does not exist.; nested exception is com.amazonaws.services.sqs.model.QueueDoesNotExistException: The specified queue does not exist for this wsdl version. (Service: AmazonSQS; Status Code: 400; Error Code: AWS.SimpleQueueService.NonExistentQueue; Request ID: 62821505-3f34-5434-a6ee)
2020-03-15 01:02:01.749 INFO 15423 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService
Also, one basic question. How does the #SQSListener know where to find the aws account info and sqs uri?
I've made it work with the following change in config class. However, I wonder, how most of the sample programs online without this code(which construct AmazonSQSAsync with withEndpointConfiguration) is working.
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQS) {
return new QueueMessagingTemplate(amazonSQS);
}
#Bean
#Primary
public AmazonSQSAsync amazonSQS(AWSCredentialsProvider credentials) {
return AmazonSQSAsyncClientBuilder.standard()
.withCredentials(credentials)
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(localStackSqsUrl, awsRegion))
.build();
}
#Bean
#Primary
public AWSCredentialsProvider awsCredentialsProvider() {
return new AWSCredentialsProviderChain(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials("local", "stack")));
}```
A couple things.
- First NEVER store your AK/SK in a property or yml file like that. I can tell those are fake values, but you'll always want to pull these from ~/.aws/credentials or instance metadata. The AWS clients like AmazonSqSAsyncClientBuilder will do automatically if you just call .standard(). No need for the credential provider.
- Second, same with region
- Third, I believe #SqsListener will use the ContainerFactory bean you defined earlier, at least that's how the #JmsListener works.
- The error message you received was that your queue name was not found in your account in your selected region. You told it us-east-1, but in your send code you specified us-east-2. My guess based on your post is that your queue is in us-east-2 since your question came up about #SqsListener, not the queueMessagingTemplate.
I am new to Spring boot ( and servlet 3.0 ). I am trying to create spring mvc project with JSP as view. When I return a view from my controller it is not getting resolved as JstlView.
Here is what I did:
#SpringBootApplication
public class MyApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
#Controller
public class MainController {
#RequestMapping( value="/main" , method = RequestMethod.GET )
public String main(){
return "main";
}
#RequestMapping( value="/" , method = RequestMethod.GET )
public String welcome(){
return "welcome";
}
}
Created both .jsp files in src\main\webapp\WEB-INF\jsp .
After googling I found that I need to specify this in application.properties So I added following in props:
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
logging.level.org.springframework: TRACE
logging.level.com: TRACE
Even after this it is not working. Here is the trace.
2016-04-24 19:54:49.016 TRACE 7880 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Invoking [MainController.welcome] method with arguments []
2016-04-24 19:54:49.016 TRACE 7880 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Method [welcome] returned [welcome]
2016-04-24 19:54:49.020 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
2016-04-24 19:54:49.020 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.BeanNameViewResolver : No matching bean found for view name 'welcome'
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Invoking afterPropertiesSet() on bean with name 'welcome'
2016-04-24 19:54:49.022 TRACE 7880 --- [nio-8080-exec-1] o.s.w.s.v.InternalResourceViewResolver : Cached view [welcome]
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Returning [org.springframework.web.servlet.view.InternalResourceView: name 'welcome'; URL [/WEB-INF/jsp/welcome.jsp]] based on requested media type 'text/html'
2016-04-24 19:54:49.022 DEBUG 7880 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'welcome'; URL [/WEB-INF/jsp/welcome.jsp]] in DispatcherServlet with name 'dispatcherServlet'
2016-04-24 19:54:49.022 TRACE 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Rendering view with name 'welcome' with model {} and static attributes {}
2016-04-24 19:54:49.026 DEBUG 7880 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Forwarding to resource [/WEB-INF/jsp/welcome.jsp] in InternalResourceView 'welcome'
2
As you see in the trace, this is trying to resolve /jsp/welcome.jsp as InternalResourceView instead of JstlView. Eventually it fails as 404.
What other steps I need to follow? Is there any tutorial for SpringBoot-mvc with jsp ?
P.S. I can create spring mvc app with jsp using web.xml ( using JstlView in my config file ). But I can't find any tutorial for Spring boot mvc with jsp.
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
also needed and your pages should be at /webapp/WEB-INF/jsp/
+
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Assuming it is embedded Tomcat,
You need to have followings in your pom.xml
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Embedded Tomcat core package has no JSP rendering support.
You do not require the ViewResolver. pom.xml needs the mentioned dependencies as told by Yura and place the jsp files in src\main\webapp\WEB-INF\jsp.
If we want to use jsp as view in spring boot(which by default has tomcat server) we need to add the following to our pom.xml:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
we need to add our pages inside
src/main/webapp/WEB-INF/view
After this we can specify the location for our jsp pages in application.properties
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
Create webapp/WEB-INF/views {Name the last folder as U Like }
under src/main
add jstl jar
add following two lines in application.properties
spring.mvc.view.prefix:/WEB-INF/views/
spring.mvc.view.suffix:.jsp
Run As Spring Boot App ..U are good to go !
For More U can consult my this project on github :
https://github.com/SudipBiswasRana/Using-JSP-As-View-For-Spring-Project
I am trying to adapt the REST Controller example on the Spring Boot website.
Unfortunately I've got the following error when I am trying to access the localhost:8080/item URL.
{
"timestamp": 1436442596410,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/item"
}
POM:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SpringBootTest</groupId>
<artifactId>SpringBootTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<javaVersion>1.8</javaVersion>
<mainClassPackage>com.nice.application</mainClassPackage>
<mainClass>${mainClassPackage}.InventoryApp</mainClass>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${javaVersion}</source>
<target>${javaVersion}</target>
</configuration>
</plugin>
<!-- Makes the Spring Boot app executable for a jar file. The additional configuration is needed for the cmd: mvn spring-boot:repackage
OR mvn spring-boot:run -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>${mainClass}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Create a jar with a manifest -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot. This replaces the usage of the Spring Boot parent POM file. -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- more comfortable usage of several features when developing in an IDE. Developer tools are automatically disabled when
running a fully packaged application. If your application is launched using java -jar or if it’s started using a special classloader,
then it is considered a 'production application'. Applications that use spring-boot-devtools will automatically restart whenever files
on the classpath change. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
</dependencies>
</project>
Starter-Application:
package com.nice.application;
#SpringBootApplication // same as #Configuration #EnableAutoConfiguration #ComponentScan
public class InventoryApp {
public static void main( String[] args ) {
SpringApplication.run( InventoryApp.class, args );
}
}
REST-Controller:
package com.nice.controller;
#RestController // shorthand for #Controller and #ResponseBody rolled together
public class ItemInventoryController {
public ItemInventoryController() {
}
#RequestMapping( "/item" )
public String getStockItem() {
return "It's working...!";
}
}
I am building this project with Maven.
Started it as jar (spring-boot:run) and as well inside the IDE (Eclipse).
Console Log:
2015-07-09 14:21:52.132 INFO 1204 --- [ main] c.b.i.p.s.e.i.a.InventoryApp : Starting InventoryApp on 101010002016M with PID 1204 (C:\eclipse_workspace\SpringBootTest\target\classes started by MFE in C:\eclipse_workspace\SpringBootTest)
2015-07-09 14:21:52.165 INFO 1204 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#7a3d45bd: startup date [Thu Jul 09 14:21:52 CEST 2015]; root of context hierarchy
2015-07-09 14:21:52.661 INFO 1204 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2015-07-09 14:21:53.430 INFO 1204 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2015-07-09 14:21:53.624 INFO 1204 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2015-07-09 14:21:53.625 INFO 1204 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.0.23
2015-07-09 14:21:53.731 INFO 1204 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2015-07-09 14:21:53.731 INFO 1204 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1569 ms
2015-07-09 14:21:54.281 INFO 1204 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2015-07-09 14:21:54.285 INFO 1204 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-07-09 14:21:54.285 INFO 1204 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-07-09 14:21:54.508 INFO 1204 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for #ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#7a3d45bd: startup date [Thu Jul 09 14:21:52 CEST 2015]; root of context hierarchy
2015-07-09 14:21:54.573 INFO 1204 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-07-09 14:21:54.573 INFO 1204 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2015-07-09 14:21:54.594 INFO 1204 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.594 INFO 1204 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.633 INFO 1204 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.710 INFO 1204 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2015-07-09 14:21:54.793 INFO 1204 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-07-09 14:21:54.795 INFO 1204 --- [ main] c.b.i.p.s.e.i.a.InventoryApp : Started InventoryApp in 2.885 seconds (JVM running for 3.227)
2015-07-09 14:22:10.911 INFO 1204 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-07-09 14:22:10.911 INFO 1204 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2015-07-09 14:22:10.926 INFO 1204 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 15 ms
What I've tried so far:
Accessing the URL with the application name (InventoryApp)
Put another #RequestMapping("/") at class level of the ItemInventoryController
As far as I understood, I won't need an application-context when using Spring Boot. Am I right?
What else can I do to access the method via URL?
Try adding the following to your InventoryApp class
#SpringBootApplication
#ComponentScan(basePackageClasses = ItemInventoryController.class)
public class InventoryApp {
...
spring-boot will scan for components in packages below com.nice.application, so if your controller is in com.nice.controller you need to scan for it explicitly.
Adding to MattR's answer:
As stated in here, #SpringBootApplication automatically inserts the needed annotations: #Configuration, #EnableAutoConfiguration, and also #ComponentScan; however, the #ComponentScan will only look for the components in the same package as the App, in this case your com.nice.application, whereas your controller resides in com.nice.controller. That's why you get 404 because the App didn't find the controller in the application package.
Same 404 response I got after service executed with the below code
#Controller
#RequestMapping("/duecreate/v1.0")
public class DueCreateController {
}
Response:
{
"timestamp": 1529692263422,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/duecreate/v1.0/status"
}
after changing it to below code I received proper response
#RestController
#RequestMapping("/duecreate/v1.0")
public class DueCreateController {
}
Response:
{
"batchId": "DUE1529673844630",
"batchType": null,
"executionDate": null,
"status": "OPEN"
}
SpringBoot developers recommend to locate your main application class in a root package above other classes. Using a root package also allows the #ComponentScan annotation to be used without needing to specify a basePackage attribute. Detailed info
But be sure that the custom root package exists.
There are 2 method to overcome this
Place the bootup application at start of the package structure and rest all controller inside it.
Example :
package com.spring.boot.app; - You bootup application(i.e. Main Method -SpringApplication.run(App.class, args);)
You Rest Controller in with the same package structure
Example :
package com.spring.boot.app.rest;
Explicitly define the Controller in the Bootup package.
Method 1 is more cleaner.
I had this issue and what you need to do is fix your packages. If you downloaded this project from http://start.spring.io/ then you have your main class in some package. For example if the package for the main class is: "com.example" then and your controller must be in package: "com.example.controller". Hope this helps.
The controller should be accessible in the same namespace
This is what you have
This is how it should be, see the hierarchy of the namespace
You need to modify the Starter-Application class as shown below.
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages="com.nice.application")
#EnableJpaRepositories("com.spring.app.repository")
public class InventoryApp extends SpringBootServletInitializer {..........
And update the Controller, Service and Repository packages structure as I mentioned below.
Example:
REST-Controller
package com.nice.controller; --> It has to be modified as
package com.nice.application.controller;
You need to follow proper package structure for all packages which are in Spring Boot MVC flow.
So, If you modify your project bundle package structures correctly then your spring boot app will work correctly.
Replace #RequestMapping( "/item" ) with #GetMapping(value="/item", produces=MediaType.APPLICATION_JSON_VALUE).
Maybe it will help somebody.
for me, I was adding spring-web instead of the spring-boot-starter-web into my pom.xml
when i replace it from spring-web to spring-boot-starter-web, all maping is shown in the console log.
I had exact same error, I was not giving base package. Giving correct base package,ressolved it.
package com.ymc.backend.ymcbe;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages="com.ymc.backend")
public class YmcbeApplication {
public static void main(String[] args) {
SpringApplication.run(YmcbeApplication.class, args);
}
}
Note: not including .controller
#ComponentScan(basePackages="com.ymc.backend.controller") because i
have many other component classes which my project does not scan if i
just give .controller
Here is my controller sample:
package com.ymc.backend.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#CrossOrigin
#RequestMapping(value = "/user")
public class UserController {
#PostMapping("/sendOTP")
public String sendOTP() {
return "OTP sent";
};
}
I found a really great thread for this issue.
https://coderanch.com/t/735307/frameworks/Spring-boot-Rest-api
The controller api should be in the sub directory structure to automatically detect the controllers. Otherwise annotation argument can be used.
#SpringBootApplication(scanBasePackages = {"com.example.demo", "com.example.Controller"})
New to Springboot, tried everything above, but ended up being as simple as I had a / at the end of the URL on my browser while my only Get() method was blank, just returning a string.
Hope this'll help someone someday.
Sometimes spring boot behaves weird. I specified below in application class and it works:
#ComponentScan("com.seic.deliveryautomation.controller")
I got the 404 problem, because of Url Case Sensitivity.
For example
#RequestMapping(value = "/api/getEmployeeData",method = RequestMethod.GET) should be accessed using http://www.example.com/api/getEmployeeData. If we are using http://www.example.com/api/getemployeedata, we'll get the 404 error.
Note:
http://www.example.com is just for reference which i mentioned above. It should be your domain name where you hosted your application.
After a lot of struggle and apply all the other answers in this post, I got that the problem is with that url only. It might be silly problem. But it cost my 2 hours. So I hope it will help someone.
It also works if we use as follows:
#SpringBootApplication(scanBasePackages = { "<class ItemInventoryController package >.*" })
It could be that something else is running on port 8080, and you're actually connecting to it by mistake.
Definitely check that out, especially if you have dockers that are bringing up other services you don't control, and are port forwarding those services.
The problem is with your package structure. Spring Boot Application has a specific package structure to allow spring context to scan and load various beans in its context.
In com.nice.application is where your Main Class is and in com.nice.controller, you have your controller classes.
Move your com.nice.controller package into com.nice.application so that Spring can access your beans.
Another solution in case it helps: in my case, the problem was that I had a #RequestMapping("/xxx") at class level (in my controller), and in the exposed services I had #PostMapping (value = "/yyyy") and #GetMapping (value = "/zzz"); once I commented the #RequestMapping("/xxx") and managed all at method level, worked like a charm.
For me, the problem was that I had set up the Application in a way that it always immediately shut down after starting. So by the time I tried out if I could access the controller, the Application wasn't running anymore.
The problem with immediately shutting down is adressed in this thread.
#SpringBootApplication
#ComponentScan(basePackages = {"com.rest"}) // basePackageClasses = HelloController.class)
// use above componnent scan to add packages
public class RestfulWebServicesApplication {
public static void main(String[] args) {
SpringApplication.run(RestfulWebServicesApplication.class, args);
}
}
There may 3 reasons causing for this error:
1>
check your URL you are requesting is correct
2> check if your
using MVC then use #Controller else use #RestController
3> check
whether you have placed Controller package(or Class) outside the root
package example: com.example.demo -> is your main
package
place controller package inside com.example.demo.controller
I had the same issue, because I created an inner class annotated with #Configuration and it prohibited somehow the component scan.
I had the same problem, and while the above solution are correct in their own right, they did not work for me, and I found another possible reason that solved it - you have to shut down the application from the port, and restart your application, if doing a Maven Update or a project clean fail to solve it.
Briefly, open a command prompt, and run the following two commands:
netstat -ano | findstr :8080
This command will locate the Process ID that is attached at the port that your app is running on - please make sure to specify the port, if you have it anywhere other than the default.
You will get the following output:
What you care about is the number in the last column, which is the process ID associated with the port, on which the instance of the app is running.
If you are using STS4 for your development purposes, you can also see the PID on the top margin of the console, but you do have to squint for it:
At this point, run the next command to kill the process:
taskkill /pid 22552 /f
And it results in this:
Do remember that there will be a different PID for every time you run the application.
And finally, you can run it again, and that should do it.
More relevant materials:
Closing network connections
Programmatically shutting down SpringBoot app
Change the Return type from String to ResponseEntity
Like :
#RequestMapping( "/item" )
public ResponseEntity<String> getStockItem() {
return new ResponseEntity<String>("It's working...!", HttpStatus.OK);
}
Place your springbootapplication class in root package for example if your service,controller is in springBoot.xyz package then your main class should be in springBoot package otherwise it will not scan below packages
You can add inside the POM.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>XXXXXXXXX</version>
</dependency>