Consider defining a bean named 'elasticsearchTemplate' in your configuration - java

I have just started springboot and tried to implement elastic search with spring-boot but I am getting this type of error while running spring-boot app
Consider defining a bean named 'elasticsearchTemplate' in your configuration.
POM.XML
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
Repository
#Repository
public interface StudentRepository extends ElasticsearchRepository<Student, Integer>{}
Controller
#RestController
public class Controller {
#Autowired
StudentRepository studentRepo;
#GetMapping(value="/student/all")
List<Student> getAllStudent() {
Iterator<Student> studentList = studentRepo.findAll().iterator();
List<Student> students = new ArrayList<>();
if(studentList.hasNext()) {
students.add(studentList.next());
}
return students;
}
#PostMapping(value="/student/add")
String addStudent(#RequestBody Student student) {
studentRepo.save(student);
return "Record Added Successfully";
}
#DeleteMapping(value="/student/delete/{id}")
String deleteStudent(#PathVariable int id) {
studentRepo.deleteById(id);
return "Record Deleted Successfully";
}
//#GetMapping(value="/student/findById/{id}")
}
Can Anyone help me to resolve this error
Consider defining a bean named 'elasticsearchTemplate' in your configuration.

You need to define some elastic search properties in your application.properties file such as cluster-nodes, cluster-names which are used by ElasticsearchTemplate and ElasticsearchRepository to connect to the Elasticsearch engine.
You can refer below mentioned link :
https://dzone.com/articles/elasticsearch-with-spring-boot-application

