In this article, I will discuss an example of the Spring Data Solr CRUD Application using Spring Boot. I have already discussed the Spring Data Solr such how to install Apache Solr and how to configure the Spring Data Solr to your spring application.
Spring Data provides an easy and very generic way to create the repositories for each technology such as Solr, Cassandra, MongoDB, JPA etc. In Spring Data Solr tutorial, I have discussed how to create Spring Data Solr repositories using Spring Data interface or custom repository creation without using Spring Data repository interface. Also, we have learned to create dynamic Solr queries and sorting the Solr query results. And how to render this Solr query result with pagination.
Let’s create an application with CRUD operation using Spring Data Solr and Spring Boot.
Spring Data Solr CRUD Application
As we know that the Apache Solr is an open source ready to deploy enterprise full-text search engine. But in this article, I will show you how to do a simple Solr configuration and how to interact with the Solr server. Let’s first start the Solr server as we have configured in the previous articles as the following diagram:
As you can see in the above diagram, the Solr server is started now and running at the 8983 port. You can see the running Solr by launching the Solr Admin UI in your web browser: http://localhost:8983/solr/ as the following:
You can see the above diagram of the Solr server admin dashboard. Finally, you can create the collections in the Solr server. And we will use these collections into our application for CRUD operations. Let’s create collections by using the following command.
bin\solr create -c Order
After creating the Order collection, let’s move to index this collection with Data using application.
Adding Spring Data to application
Spring team has created Spring Data projects to simplify DAO layer implementation and removing boilerplate codes. Like other Spring Data project. Spring Data Solr is also created for removing boilerplate codes and simplifying DAO implementation in the spring application. Let’s see how to add Spring Data Solr in your application by using the following Maven and Gradle dependency.
Maven Dependency
Let’s start by adding the Spring Data Solr dependency on our pom.xml:
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-solr</artifactId> <version>3.0.10.RELEASE</version> </dependency>
Gradle Dependency
Let’s start by adding the Spring Data Solr dependency on our build.gradle:
{ compile group: 'org.springframework.data', name: 'spring-data-solr', version: '3.0.10.RELEASE' }
You can configure the latest dependency of the Spring Data Solr project in your application. Next, let’s define a document class for the Order collection in this application.
Defining the Document Class
In this application, we are using Order collection, so, let’s define a document called Order as the following class:
package com.doj.app.pojo; import org.springframework.data.annotation.Id; import org.springframework.data.solr.core.mapping.Indexed; import org.springframework.data.solr.core.mapping.SolrDocument; /** * @author Dinesh.Rajput * */ @SolrDocument(collection="Order") public class Order { @Id @Indexed(name = "oid", type = "long") private Long orderid; @Indexed(name = "oname", type = "string") private String orderName; @Indexed(name = "odesc", type = "string") private String orderDescription; @Indexed(name = "pname", type = "string") private String productName; @Indexed(name = "cname", type = "string") private String customerName; @Indexed(name = "cmobile", type = "string") private String customerMobile; public Long getOrderid() { return orderid; } public void setOrderid(Long orderid) { this.orderid = orderid; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getCustomerMobile() { return customerMobile; } public void setCustomerMobile(String customerMobile) { this.customerMobile = customerMobile; } public String getOrderDescription() { return orderDescription; } public void setOrderDescription(String orderDescription) { this.orderDescription = orderDescription; } }
In the above document class, we have annotated this class @SolrDocument annotation. This annotation indicates that the Order class is a Solr document and indexed to collection name Order. In this class, you would notice, the fields are annotated with @Indexed. It indicates these fields will be indexed to the Order collection and will be searchable. Also, a field of the Order class “orderid” is annotated with @Id annotation. This means that the field “orderid” is like primary key of this a Solr document.
In the next section, I will define the Spring Data Solr repository interface for this application.
Defining Repository Interface
Let’s create a repository interface for the Order Solr collection and this interface extending a repository provided by Spring Data Solr. As the given class below:
package com.doj.app.repository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.solr.repository.Query; import org.springframework.data.solr.repository.SolrCrudRepository; import com.doj.app.pojo.Order; /** * @author Dinesh.Rajput * */ public interface SolrOrderRepository extends SolrCrudRepository<Order, Long> { Order findByOrderid(Long orderid); @Query("odesc:*?0*") Page<Order> findByOrderDescription(String searchTerm, Pageable pageable); @Query("odesc:*?0* OR oname:*?0* OR pname:*?0*") Page<Order> findByCustomerQuery(String searchTerm, Pageable pageable); }
The above repository interface, we have naturally parametrized this with Order and Long as our entity id. As we know that this is Spring Boot application, so we don’t need to configure Spring Data Solr manually for the Spring Boot application. The Spring Boot application will automatically configure the required configuration by default according to the library available on the classpath of the application. But we have to provide Apache Solr server address by configuring it with the application.properties file as the following:
Application configuration file
First, let’s see the configuration file for the Spring Boot application.
application.properties
spring.data.solr.host=http://localhost:8983/solr/
Let’s assume, if you don’t want to use default configuration of the Spring Boot application or you are not using the Spring Boot for this application then you have to explicitly configure the Spring Data Solr into this Spring Data Solr CRUD Application.
Explicitly Java Based Configuration
Let’s see the following Java-based configuration for the Spring Data Solr in the Spring Data Solr CRUD Application.
/** * */ package com.doj.app.config; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.data.solr.core.SolrTemplate; import org.springframework.data.solr.repository.config.EnableSolrRepositories; /** * @author Dinesh.Rajput * */ @Configuration @EnableSolrRepositories( basePackages = "com.doj.app.repository") @ComponentScan public class SolrConfig { @Value("spring.data.solr.host") String solrURL; @Bean public SolrClient solrClient() { return new HttpSolrClient.Builder(solrURL).build(); } @Bean public SolrTemplate solrTemplate(SolrClient client) throws Exception { return new SolrTemplate(client); } }
We are using @EnableSolrRepositories to scan the packages for repositories.
Note: If multi-core is not enabled, then by default Spring Data will assume that Solr configuration is for a single core.
Now, move to perform CRUD operation for this Solr collection in the Spring Data Solr CRUD Application.
Indexing, Updating, Deleting, and Querying
In order to search documents in Solr, documents should be indexed to Solr repository. Let’s create a controller class which takes request parameters and index to the Solr document Order.
package com.doj.app.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import com.doj.app.pojo.Order; import com.doj.app.repository.SolrOrderRepository; /** * @author Dinesh.Rajput * */ @RestController public class OrderController { @Autowired SolrOrderRepository solrOrderRepository; @PostMapping("/order") public String createOrder(@RequestBody Order order){ String description = "Order Created"; solrOrderRepository.save(order); return description; } @GetMapping("/order/{orderid}") public Order readOrder(@PathVariable Long orderid){ return solrOrderRepository.findByOrderid(orderid); } @PutMapping("/order") public String updateOrder(@RequestBody Order order){ String description = "Order Updated"; solrOrderRepository.save(order); return description; } @DeleteMapping("/order/{orderid}") public String deleteOrder(@PathVariable Long orderid){ String description = "Order Deleted"; solrOrderRepository.delete(solrOrderRepository.findByOrderid(orderid)); return description; } @GetMapping("/order/desc/{orderDesc}/{page}") public List<Order> findOrder(@PathVariable String orderDesc, @PathVariable int page){ return solrOrderRepository.findByOrderDescription(orderDesc, PageRequest.of(page, 2)).getContent(); } @GetMapping("/order/search/{searchTerm}/{page}") public List<Order> findOrderBySearchTerm(@PathVariable String searchTerm, @PathVariable int page){ return solrOrderRepository.findByCustomerQuery(searchTerm, PageRequest.of(page, 2)).getContent(); } }
Create
In the above controller class, we have created all CRUD operation and provided handler methods for these operations. Let’s run this application and index some data by using createOrder() request handler method with /order POST endpoint.
Read
In the above controller class, we have created readOrder() request handler method with /order/{orderid} GET endpoint to read the data from the Solr server using the Spring Data Solr.
Update
In the above controller class, we have created updateOrder() request handler method with /order PUT endpoint to update a given order value.
Delete
In the above controller class, we have created deleteOrder() request handler method with /order/{orderid} DELETE endpoint to delete a document from the Solr collection.
Let’s see the following the Solr dashboard after creating data into Order collection.
Summary
This article has all about the Spring Data Solr with Spring Boot and the Apache Solr. It is a quick and practical introduction to Spring Data Solr, covering the basic configuration, defining repositories and perform CRUD operation. In this Spring Data Solr CRUD Application, we have created an application and this application available as a sample project on Github.
Hi Dinesh,
I am getting the following error.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘orderController’: Unsatisfied dependency expressed through field ‘solrOrderRepository’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘solrOrderRepository’: Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property namedQuery found for type Order!
The code is to be fixed.. need to add namedQueriesLocation = “classpath:solr-named-queries.properties” to SolrConfig.java, also props file under resources.
Thanks for the suggestion.
Hi, should it not be
@Value(“${spring.data.solr.host}”) String solrURL;
to resolve the solrUrl from properties.
Any suggestion on it.
While doing save operation getting the following error:IOException occured when talking to server nested exception is org.apache.solr.client.solrj.SolrServerException: IOException occured when talking to server.Please help
Please check, Solr server is running or not.
Update and delete does not working, it is even not showing any error on console too, when when you try to update added order with put method then it will add new order with same id in solr core.
Please add solr-named-queries.properties to the github project