I am learning spring boot, I made a simple GET endpoint but whenever I request on that endpoint I keep getting 404.
Below is my code:
Student.Controller.java
package student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
#RestController
public class StudentController {
#GetMapping("/home")
public String home(){
return "This is String";
}
}
Project Structure:
If you add #ComponentScan({"student"}) annotation on DemoApplication class it should work. You can also create your packages such as controller, service, repository ... under com.example.demo, then you don't have to add additional annotations for component scanning.
Follow this project structuring advice: https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-structuring-your-code.html
Related
I have a SpringBoot application. I have a dedicated server, where I shall read data by the HTTP GET requests. I configured the http-outbound-config.xml file for Spring Integration module.
When I run the following code, everything is fine:
http-outbound-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http https://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<int:channel id="requestChannel"/>
<int:channel id="replyChannel">
<int:queue capacity='10'/>
</int:channel>
<int-http:outbound-gateway id="outboundGateway"
request-channel="requestChannel"
url="http://server/API.jsp?id=1"
http-method="GET"
expected-response-type="java.lang.String"
charset="UTF-8"
reply-channel="replyChannel"/>
</beans>
Main Application Class:
package test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
import ru.eco.products.waste.egr.Integration;
#SpringBootApplication
#ImportResource("/META-INF/spring/integration/http-outbound-config.xml")
public class Application {
public static void main(String[] args) {
Integration integration = new Integration();
integration.start();
SpringApplication.run(WasteWebClientApplication.class,
args
);
}
}
Integration class:
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
#Configuration
public class Integration {
public void start() {
ClassPathXmlApplicationContext
context = new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/http-outbound-config.xml");
context.start();
MessageChannel requestChannel = context.getBean("requestChannel", MessageChannel.class);
PollableChannel replyChannel = context.getBean("replyChannel", PollableChannel.class);
Message<?> message = MessageBuilder.withPayload("").build();
requestChannel.send(message);
Message<?> receivedMsg = replyChannel.receive();
System.out.println("RESULT IS : " + receivedMsg.getPayload());
}
}
BUT, when I try to Autowire MessageChannel and PollableChannel, I receive a null pointer exception.
Integration class(not working example):
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
#Configuration
public class Integration {
#Autowired
#Qualifier("requestChannel")
MessageChannel requestChannel;
#Autowired
#Qualifier("replyChannel")
PollableChannel replyChannel;
public void start() {
Message<?> message = MessageBuilder.withPayload("").build();
requestChannel.send(message);
Message<?> receivedMsg = replyChannel.receive();
System.out.println("RESULT IS : " + receivedMsg.getPayload());
}
}
Question 1: Why Autowiring is not working?
Question 2: What is the best way to get data from dedicated server and save it into DB? Such config is ok? I will create a model class for the response and after will save it into DB via JPA.
Question 3: I need reading from server works in Async mode. How can I implement it in Spring Boot? So the main idea here is that I will receive a POST method from the UI, and will launch the integration with web-service. After integration will be finished, I need to notify user.
Question 4: Maybe Camel will be the best solution here?
Stack: Java 11, Spring Boot, thymeleaf + bootstrap.
Thank you for the answer in advance.
Since you do new Integration();, you definitely not going to have dependency injection since inversion of control container is not involved. Although it is fully not clear why do you need that new ClassPathXmlApplicationContext("classpath:META-INF/spring/integration/http-outbound-config.xml") if you already do Spring Boot and that proper #ImportResource.
The best way as you already do with the #ImportResource for that Spring Integration XML config. Then you need to get access to the ApplicationContext of the SpringApplication.run() and getBean(Integration.class) to call your start() method. However you fully need to forget about new Integratio(). Spring is going to manage a bean for that Integration and then dependency injection is going to work.
Async mode can be achieved with an ExecutorChannel in Spring Integration. So, when you send a message to this channel, the logic is going to be processed on a different thread. However it is not clear why you state such a requirement since you still going to block via that replyChannel.receive()... Although this should be addressed in a separate SO thread.
Camel VS Spring Integration question is out of StackOverflow policies.
Thymeleaf and Bootstrap are misleading in the context of this question.
Please, consider to learn how to ask properly here on SO: https://stackoverflow.com/help/how-to-ask
Also read some docs about dependency injection and inversion of control: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
I just updated the Springfox dependency in my Spring Boot application (version 2.3.1.RELEASE) from 2.9.2 to 2.10.4.
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
<swagger.version>2.10.4</swagger.version>
Due to class changes in the springfox.documentation.* packages, I had to change the annotation in my configuration class from
#EnableSwagger2
to
#EnableSwagger2WebMvc
Also the Predicate import changed from Google Guave to java.util.function. My current Configuration class looks like this
package de.rewe.zlip.config;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
#Configuration
#EnableSwagger2WebMvc
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).globalOperationParameters(globalOperationParameters())
.select()
.apis(sourceScannedForRestApis())
.paths(PathSelectors.any())
.build()
.apiInfo(apiEndPointsInfo())
.genericModelSubstitutes(Optional.class);
}
private List<Parameter> globalOperationParameters() {
List<Parameter> operationParameters = new LinkedList<>();
Parameter authorizationParameter = new ParameterBuilder().name("Authorization")
.description("Your Bearer token ")
.modelRef(new ModelRef("string"))
.parameterType("header")
.build();
operationParameters.add(authorizationParameter);
return operationParameters;
}
private Predicate<RequestHandler> sourceScannedForRestApis() {
return RequestHandlerSelectors.basePackage("de.my.package");
}
private ApiInfo apiEndPointsInfo() {
return new ApiInfoBuilder().title("TEST SERVER REST API")
.description("REST API provided for the TEST web application")
.contact(contactInfo())
.version("v1.0")
.build();
}
private Contact contactInfo() {
return new Contact("Test Team", "https://", "test#test.com");
}
}
When I open http://localhost:8080/swagger-ui.html now, I get the following message:
Unable to infer base url. This is common when using dynamic servlet
registration or when the API is behind an API Gateway. The base url is
the root of where all the swagger resources are served. For e.g. if
the api is available at http://example.org/api/v2/api-docs then the
base url is http://example.org/api/. Please enter the location
manually:
Needless to say, the same configuration (except of the 2 changes mentioned above) worked with 2.9.2. Most of the tips in earlier questions are adding
#EnableSwagger2
but since this annotation has changed in 2.10.X to either #EnableSwagger2Mvc or #EnableSwagger2Flux this won't help.
From springfox issue tracker:
Oh please dont use 2.10... it was an intermediate step so that people who were on 3.0.0-SNAPSHOT can continue using a released version if needed.
I suggest reverting back to 2.9.2 for the time being.
You can try below.
Add this dependency to your pom.xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>${your.spring.fox.version}</version>
</dependency>
Add this line to either your main class or your swagger config class
#Import(SpringDataRestConfiguration.class)
I'm working on a Spring Boot project. Implementing Back-End code with the data, I've got an error.
Before working on the security, that is, when I've just done with the MemberRepository, MemberService, and MemberController, it worked well. After I worked on the security, that kind of error occurs.
I'm using IntelliJ as the IDE, and the methods were MySQL, Java, Spring Boot, Spring Security, and Maven. The OS is Mac.
This is a part of MemberRepository.java code:
package com.springboot.reserving.member;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.context.annotation.Bean;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
#Repository
public interface MemberRepository extends CrudRepository<Member, Long> { ... }
This is a part of MemberService.java code:
package com.springboot.reserving.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
#Service
public class MemberService {
#Autowired
MemberRepository memberRepository;
...
}
This is CustomUserDetailService.java code:
package com.springboot.reserving.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Optional;
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
MemberRepository memberRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return Optional.ofNullable(memberRepo.read(username))
.filter(m -> m != null)
.map(m -> new SecurityMember(m)).get();
}
}
The error message was:
Description:
Field memberRepo in com.springboot.reserving.member.CustomUserDetailsService required a bean of type 'com.springboot.reserving.member.MemberRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.springboot.reserving.member.MemberRepository' in your configuration.
What should I do to fix this error?
One possible reason is that spring doesn't create Spring Data Repository out of the interface.
In a nutshell, spring data project generates a "proxy" in runtime - an implementation of the interface that will contain all the required methods for working with the database.
In order to make is possible you should enable this proxy generation for you DAOs:
This can be done with:
#EnableJpaRepositories(basePackages = "com.springboot.reserving.member")
So make sure you have this annotation on spring boot application class.
In my main Controller file, I can not get the annotation #Controller to import and clear the error. I just get "Controller is not an annotation type" which is really confusing.
#Controller
public class Controller {
}
Try renaming the class like below:
import org.springframework.stereotype.Controller;
#Controller
public class MainController {
}
#RestController is more used than Controller. It is imported from org.springframework.web.bind.annotation.RestController;
I am having an issue in which a defined repository is not being correctly interpreted as a bean on server startup. The class with #SpringBootApplication is in a higher directory than the defined repository, so I cannot find why it does not configure.
#SpringBootApplication:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.Properties;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println("http://localhost:8080");
}
}
Repository
package lab14.panoslab.Repositories;
import lab14.panoslab.Models.Account;
import org.apache.catalina.User;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface UserRepository extends JpaRepository<Account,Long> {
#NotFound(action = NotFoundAction.IGNORE)
List<User> findByUsername(String username);
}
Error code:
*************************** APPLICATION FAILED TO START***************************
Description:
Field userRepository in lab14.panoslab.Controllers.RegisterController
required a bean of type 'lab14.panoslab.Repositories.UserRepository'
that could not be found.
Action:
Consider defining a bean of type
'lab14.panoslab.Repositories.UserRepository' in your configuration.
Process finished with exit code 1
Are you sure that your class Account implements the interface User?
And try to remove the annotation #Repository and add annotations #EntityScan and #EnableJpaRepositories in your DemoApplication class:
#SpringBootApplication
#EntityScan({"lab14.panoslab.Models"})
#EnableJpaRepositories({"lab14.panoslab.Repositories"})
public class DemoApplication {...}
Also, I would advise you to rename all your packages into lowercase and return a value of List<Account>, not List<User>.
I did face similar issue. What I have done the mistake is, I have placed my controller/repository and other component packages outside the Main Class package. So, Spring boot not able to identify my components,
For Ex: main class package is package com.example.demo;
Controller package like, package com.example.controller;
Repository package like, package com.example.repository;
Below are the two different ways to solve this problem,
Explicitly defining my component packages in #ComponentScan, like #ComponentScan(basePackages="com.example.controller,com.example.repository") with base packages of required components.
Otherwise, You can create Controller/repository packages inside the main package. So, you no need to define #ComponentScan and all.
For ex,
main class package is package com.example.demo;
Controller package like, package com.example.demo.controller;
Repository package like, package com.example.demo.repository;