Note: Please refer to the spring-data-elasticsearch-versions or Spring Data Elasticsearch Changelog (check Elasticsearch version of desired release) to check version compatibility.
Solution(1):
If you want to use spring boot 1.x, simply create a #Configuration class and add a ElasticsearchOperations Bean. Please note than spring boot 1.x does not support the latest versions of ElasticSearch 5.x and higher.
cluster.name: make sure the cluster name you set in the code is the same as the cluster.name you set in $ES_HOME/config/elasticsearch.yml
#Configuration
public class ElasticSearchConfig {
#Bean
public ElasticsearchOperations elasticsearchTemplate() throws UnknownHostException {
return new ElasticsearchTemplate(getClient());
}
#Bean
public Client getClient() throws UnknownHostException {
Settings setting = Settings
.builder()
.put("client.transport.sniff", true)
.put("path.home", "/usr/share/elasticsearch") //elasticsearch home path
.put("cluster.name", "elasticsearch")
.build();
//please note that client port here is 9300 not 9200!
TransportClient client = new PreBuiltTransportClient(setting)
.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
return client;
}
}
Solution (2):Also, you can refer to this spring boot issue that shows automatic configuration of the Elasticsearch in the spring data from spring boot 2.2.0.
Therefore, using spring boot 2.2 and spring-boot-starter-elasticserach you don't need to configure the Elasticsearch manually.
Sample working project:
Versions:
spring boot : 2.2.0.RELEASE
Elasticsearch: 6.6.2
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-boot-elasticsearch</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.properties:
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.elasticsearch.jest.uris=http://localhost:9200
Main Application class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Model class:
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
#Document(indexName = "your_index", type = "books")
public class Book {
#Id
private String id;
private String title;
private String author;
private String releaseDate;
//getter, setter/constructors
}
Repository class:
import com.example.model.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface BookRepository extends ElasticsearchRepository<Book, String> {
Page<Book> findByAuthor(String author, Pageable pageable);
List<Book> findByTitle(String title);
}
Service class:
some methods to test:
import com.example.model.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface BookService {
Book save(Book book);
void delete(Book book);
Book findOne(String id);
Iterable<Book> findAll();
Page<Book> findByAuthor(String author, Pageable pageable);
List<Book> findByTitle(String title);
}
Service implementation:
import com.example.model.Book;
import com.example.repository.BookRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class BookServiceImpl implements BookService {
private BookRepository bookRepository;
public BookServiceImpl(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#Override
public Book save(Book book) {
return bookRepository.save(book);
}
#Override
public void delete(Book book) {
bookRepository.delete(book);
}
#Override
public Book findOne(String id) {
return bookRepository.findById(id).orElse(null);
}
#Override
public Iterable<Book> findAll() {
return bookRepository.findAll();
}
#Override
public Page<Book> findByAuthor(String author, Pageable pageable) {
return bookRepository.findByAuthor(author, pageable);
}
#Override
public List<Book> findByTitle(String title) {
return bookRepository.findByTitle(title);
}
}
Test class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
public class BookTest {
#Autowired
private BookService bookService;
#Autowired
private ElasticsearchTemplate esTemplate;
#Before
public void before(){
esTemplate.deleteIndex(Book.class);
esTemplate.createIndex(Book.class);
esTemplate.putMapping(Book.class);
esTemplate.refresh(Book.class);
}
#Test
public void testSave(){
Book book = new Book("1001", "Elasticsearch", "title", "23-FEB-2017");
Book testBook = bookService.save(book);
assertNotNull(testBook.getId());
assertEquals(testBook.getTitle(), book.getTitle());
assertEquals(testBook.getAuthor(), book.getAuthor());
assertEquals(testBook.getReleaseDate(), book.getReleaseDate());
}
}

Related

connect spring boot to swagger

I am trying to connect my e-commerce project backend to swagger2. I have installed all the dependencies, yet I still cannot do it.
This is the dependency declared in my pom.xml file:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This is one of my user controller files:
#RestController
#RequestMapping("/api")
#CrossOrigin
public class UserController {
#Autowired
private UserRepository userRepository;
#GetMapping("/")
public List<User> GetUsers() {
return userRepository.findAll();
}
#GetMapping("/{id}")
public User GetUser(#PathVariable String id) {
return userRepository.findById(id).orElse(null);
}
#PostMapping("/")
public User postMethodName(#RequestBody User user) {
return userRepository.save(user);
}
#PutMapping("/")
public User PutMapping(#RequestBody User newUser) {
User oldUser = userRepository.findById(newUser.getId()).orElse(null);
oldUser.setName(newUser.getName());
oldUser.setEmail(newUser.getEmail());
oldUser.setPassword(newUser.getPassword());
userRepository.save(oldUser);
return oldUser;
}
#DeleteMapping("/{id}")
public String DeleteUser(#PathVariable String id) {
userRepository.deleteById(id);
return id;
}
}
This is the code of my main application:
package com.omazon.ecommerce;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#SpringBootApplication
#EnableSwagger2
public class ECommerceApplication {
public static void main(String[] args) {
SpringApplication.run(ECommerceApplication.class, args);
}
}
Lastly, this is what I declared in the application.properties file:
spring.data.mongodb.uri=mongodb://localhost:27017/e-commerce
This is the picture of the error I got:
Swagger2's usage seems to require (or at least often includes) the concept of a Docket api via an instantiation such as new Docket() or new Docket(DocumentationType.SWAGGER_2). I don't see that in your code snippets, so wonder if that may be one issue.
Per the swagger docs, Docket is Springfox’s primary api configuration mechanism.
Specifically, this section regarding configuration may be helpful. Note the Docket instantiation:
...
#Bean //Don't forget the #Bean annotation
public Docket customImplementation(){
return new Docket()
.apiInfo(apiInfo());
//... more options available
...
There's also a more complete example in those same docs here.
For reference, there's another usage example in this tutorial.

SpringBoot doesn't scan for components in microservices app

I'm coding microservices app based on Spring Cloud. I launched Eureka Server and now i'm coding a car-service. It worked when I didn't have any Autowiring in project. After adding Repository, Service and changing Controller the car-service doesn't launch.
When I added #SpringBootApplication("com.carrental.carservice.repository") application started but Rest API doesn't work and return 404. I tried with #Qualifier and naming Repository but still doesn't work.
There is an error when starting:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.carrental.carservice.service.impl.CarTypeServiceImpl required a bean of type 'com.carrental.carservice.repository.CarTypeRepository' that could not be found.
Action:
Consider defining a bean of type 'com.carrental.carservice.repository.CarTypeRepository' in your configuration.
And there is a WARN in logs:
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.carrental.carservice.repository.CarTypeRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
pom.xml of car service
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>carrental</artifactId>
<groupId>com.carrental</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>car-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.9.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
</project>
starting application file
package com.carrental.carservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#EnableEurekaClient
//#ComponentScan("com.carrental.carservice.repository")
public class CarServiceApp {
public static void main(String[] args) {
SpringApplication.run(CarServiceApp.class, args);
}
}
controller
package com.carrental.carservice.controller;
import com.carrental.carservice.dto.CarTypeDto;
import com.carrental.carservice.model.entity.CarType;
import com.carrental.carservice.service.CarTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
#RestController
#RequestMapping("/car")
public class CarTypeController {
private final CarTypeService carTypeService;
#Autowired
public CarTypeController(CarTypeService carTypeService){
this.carTypeService = carTypeService;
}
#PostMapping("/cartype/add")
public ResponseEntity<CarTypeDto> addCarType(#Valid #RequestBody CarTypeDto dto){
CarType entity = Mapper.mapToCarTypeEntity(dto);
this.carTypeService.add(entity);
return new ResponseEntity<CarTypeDto>(Mapper.mapToCarTypeDto(entity), HttpStatus.CREATED);
}
#GetMapping
public String get(){
return "jajo";
}
}
service
package com.carrental.carservice.service.impl;
import com.carrental.carservice.model.entity.CarType;
import com.carrental.carservice.repository.CarTypeRepository;
import com.carrental.carservice.service.CarTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class CarTypeServiceImpl implements CarTypeService {
private final CarTypeRepository carTypeRepository;
#Autowired
public CarTypeServiceImpl(CarTypeRepository carTypeRepository){
this.carTypeRepository = carTypeRepository;
}
#Override
public void add(CarType carType) {
if(this.carTypeRepository.existsByName(carType.getName()))
return;
this.carTypeRepository.save(carType);
}
#Override
public List<CarType> getAll() {
return this.carTypeRepository.findAll();
}
#Override
public void update(CarType carType) {
if(this.carTypeRepository.existsById(carType.getId()))
this.carTypeRepository.save(carType);
}
#Override
public void delete(CarType carType) {
this.carTypeRepository.delete(carType);
}
}
repository
package com.carrental.carservice.repository;
import com.carrental.carservice.model.entity.CarType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CarTypeRepository extends JpaRepository<CarType, Long> {
boolean existsByName(String name);
CarType getByName(String name);
boolean existsById(Long id);
}
I tried a lot of stuff and still doesn't work. Can you help, please?
i think you need to use feignClient to avoid this exception.i had similar issue and added
#EnableFeignClients to my ApplicationClass and its dependency to your pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId
</dependency>

Repository won't Beanify

I have an error that I can't track down. I'm new so sorry if I missed this in the searches, but I tried several things and no luck.
UserApi.java:
package com.jsp.jsp;
import com.jsp.models.User;
import com.jsp.services.UserService;
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.bind.annotation.RestController;
#RestController
class UserApi {
private final UserService userService;
public UserApi(UserService userService) {
this.userService = userService;
}
#RequestMapping(value="/api/user", method=RequestMethod.POST)
public User createUser(
#RequestParam(value="name", required=true) String name,
#RequestParam(value="email", required=true) String email,
#RequestParam(value="password", required=true) String password,
#RequestParam(value="confirm", required=true) String confirm)
{
User u = this.userService.createUser(new User(name, email, password));
return u;
}
}
UserRepository.java:
package com.jsp.repositories;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
import com.jsp.models.User;
import org.springframework.data.repository.CrudRepository;
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByEmail(String email);
Optional<User> findById(Long id);
List<User> findAll();
}
Server.java
package com.jsp.jsp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication(scanBasePackages={"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#RestController
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
UserService.java
package com.jsp.services;
import java.util.List;
import com.jsp.models.User;
import com.jsp.repositories.UserRepository;
import org.springframework.stereotype.Service;
#Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> allUsers() {
return this.userRepository.findAll();
}
public User createUser(User u) {
return this.userRepository.save(u);
}
}
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 http://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.1.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.jsp</groupId>
<artifactId>jsp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.7.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
So in short, when I run the above project in VSCode, it errors out with the following:
2019-02-23 19:07:52.744 WARN 25412 --- [ restartedMain]
ConfigServletWebServerApplicationContext : Exception encountered
during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'userService' defined in file
[C:\Users\Alex\Documents\dojo\javatown\everything\target\classes\com\jsp\services\UserService.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'com.jsp.repositories.UserRepository'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations: {}
My understanding is that the repository I made should be automatically turned into a bean and then wire itself up to the service I made. However, that seems to be not happening. My example videos are using MySQL -- will that make a difference? Am I using the right driver for Postgres 11? I'm super lost.
Some remarks and suggestions:
1.add autowired annotation on your constructor, it is clearer what you need spring to do.
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
2. I don't understand #RestController annotation on your main class.
#SpringBootApplication(scanBasePackages {"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#RestController --> THIS CAN BE REMOVED
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
3.You should add #EnableJpaRepositories("com.jsp.repositories") on your spring boot application => it will scan the repositories in that package.
#SpringBootApplication(scanBasePackages {"com.jsp.models","com.jsp.repositories","com.jsp.services"})
#EnableJpaRepositories("com.jsp.repositories")
public class Server {
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}

How to fix 'HTTP-404' error, during GET request in REST web service using spring boot

My sample spring boot REST web service gives 404 error, and I am not sure what went wrong
package com.in28minutes.springboot.studentservices;
#SpringBootApplication
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}
package com.in28minutes.springboot.controller;
#RestController
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping("/students/{studentId}/courses")
public List<Course> retrieveCoursesForStudent(#PathVariable String
studentId) {
return studentService.retrieveCourses(studentId);
}
#GetMapping("/students/{studentId}/courses/{courseId}")
public Course retrieveDetailsForCourse(#PathVariable String studentId,
#PathVariable String courseId) {
return studentService.retrieveCourse(studentId, courseId);
}
}
My Request from POSTMan REST request sender:
http://localhost:8080/students/stu1/courses/course1
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
http://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.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.in28minutes.springboot</groupId>
<artifactId>student-services</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>student-services</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Response:
{
"timestamp": "2018-12-28T02:48:00.185+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/students/stu1/courses/course1"
}
As assumed, you have Controller classes in different package com.in28minutes.springboot.controller; and Spring boot main class in different package com.in28minutes.springboot.studentservices;
#SpringBootApplication
By default #SpringBootApplication will only scan from the package of the class that declares this annotation.
This is a convenience annotation that is equivalent to declaring #Configuration, #EnableAutoConfiguration and #ComponentScan.
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
use #ComponentScan to scan controller package
#ComponentScan(basePackages = {"com.in28minutes.springboot.controller"})
#SpringBootApplication
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}
More Info : ref
The issue is resolved, #Component needed to be added to Service class, along with #ComponentScan in the main application class:
package com.in28minutes.springboot.service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import com.in28minutes.springboot.model.Course;
import com.in28minutes.springboot.model.Student;
#Component
public class StudentService {
public List<Course> retrieveCourses(String studentId) {
Map<String, Course> courses = Student.getStudentObj(studentId).getCourses();
List<Course> courseList =
courses.values().parallelStream().collect(Collectors.toList());
return courseList;
}
public Course retrieveCourse(String studentId, String courseId) {
return Student.getStudentObj(studentId).getCourses().get(courseId);
}
}
package com.in28minutes.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("com.in28minutes.springboot")
public class StudentServicesApplication {
public static void main(String[] args) {
SpringApplication.run(StudentServicesApplication.class, args);
}
}

