Spring boot 2: Fail to reach controller method - spring

I am having some spring boot rest tutorial.
I fail to reach the controller method when I call:
http://localhost:8090/customers/stam
Tomcat log:
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s):
8090 (http) with context path ''
t.s.SpringbootRestDemoApplication : Started SpringbootRestDemoApplication in 2.696 seconds (JVM running for 4.042)
The response I get:
{
"timestamp": "2019-06-02T12:25:03.400+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/customers/stam"
}
Can you assist?
package ttt.springboot_rest_demo;
import ...
#SpringBootApplication
#ComponentScan({"springboot_rest_demo.controller", "springboot_rest_demo.data"})
public class SpringbootRestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootRestDemoApplication.class, args);
}
}
package ttt.springboot_rest_demo.controller;
import ...
#RestController
#RequestMapping("/customers")
public class CustomerController {
#RequestMapping(value = "/stam", method = RequestMethod.GET)
public ResponseEntity < Customer > getCustomer() {
return new ResponseEntity < >(new Customer(), HttpStatus.OK);
}
}
package ttt.springboot_rest_demo.data;
public class Customer {
private String name;
private int age;
private String email;
private Long id;
//getters and setters
}
This is only a part of the project. I use also a service class but because I have failed, I a added a simple controller method which doesn't need the service class for now, just to ease the example.

Your ComponentScan is incorrect, please check the packages (these package names do not exists):
#ComponentScan({"springboot_rest_demo.controller", "springboot_rest_demo.data"})
Your controller is in ttt.springboot_rest_demo.controller package. Change the package name in the ComponentScan to this package.
#ComponentScan({"ttt.springboot_rest_demo.controller", "springboot_rest_demo.data"})
Alternatively just leaving out the ComponentScan will also work for you, because then you will rely on the default behaviour of Spring Boot to scan all packages under the SpringBootApplication.
Note that if your controller is not a managed bean (for example not scanned by ComponentScan) any Spring annotation you add (like RequestMapping, RestController) is ignored.

Related

Spring boot get #value within a class extending a dependency

Folks, am trying to access config properties from within a class that I've extended from a dependency. Apparently the config class is returning a null pointer in my implementation class (CustomUtil).
pom.xml
...
<dependency>
<groupId>com.utilapp</groupId> //3rd party library that I need to use
<artifactId>util-lib</artifactId>
</dependency>
...
The BaseUtil is from the dependency. CustomUtil is a bean in my SpringBoot App & am overriding the method as below to check the key from the config property ignoreKeyList .
package com.myapp
...
#Component
public class CustomUtil extends BaseUtil {
#Autowired
private ClientConfig clientConfig; // This returns null!
#Override
protected boolean shouldExcludeFromList(String key) {
return this.clientConfig.getIgnoreKeyList.contains(key); // their library/util excludes certain keywords from the content being formatted
}
}
Config class in my SpringBoot App.
package com.myapp
...
#Configuration
#Getter
#Setter
public class ClientConfig {
#Value("${myapp.ignorekeys}")
private List<String> ignoreKeyList;
...
...
}
Main class in my app.
package com.myapp
...
#SpringBootApplication
public class MyClientApplication {
public static void main(String[] args) {
SpringApplication.run(MyClientApplication.class, args);
}
}
Service implementation class in my SpringBoot App.
package com.myapp
import com.utilapp.formatters.FormatBuilder;
import com.utilapp.formatters.TextFormatter;
...
#Service
public class ServiceImpl implements MyService {
#Autowired
private ClientConfig clientConfig; // works here!
public String formatContent(String content) {
TextFormatter formatter = this.getTextFormatter();
return formatter.parseAndFormat(content);
}
private TextFormatter getTextFormatter() {
return FormatBuilder.custom() // FormatBuilder is from the dependency
.withApplication(this.clientConfig.getAppName()) // In their library, the BaseUtil gets instantiated which am extending in my CustomUtil bean
...
...
.withIndentSupport(Boolean.TRUE)
.build();
}
}
Controller in my app
package com.myapp
...
#RestController
#RequestMapping("/app/v1")
public class StyleController {
#Autowired
private MyService myService;
#GetMapping("/format")
public String formatContent(#RequestParam String content) {
return this.myService.formatContent(content);
}
}
When I debug ClientConfig, it loads the properties from the config file; application.properties in src\main\resources.
But for some reason the ClientConfig is returning null from within the CustomUtil bean. Not sure why!
I originally thought it was due to ordering of bean instantiation. I tried playing around with #Order, #DependsOn, #ComponentScan, #ScanBasePackages etc, but none yields.
Any pointers/guidance please.
Thanks.

