SlideShare a Scribd company logo
Creating a Facebook Clone - Part XXXI
The next big step is making this into a "real" app by implementing a lot of the "details" such as comments, search & settings. Each one of these seems like a huge task
but surprisingly they aren't as hard as one would have expected!
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>
<version>7.17.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.8.2.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
pom.xml
For search we need to leap back into the server code to implement search. On the surface search seems like a complex problem but thankfully Spring Boot & hibernate
magically solve that for us!

Hibernate is the default JPA implementation in Spring Boot. One of its features is integration with Lucene/Elastic Search which you can read about at hibernate.org/
search/. 

Spring Boot makes that even simpler. We can support search by making a small change to the pom.xml file.
spring.datasource.url=jdbc:mysql://localhost/facebookclone
spring.datasource.username=root
spring.datasource.password=XXXXXXXX
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.http.multipart.max-file-size=100MB
spring.http.multipart.max-request-size=100MB
spring.servlet.multipart.maxFileSize=100MB
spring.servlet.multipart.maxRequestSize=100MB
spring.jackson.default-property-inclusion=non_null
hibernate.search.default.directory_provider = filesystem
hibernate.search.default.indexBase = /data/index/default
application.properties
Then we need to configure search in the application.properties file as such… 

These just mean the search index is saved into the file system which is the simplest approach for implementing this. There is a lot of power behind this tool and you can
learn more about it in their website.
@Entity
@Indexed
public class User {
@Id
private String id;
@Field
private String firstName;
@Field
private String familyName;
@Column(unique=true)
private String email;
@Column(unique=true)
private String phone;
private String gender;
private String verificationCode;
private String verifiedEmailAddress;
User (Entity)
Users can't search everything, that would be bad as we don't want the ability to search through passwords etc. 

We can add search support by marking an Entity with the @Indexed annotation then marking each field that should be indexed with the @Field annotation.

Notice that we should use the org.hibernate.search.annotations package for these annotations as there is another Indexed class in Spring Boot
@Entity
@Indexed
public class User {
@Id
private String id;
@Field
private String firstName;
@Field
private String familyName;
@Column(unique=true)
private String email;
@Column(unique=true)
private String phone;
private String gender;
private String verificationCode;
private String verifiedEmailAddress;
User (Entity)
We only index the name of the user as we don't necessarily want to expose private data through search
@Entity
@Indexed
public class Post {
@Id
private String id;
@ManyToOne
private User user;
private long date;
@Field
private String title;
@Field
private String content;
private String visibility;
private String styling;
@OneToMany
@OrderBy("date ASC")
private Set<Comment> comments;
Post (Entity)
We'll do a similar change to Post which contains fields worth indexing. We only index the text content as other content might produce weird results in search. 

I could go further with searching comments etc. but for simplicity I stopped here.
@Service
public class SearchService {
@Autowired
private EntityManager manager;
private FullTextEntityManager ft() {
return Search.getFullTextEntityManager(manager);
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
SearchService
With that the entities should be completely searchable. We now need to expose the search functionality in the service layer.

This warrants a brand new SearchService class.
@Service
public class SearchService {
@Autowired
private EntityManager manager;
private FullTextEntityManager ft() {
return Search.getFullTextEntityManager(manager);
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
SearchService
The entity manager provides direct access to the underlying JPA implementation. Normally Spring Boot hides that but for search we need direct access
@Service
public class SearchService {
@Autowired
private EntityManager manager;
private FullTextEntityManager ft() {
return Search.getFullTextEntityManager(manager);
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
SearchService
This is a small helper method that shortens the boilerplate syntax to ft() instead all of that code…
@Service
public class SearchService {
@Autowired
private EntityManager manager;
private FullTextEntityManager ft() {
return Search.getFullTextEntityManager(manager);
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
SearchService
We first need to build a search database, this is a one time operation. Once the database is built Hibernate will keep the database up to date
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
.onFields(fields).matching(text).createQuery();
FullTextQuery jpaQuery = ft.createFullTextQuery(query, type);
return jpaQuery.setFirstResult(page * amount).
setMaxResults(amount).getResultList();
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
SearchService
We have two types of searches so I combined their common logic into this method
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
.onFields(fields).matching(text).createQuery();
FullTextQuery jpaQuery = ft.createFullTextQuery(query, type);
return jpaQuery.setFirstResult(page * amount).
setMaxResults(amount).getResultList();
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
SearchService
The query builder searches a specific entity e.g. Post, User etc. once we have it we can construct a complex search query
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
.onFields(fields).matching(text).createQuery();
FullTextQuery jpaQuery = ft.createFullTextQuery(query, type);
return jpaQuery.setFirstResult(page * amount).
setMaxResults(amount).getResultList();
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
SearchService
The search for keywords is marked as fuzzy which means it will find answers that don't match completely for the given text
}
public void rebuildSearchDB() {
ft().createIndexer().start();
}
private <T> List<T> genericSearch(String text, int page, int amount,
Class type, String... fields) {
FullTextEntityManager ft = ft();
QueryBuilder queryBuilder = ft.getSearchFactory()
.buildQueryBuilder()
.forEntity(type).get();
Query query = queryBuilder.keyword().fuzzy()
.onFields(fields).matching(text).createQuery();
FullTextQuery jpaQuery = ft.createFullTextQuery(query, type);
return jpaQuery.setFirstResult(page * amount).
setMaxResults(amount).getResultList();
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
SearchService
We create the query and issue it, we give it a range of results so we can page through query results like we do with other pageable content
return jpaQuery.setFirstResult(page * amount).
setMaxResults(amount).getResultList();
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
List<UserDAO> response = new ArrayList<>();
for(User u : results) {
response.add(u.getDAO());
}
return response;
}
public List<PostDAO> searchPosts(String text, int page, int amount) {
List<Post> results = genericSearch(text, page, amount,
Post.class, "title", "content");
List<PostDAO> response = new ArrayList<>();
for(Post p : results) {
response.add(p.getDAO());
}
return response;
}
SearchService
Searching people or posts becomes a matter of passing the entity type, field names & paging numbers
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
List<UserDAO> response = new ArrayList<>();
for(User u : results) {
response.add(u.getDAO());
}
return response;
}
public List<PostDAO> searchPosts(String text, int page, int amount) {
List<Post> results = genericSearch(text, page, amount,
Post.class, "title", "content");
List<PostDAO> response = new ArrayList<>();
for(Post p : results) {
response.add(p.getDAO());
}
return response;
}
}
SearchService
We then convert the entity result to the DAO object as return types
}
public List<UserDAO> searchPeople(String name, int page, int amount) {
List<User> results = genericSearch(name, page, amount,
User.class, "firstName", "familyName");
List<UserDAO> response = new ArrayList<>();
for(User u : results) {
response.add(u.getDAO());
}
return response;
}
public List<PostDAO> searchPosts(String text, int page, int amount) {
List<Post> results = genericSearch(text, page, amount,
Post.class, "title", "content");
List<PostDAO> response = new ArrayList<>();
for(Post p : results) {
response.add(p.getDAO());
}
return response;
}
}
SearchService
Post searches are exactly the same only with Post objects instead of User objects. 

That was a bit of code but the premise is relatively simple and the heavy lifting is done by Hibernate. The interesting part is the query builder portion. You can customize
the query builder with any fields you wish to search and complex constraints related to the search. But for the simple implementation we have right now this will do just
fine.

More Related Content

Similar to Creating a Facebook Clone - Part XXXI - Transcript.pdf

Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
DataArt
 
An introduction into Spring Data
An introduction into Spring DataAn introduction into Spring Data
An introduction into Spring Data
Oliver Gierke
 
Django tech-talk
Django tech-talkDjango tech-talk
Django tech-talk
dtdannen
 
Pyconie 2012
Pyconie 2012Pyconie 2012
Pyconie 2012Yaqi Zhao
 
Vaadin 7 FieldGroup & Converter
Vaadin 7 FieldGroup & ConverterVaadin 7 FieldGroup & Converter
Vaadin 7 FieldGroup & Converter
Nicolas Fränkel
 
This is a java lab assignment. I have added the first part java re.pdf
This is a java lab assignment. I have added the first part java re.pdfThis is a java lab assignment. I have added the first part java re.pdf
This is a java lab assignment. I have added the first part java re.pdf
feetshoemart
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke
 
Sharepoint Saturday India Online best practice for developing share point sol...
Sharepoint Saturday India Online best practice for developing share point sol...Sharepoint Saturday India Online best practice for developing share point sol...
Sharepoint Saturday India Online best practice for developing share point sol...Shakir Majeed Khan
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdf
ShaiAlmog1
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
The Principle of Hybrid App.
The Principle of Hybrid App.The Principle of Hybrid App.
The Principle of Hybrid App.
musart Park
 
Wicket KT part 2
Wicket KT part 2Wicket KT part 2
Wicket KT part 2
stuq
 
ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON
Padma shree. T
 
Intake 38 data access 5
Intake 38 data access 5Intake 38 data access 5
Intake 38 data access 5
Mahmoud Ouf
 
Coherence SIG: Advanced usage of indexes in coherence
Coherence SIG: Advanced usage of indexes in coherenceCoherence SIG: Advanced usage of indexes in coherence
Coherence SIG: Advanced usage of indexes in coherence
aragozin
 
Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparison
Emily Jiang
 
Clean code _v2003
 Clean code _v2003 Clean code _v2003
Clean code _v2003
R696
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVC
Richard Paul
 

Similar to Creating a Facebook Clone - Part XXXI - Transcript.pdf (20)

Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
An introduction into Spring Data
An introduction into Spring DataAn introduction into Spring Data
An introduction into Spring Data
 
Django tech-talk
Django tech-talkDjango tech-talk
Django tech-talk
 
Pyconie 2012
Pyconie 2012Pyconie 2012
Pyconie 2012
 
Vaadin 7 FieldGroup & Converter
Vaadin 7 FieldGroup & ConverterVaadin 7 FieldGroup & Converter
Vaadin 7 FieldGroup & Converter
 
This is a java lab assignment. I have added the first part java re.pdf
This is a java lab assignment. I have added the first part java re.pdfThis is a java lab assignment. I have added the first part java re.pdf
This is a java lab assignment. I have added the first part java re.pdf
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
 
Eclipse Banking Day
Eclipse Banking DayEclipse Banking Day
Eclipse Banking Day
 
Sharepoint Saturday India Online best practice for developing share point sol...
Sharepoint Saturday India Online best practice for developing share point sol...Sharepoint Saturday India Online best practice for developing share point sol...
Sharepoint Saturday India Online best practice for developing share point sol...
 
Creating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdfCreating a Whatsapp Clone - Part XI.pdf
Creating a Whatsapp Clone - Part XI.pdf
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 
The Principle of Hybrid App.
The Principle of Hybrid App.The Principle of Hybrid App.
The Principle of Hybrid App.
 
Wicket KT part 2
Wicket KT part 2Wicket KT part 2
Wicket KT part 2
 
ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON ACADGILD:: ANDROID LESSON
ACADGILD:: ANDROID LESSON
 
Intake 38 data access 5
Intake 38 data access 5Intake 38 data access 5
Intake 38 data access 5
 
Coherence SIG: Advanced usage of indexes in coherence
Coherence SIG: Advanced usage of indexes in coherenceCoherence SIG: Advanced usage of indexes in coherence
Coherence SIG: Advanced usage of indexes in coherence
 
Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparison
 
Clean code _v2003
 Clean code _v2003 Clean code _v2003
Clean code _v2003
 
Introduction to Spring MVC
Introduction to Spring MVCIntroduction to Spring MVC
Introduction to Spring MVC
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
ShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 

Recently uploaded

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
Abida Shariff
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 

Creating a Facebook Clone - Part XXXI - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XXXI The next big step is making this into a "real" app by implementing a lot of the "details" such as comments, search & settings. Each one of these seems like a huge task but surprisingly they aren't as hard as one would have expected!
  • 2. <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.mashape.unirest</groupId> <artifactId>unirest-java</artifactId> <version>1.4.9</version> </dependency> <dependency> <groupId>com.twilio.sdk</groupId> <artifactId>twilio</artifactId> <version>7.17.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search-orm</artifactId> <version>5.8.2.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> pom.xml For search we need to leap back into the server code to implement search. On the surface search seems like a complex problem but thankfully Spring Boot & hibernate magically solve that for us! Hibernate is the default JPA implementation in Spring Boot. One of its features is integration with Lucene/Elastic Search which you can read about at hibernate.org/ search/. Spring Boot makes that even simpler. We can support search by making a small change to the pom.xml file.
  • 3. spring.datasource.url=jdbc:mysql://localhost/facebookclone spring.datasource.username=root spring.datasource.password=XXXXXXXX spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.generate-ddl=true spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.http.multipart.max-file-size=100MB spring.http.multipart.max-request-size=100MB spring.servlet.multipart.maxFileSize=100MB spring.servlet.multipart.maxRequestSize=100MB spring.jackson.default-property-inclusion=non_null hibernate.search.default.directory_provider = filesystem hibernate.search.default.indexBase = /data/index/default application.properties Then we need to configure search in the application.properties file as such… These just mean the search index is saved into the file system which is the simplest approach for implementing this. There is a lot of power behind this tool and you can learn more about it in their website.
  • 4. @Entity @Indexed public class User { @Id private String id; @Field private String firstName; @Field private String familyName; @Column(unique=true) private String email; @Column(unique=true) private String phone; private String gender; private String verificationCode; private String verifiedEmailAddress; User (Entity) Users can't search everything, that would be bad as we don't want the ability to search through passwords etc. We can add search support by marking an Entity with the @Indexed annotation then marking each field that should be indexed with the @Field annotation. Notice that we should use the org.hibernate.search.annotations package for these annotations as there is another Indexed class in Spring Boot
  • 5. @Entity @Indexed public class User { @Id private String id; @Field private String firstName; @Field private String familyName; @Column(unique=true) private String email; @Column(unique=true) private String phone; private String gender; private String verificationCode; private String verifiedEmailAddress; User (Entity) We only index the name of the user as we don't necessarily want to expose private data through search
  • 6. @Entity @Indexed public class Post { @Id private String id; @ManyToOne private User user; private long date; @Field private String title; @Field private String content; private String visibility; private String styling; @OneToMany @OrderBy("date ASC") private Set<Comment> comments; Post (Entity) We'll do a similar change to Post which contains fields worth indexing. We only index the text content as other content might produce weird results in search. I could go further with searching comments etc. but for simplicity I stopped here.
  • 7. @Service public class SearchService { @Autowired private EntityManager manager; private FullTextEntityManager ft() { return Search.getFullTextEntityManager(manager); } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() SearchService With that the entities should be completely searchable. We now need to expose the search functionality in the service layer. This warrants a brand new SearchService class.
  • 8. @Service public class SearchService { @Autowired private EntityManager manager; private FullTextEntityManager ft() { return Search.getFullTextEntityManager(manager); } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() SearchService The entity manager provides direct access to the underlying JPA implementation. Normally Spring Boot hides that but for search we need direct access
  • 9. @Service public class SearchService { @Autowired private EntityManager manager; private FullTextEntityManager ft() { return Search.getFullTextEntityManager(manager); } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() SearchService This is a small helper method that shortens the boilerplate syntax to ft() instead all of that code…
  • 10. @Service public class SearchService { @Autowired private EntityManager manager; private FullTextEntityManager ft() { return Search.getFullTextEntityManager(manager); } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() SearchService We first need to build a search database, this is a one time operation. Once the database is built Hibernate will keep the database up to date
  • 11. } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() .onFields(fields).matching(text).createQuery(); FullTextQuery jpaQuery = ft.createFullTextQuery(query, type); return jpaQuery.setFirstResult(page * amount). setMaxResults(amount).getResultList(); } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); SearchService We have two types of searches so I combined their common logic into this method
  • 12. } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() .onFields(fields).matching(text).createQuery(); FullTextQuery jpaQuery = ft.createFullTextQuery(query, type); return jpaQuery.setFirstResult(page * amount). setMaxResults(amount).getResultList(); } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); SearchService The query builder searches a specific entity e.g. Post, User etc. once we have it we can construct a complex search query
  • 13. } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() .onFields(fields).matching(text).createQuery(); FullTextQuery jpaQuery = ft.createFullTextQuery(query, type); return jpaQuery.setFirstResult(page * amount). setMaxResults(amount).getResultList(); } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); SearchService The search for keywords is marked as fuzzy which means it will find answers that don't match completely for the given text
  • 14. } public void rebuildSearchDB() { ft().createIndexer().start(); } private <T> List<T> genericSearch(String text, int page, int amount, Class type, String... fields) { FullTextEntityManager ft = ft(); QueryBuilder queryBuilder = ft.getSearchFactory() .buildQueryBuilder() .forEntity(type).get(); Query query = queryBuilder.keyword().fuzzy() .onFields(fields).matching(text).createQuery(); FullTextQuery jpaQuery = ft.createFullTextQuery(query, type); return jpaQuery.setFirstResult(page * amount). setMaxResults(amount).getResultList(); } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); SearchService We create the query and issue it, we give it a range of results so we can page through query results like we do with other pageable content
  • 15. return jpaQuery.setFirstResult(page * amount). setMaxResults(amount).getResultList(); } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); List<UserDAO> response = new ArrayList<>(); for(User u : results) { response.add(u.getDAO()); } return response; } public List<PostDAO> searchPosts(String text, int page, int amount) { List<Post> results = genericSearch(text, page, amount, Post.class, "title", "content"); List<PostDAO> response = new ArrayList<>(); for(Post p : results) { response.add(p.getDAO()); } return response; } SearchService Searching people or posts becomes a matter of passing the entity type, field names & paging numbers
  • 16. } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); List<UserDAO> response = new ArrayList<>(); for(User u : results) { response.add(u.getDAO()); } return response; } public List<PostDAO> searchPosts(String text, int page, int amount) { List<Post> results = genericSearch(text, page, amount, Post.class, "title", "content"); List<PostDAO> response = new ArrayList<>(); for(Post p : results) { response.add(p.getDAO()); } return response; } } SearchService We then convert the entity result to the DAO object as return types
  • 17. } public List<UserDAO> searchPeople(String name, int page, int amount) { List<User> results = genericSearch(name, page, amount, User.class, "firstName", "familyName"); List<UserDAO> response = new ArrayList<>(); for(User u : results) { response.add(u.getDAO()); } return response; } public List<PostDAO> searchPosts(String text, int page, int amount) { List<Post> results = genericSearch(text, page, amount, Post.class, "title", "content"); List<PostDAO> response = new ArrayList<>(); for(Post p : results) { response.add(p.getDAO()); } return response; } } SearchService Post searches are exactly the same only with Post objects instead of User objects. That was a bit of code but the premise is relatively simple and the heavy lifting is done by Hibernate. The interesting part is the query builder portion. You can customize the query builder with any fields you wish to search and complex constraints related to the search. But for the simple implementation we have right now this will do just fine.