Null Pointer Exception for JdbcTemplate with SpringMVC

I'm pretty new to Java, but I wanted to try to build a simple project with SpringMVC. It's just a simple CRUD app that should allow people to post notes.
When attempting to submit the form or query for notes, I get a null pointer exception when I attempt to call methods on JdbcTemplate. Here is the code for my application class:
package mvc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;
#SpringBootApplication
public class SpringMvcApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringMvcApplication.class, args);
}
#Autowired
JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void run(String... string) throws Exception {
System.out.println("Creating tables");
jdbcTemplate.execute("drop table notes if exists");
jdbcTemplate.execute(("create table notes(" +
"id serial, content varchar(255), author varchar(255))"));
}
public static SpringMvcApplication instance = new SpringMvcApplication();
public static SpringMvcApplication getInstance() { return instance; }
}
Here is my NoteController.java:
package mvc;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class NoteController {
#RequestMapping("/notes")
public String index() {
return "index";
}
#RequestMapping("/notes/new")
public String newNote(Model model) {
model.addAttribute("note",new Note());
return "new";
}
#RequestMapping(value="/notes", method= RequestMethod.POST)
public String create(Note note, Model model) {
model.addAttribute("note", note);
Note.create(note.getContent(), note.getAuthor());
return "show";
}
#RequestMapping(value = "/notes/{noteId}", method=RequestMethod.GET)
public String show(#PathVariable String noteId) {
long id = Long.parseLong(noteId);
Note note = Note.find(id);
return "show";
}
}
My Note model:
package mvc;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public class Note {
private Long id;
private String content;
private String author;
public Note() {}
public Note(Long id, String content, String author) {
this.id = id;
this.content = content;
this.author = author;
}
public Long getId() {
return id;
}
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
public String toString() {
return content + "by " + author;
}
public static void create(String content, String author) {
JdbcTemplate jdbcTemplate = SpringMvcApplication.getInstance().getJdbcTemplate();
jdbcTemplate.update("INSERT INTO notes(content, author) values (?,?)", content, author);
}
public static Note find(Long id) {
JdbcTemplate jdbcTemplate = SpringMvcApplication.getInstance().getJdbcTemplate();
List<Note> notes = jdbcTemplate.query("SELECT id, content, author FROM notes WHERE id = ?", new Object[]{id},
new RowMapper<Note>() {
#Override
public Note mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Note(rs.getLong("id"), rs.getString("content"),
rs.getString("author"));
}
});
return notes.get(0);
}
}
Here's my 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>mvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring MVC</name>
<description>MVC Project for Ship It Saturday</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>mvc.SpringMvcApplication</start-class>
<java.version>1.7</java.version>
</properties>
<dependencies>
<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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1100-jdbc41</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
I'm not really sure what the issue is with my code here. I was following a few different guides but most of them weren't too clear on what code was doing what. I'm sure there are probably some really obvious issues here, but I'm totally new to Spring and Java so I'm not seeing it.
EDIT:
Here is what I think are the relevant lines of the trace:
2015-04-11 19:01:35.125 ERROR 24895 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at mvc.Note.create(Note.java:44)
at mvc.NoteController.create(NoteController.java:30)
I should also mention that the run() method in the SpringMVCApplication class works just fine at creating the table, and if I move the insert and query statements into that method with static data the also work. It's only when I move them into their own methods so that I can use them dynamically that everything falls apart.
As already mentioned in the comments your SpringMvcApplication.getInstance() will not work as expected. You need something to connect the "spring-world" with the "not-spring-world". A possible solution would be to save the ApplicationContext as singleton.
#SpringBootApplication
public class SpringMvcApplication {
private static ApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(SpringMvcApplication.class, args);
}
public static JdbcTemplate getJdbcTemplate() {
return context.getBean(JdbcTemplate.class);
}
}
Maybe you have to adapt it to your needs.

Categories

Resources