Controller Method not returning value

I am building a spring boot application .This is my RestController
#RestController
#RequestMapping("api/v1/bikes")
public class BikeController {
#GetMapping
public String s(){
return " show this message";
}
When i paste the following URL in the POSTMAN i get the following message
http://localhost:8080/api/v1/bikes
{
"timestamp": "2018-06-16T21:19:17.791+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/v1/bikes"
}
Why i am getting the error ?I expect to see the message returned by the method s().
My project name is bike and it's structure is below
**bike
-- src/main/java
--------- com.globomatics.bike (here is my main class)
--------- controllers**
And this is my main class
#SpringBootApplication
public class BikeApplication {
public static void main(String[] args) {
SpringApplication.run(BikeApplication.class, args);
}
}
The problem is that you #RestController is not being scanned by you #SpringBootApplication. You can do two things here. Either move the controller in the same package as your main class or specify that you want to scan other packages. Something like #SpringBootApplication(scanBasePackages = {"com.globomatics.*"}). Check out the documentation here and here where all of those things are very well explained.
#SpringBootApplication by defult will always scan the same package in which class with main method is present and all the packages inside it. In your case your package with class containing main method is "com.globomatics.bike" so your class BikeController should be either in same package or the the package containing class BikeController must be inside package "com.globomatics.bike". Or you can tell explcitly to scan in some other packages by use of annotation
#ComponentScan("package name you want spring to scan").
change you code to :
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("controllers")
public class BikeApplication {
public static void main(String[] args) {
SpringApplication.run(BikeApplication.class, args);
}
}

Why does Spring boot returns 404 error, but works if I place all methods of all controllers under one controller class?

I get 404 error when I try to send a request to access handleFileUpload( ) method
But if I place handleFileUpload( ) in DetailsController.java things work. Why is that? I'm using Spring boot.
I have two controller classes.
I don't have ServletInitializer.java
com.amazon.s3
|__ AmazonS3Controller.java
com.myproject
|__ DetailsController.java
This is how my #SpringBootApplication class looks like
#SpringBootApplication //This annotation means, it is the starting point of the app.
public class QqdApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(QqdApplication.class, args);
}
DetailsController.java
#RestController
#Component
public class DetailsController {
#Autowired
private DetailsService detailsService;
#RequestMapping("/contactUs")
public ModelAndView contactUs(){
ModelAndView mav = new ModelAndView();
mav.setViewName("contactUs");
return mav;
}
}
AmazonS3Controller.java
package com.amazon.s3;
import com.amazon.s3.AmazonS3Template;
import com.amazonaws.services.s3.model.*;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.annotation.MultipartConfig;
#RestController
#RequestMapping("/s")
public class AmazonS3Controller {
private AmazonS3Template amazonS3Template;
private String bucketName;
#Autowired
public AmazonS3Controller(AmazonS3Template amazonS3Template, #Value("${amazon.s3.default-bucket}") String bucketName) {
this.amazonS3Template = amazonS3Template;
this.bucketName = bucketName;
}
#PostMapping(value = "upload", headers = "Accept=*/*")
#ResponseBody
public String handleFileUpload() {
JSONObject result = new JSONObject();
try {
// System.out.println("we ar ehere" + file.getName() + " " + file.getContentType() + " " + file.getSize());
result.put("link", "https://static.swappa.com/static/icons/stars/star-on-small-green.png");
System.out.println("imgae returned");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return new JSONArray().put(result).toString();
}
}
My application.properties looks like
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
#AWS details
amazon.s3.default-bucket=<someVal>
#Database
spring.datasource.....=....
#Hibernate
entitymanager.packagesToScan:com
spring.jpa.....=....
PS: Ok, After renaming the com.amazon.s3 to com.myproject.s3 things are working. But, I still don't get why it wasn't working before and why its working now.
P.S.S: I typed the above three lines here rather than comment, because SOF keep on telling me that there was too much code and less text. Sorry I cannot write stories here. I feel I gave enough details. Thanks.
The annotation #SpringBootApplication includes #ComponentScan:
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan with their
default attributes:
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-using-springbootapplication-annotation.html
#ComponentScan will, by default, scan for annotations from the package of the class the annotation is residing on ( i.e. the package of QqdApplication)
If specific packages are not defined, scanning will occur from the
package of the class that declares this annotation.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html
So the #PostMapping annotation was not being captured when placed in a controller in the package com.amazon.s3 to com.myproject.s3. Either you had to change the package to be under a scanned location, or you had to specify which packages to scan in the #ComponentScan annotation.

Fallback method is not being called when rest call is failed by using feign client

I am trying to implement fallback by using Feign client but not getting success.Its a simplest code Please find below.
Main Class
#SpringBootApplication
#EnableDiscoveryClient
#RestController
#EnableFeignClients
public class EurekaClient1Application {
#Autowired
public DiscoveryClient discoveryClient;
public static void main(String[] args) {
SpringApplication.run(EurekaClient1Application.class, args);
}
#Autowired
FeingInterface feingInterface;
#GetMapping("/hi/{name}")
public String test(#PathVariable String name)
{
String h = feingInterface.test(name);
return h;
}
}
Feign interface
#FeignClient(name="client22",fallback=FallBack.class)
public interface FeingInterface {
#GetMapping("/hiname/{name}")
public String test(#PathVariable("name") String name);
}
fallback class
#Component
class FallBack implements FeingInterface{
#Override
public String test(String name) {
// TODO Auto-generated method stub
return "fall back methord being called";
}
}
Getting Error in rest client but not from fallback method
"timestamp": 1501950134118,
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.RuntimeException",
"message": "com.netflix.client.ClientException: Load balancer does not have available server for client: client22",
To get the fallback method message I passed client22 eureka id which is not there in eureka server. I have stater-feign in pom. Can someone look into this.
Fallbacks are actually not handled by Feign itself, but by a circuit breaker. So, you need to put Hystrix (which is the Netflix circuit breaker) on your classpath and enable it in your application.yml file like this:
feign:
hystrix:
enabled: true
If you're using 'cloud:spring-cloud-starter-openfeign' in your build.gradle or pom.xml file, Hystrix should be automatically on your classpath.

Spring Boot | MyBatis project structure can't wire layers

Can't wire layers in Spring Boot | MyBatis application. The problem is probably happening when Service layer uses Mapper.
Controller method sample:
#Controller
#RequestMapping("demo")
public class MessageController {
#Autowired
private MessageService messageService;
#RequestMapping(value = "messages", method = RequestMethod.GET)
public String getMessages(ModelMap modelMap) {
modelMap.addAttribute(MESSAGE,
messageService.selectMessages());
return "messages";
}
Service class:
#Service
public class MessageService {
#Autowired // Not sure if I can use Autowired here.
private MessageMapper messageMapper;
public MessageService() {
}
public Collection<Message> selectMessages() { return
messageMapper.selectAll(); }
}
MyBatis Mapper:
#Mapper
public interface MessageMapper {
#Select("select * from message")
Collection<Message> selectAll();
}
UPDATE
It feels like I'm having some fundamental knowledge based mistake. Probably managing external libraries.
Here's maven pom.xml. Looks kind of overloaded, I faced a lot of errors managing different spring-boot packages. Starter for autoconfiguration included.
pom.xml
Here's the project structure:
UPDATE #2
I'm sure DB connection is working well, I'm able to track changes in MySQL Workbench while Spring Boot is executing schema.sql and data.sql. But somehow, MyBatis mapper methods throw NullPointerException and page proceeds with exit code 500. Seems like they can't connect.
MessageService isn't managed by spring.
You have to annotate the MessageService class with #Service annotation (also, after adding this annotation you can indeed use #Autowired inside the service class)
#Service
public class MessageService {
#Autowired
private MessageMapper messageMapper;
public Collection<Message> selectMessages() {
return messageMapper.selectAll();
}
}
and wire it to the controller with
#Autowired
private MessageService messageService
and use it in a method like this
#RequestMapping(value = "messages", method = RequestMethod.GET)
public String getMessages(ModelMap modelMap) {
modelMap.addAttribute(MESSAGE, messageService.selectMessages());
return "messages";
}

Resources