I have a Spring Boot project using Jersey as my REST service and using AngularJS for my front end development. While I run it without using any controller and go to index.html (which is in resource/static/index.html) it works fine. When I add a controller it renders gives the string "index.html" as an output. Spring Boot Configuration:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages = {"com.cst.interfaces","com.cst.configuration","com.cst.application","com.cst.application.implmentation"})
#EnableAutoConfiguration
public class ApplicationConfiguration {
public static void main(String args[]) throws Exception{
SpringApplication.run(ApplicationConfiguration.class, args);
}
public ServletRegistrationBean jerseyServlet(){
ServletRegistrationBean register = new ServletRegistrationBean(new ServletContainer(),"/*");
register.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyInitalize.class.getName());
return register;
}
}
JerseyConfiguration:
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
#Component
public class JerseyInitalize extends ResourceConfig{
public JerseyInitalize(){
super();
this.packages("com.cst.interfaces");
}
}
Controller Class:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Path("/home")
public class HomeResource {
#GET
#Produces("application/json")
public String getString(){
return "index.html";
}
}
This is because you annotated your controller with #RestController, which is a shorthand for #Controller with #ResponseBody. The latter annotation instructs the controller to render the output as-is directly into the response.
Use #Controller for controllers that are not RESTful instead.
Related
Basically, I have created all of the pojo and layers(including the repository layer) necessary for Spring Boot to automatically implement MySql commands. When I trying to run the programme, I get the following command:
Description:
Parameter 0 of constructor in com.fsse2207.project_backend.api.ProductApi required a bean of type 'com.fsse2207.project_backend.service.ProductService' that could not be found.
Action:
Consider defining a bean of type 'com.fsse2207.project_backend.service.ProductService' in your configuration.
It turns out there's sth wrong about the bean in my ProductApi. It says "
Could not autowire. No beans of 'ProductService' type found." How do I fix it?
The following is the interface under the service layer:
package com.fsse2207.project_backend.service;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import org.springframework.stereotype.Service;
public interface ProductService {
ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException;
}
The following is the service class:
package com.fsse2207.project_backend.service.impl;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.entity.ProductEntity;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.repository.ProductRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductServiceImpl {
private ProductRepository productRepository;
#Autowired
public ProductServiceImpl(ProductRepository productRepository){
this.productRepository=productRepository;
}
public ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException {
ProductEntity productEntity=new ProductEntity(productCreateData);
if(productRepository.existsById(productEntity.getpId())){
throw new ProductFoundByIdException();
}
return new ProductDetailData(productRepository.save(productEntity));
}
}
The following is the Api:
package com.fsse2207.project_backend.api;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.dto.CreateRequestDto;
import com.fsse2207.project_backend.data.dto.CreateResponseDto;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductApi {
private ProductService productService;
#Autowired
public ProductApi(ProductService productService){
this.productService=productService;
}
#PostMapping
public CreateResponseDto createResponseDto(#RequestBody CreateRequestDto createRequestDto) throws ProductFoundByIdException {
ProductCreateData productCreateData=new ProductCreateData(createRequestDto);
ProductDetailData productDetailData =productService.createProductData(productCreateData);
return new CreateResponseDto(productDetailData);
}
}
I found the problem:
I didn't add the implements keyword in the class definition of ProductServiceImpl so it was not connected to the bean, aka the interface, aka the service layer.
First of all you should not add annotation #Service for ProductService interface.
Moreover this can happen when you have your Class Application in "another package".
You can solve the problem using annotation #ComponentScan (basePackages = {"your.company.domain.package"})
I have a repository, annotated with #Repository
package com.jeppa.interfaces;
import com.jeppa.entities.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends CrudRepository<User, String> {
User findByUserEmailIgnoreCase(String useremail);
}
Part of my controller:
package com.jeppa.controllers;
import com.jeppa.entities.ConfirmationToken;
import com.jeppa.entities.User;
import com.jeppa.interfaces.TokenRepository;
import com.jeppa.interfaces.UserRepository;
import com.jeppa.mail.EmailSenderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class UserAccountController {
#Autowired
private UserRepository userRepository;
#Autowired
private TokenRepository tokenRepository;
#Autowired
private EmailSenderService emailSenderService;
#RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView displayRegistration(ModelAndView modelAndView, User user){
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
//////////////
And, finnaly, my #SpringBootApplication:
package com.jeppa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RunApplication {
public static void main(String[] args) {
SpringApplication.run(RunApplication.class, args);
}
}
and i keep getting this error
*************************** APPLICATION FAILED TO START
Description:
Field userRepository in com.jeppa.controllers.UserAccountController
required a bean of type 'com.jeppa.interfaces.UserRepository' 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.jeppa.interfaces.UserRepository'
in your configuration.
what am i doing wrong? here's my project structure:
structure
With Spring Boot, you should generally rely on Spring Boot starters to autoconfigure your dependencies. In case of Spring Data add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
into your pom file to autoconfigure Spring Data instead of directly relying on Spring Data (spring-data-jpa), which requires further manual configuration.
Also don't forget to add and configure an actual implementation as well (h2, jdbc, etc.)
I wanted to play around with the different types of bean scopes. So I wrote a test environment which should generate a random number so I could see if a bean had changed. My test setup does not work and I can not explain what I found out.
I'm using Spring Boot 2.13 with the Spring Framework 5.15.
Following setup:
Main class:
package domain.webcreator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class WebcreatorApplication {
public static void main(String[] args) {
SpringApplication.run(WebcreatorApplication.class, args);
}
}
Beans class:
package domain.webcreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
#Configuration
public class Beans {
#Bean
public Random randomGenerator() {
return new Random();
}
}
Scoper class:
package domain.webcreator;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import java.util.Random;
#Service
#Scope("singleton")
public class Scoper {
private Random rand;
public Scoper(Random rand) {
this.rand = rand;
}
public int getNumber(int max) {
return rand.nextInt(max);
}
}
Index Controller
package domain.webcreator.controller;
import domain.webcreator.Scoper;
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.ResponseBody;
#Controller
public class IndexController {
#GetMapping("/")
#ResponseBody
#Autowired
public String indexAction(Scoper scoper) {
return String.valueOf(scoper.getNumber(50));
}
}
My problem is, that I get an NPE while calling scoper.getNumber(50).
This is strange because when debugging, a Random bean is generated and passed to the scoper constructor.
Later on, in the controller, the rand property is null.
What am I doing wrong?
You're trying to apply #Autowired to a random method, which isn't how Spring works. Controller method parameters are for information specific to that HTTP request, not general dependencies, and so Spring is trying to create a new Scoper that is associated with the request--but it doesn't have any incoming values in the request to fill in. (I'm actually surprised you're not getting an error about no default constructor.)
Instead, pass your Scoper in a constructor.
#RestController
public class IndexController {
private final Scoper scoper;
public IndexController(Scoper scoper) {
this.scoper = scoper;
}
#GetMapping("/")
public String indexAction(Scoper scoper) {
return String.valueOf(scoper.getNumber(50));
}
}
A couple of notes:
Singleton scope is the default, and there's no need to specify it.
#RestController is preferable to repeating #ResponseBody unless you have a mixed controller class.
I am just getting into spring-cloud-config and I'm working on this basic project. I would like to know if it is possible and how to rewrite this client to not use Spring Boot.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#EnableAutoConfiguration
#ComponentScan
#RestController
#RefreshScope
public class ClientApp {
#Value("${bar:World!}")
String bar;
#RequestMapping("/")
String hello() {
return "Hello " + bar + "!";
}
public static void main(String[] args) {
SpringApplication.run(ClientApp.class, args);
}
}
The reason for this is that we are thinking of using spring-cloud-config in our spring batch web service, but we use the old spring with xmls, not spring boot. I couldn't find any documentation related to this.
I'm coding a Spring server and I am using Retrofit to make the api calls.
I have the next interface for the Retrofit client:
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.POST;
public interface AuthSvcApi {
public static final String AUTHENTICATION_PATH = "/authToken";
#POST(AUTHENTICATION_PATH)
public boolean loginUser(#Body String accessToken);
}
Then my controller is:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.purposes.client.AuthSvcApi;
#Controller
public class AuthSvc{
#RequestMapping(value=AuthSvcApi.AUTHENTICATION_PATH, method = RequestMethod.POST)
public #ResponseBody boolean loginUser(#RequestBody String accessToken) {
CheckAccessToken checkAccessToken = new CheckFacebookAccessToken();
checkAccessToken.checkToken(accessToken);
return false;
}
}
The method isn't finished, but it should work. And the application class is:
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.web.servlet.config.annotation.EnableWebMvc;
//Tell Spring to automatically inject any dependencies that are marked in
//our classes with #Autowired
#EnableAutoConfiguration
//Tell Spring to turn on WebMVC (e.g., it should enable the DispatcherServlet
//so that requests can be routed to our Controllers)
#EnableWebMvc
//Tell Spring to go and scan our controller package (and all sub packages) to
//find any Controllers or other components that are part of our applciation.
//Any class in this package that is annotated with #Controller is going to be
//automatically discovered and connected to the DispatcherServlet.
#ComponentScan
//Tell Spring that this object represents a Configuration for the
//application
#Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I don't know why this doesn't work fine, but I am going crazy because the response is:
No mapping found for HTTP request with URI [/authToken] in DispatcherServlet with name 'dispatcherServlet'
Looks like you need to include AuthSvcApi.AUTHENTICATION_PATH
to this line:
.setEndpoint(SERVER).build()
Like this:
.setEndpoint(SERVER + AuthSvcApi.AUTHENTICATION_PATH).build()
Well, I found the solution, the problem was that the annotation #ComponentScan didn't find the package where the controller was. I resolve the problem indicating to the annotation the package where the controller is.
#ComponentScan(basePackages={"com.purposes.controllers"})