technionyearlyproject / roommates Goto Github PK
View Code? Open in Web Editor NEWThe Best platform for finding your next Roommates
The Best platform for finding your next Roommates
Planned the architecture of the integration with Azure + implemented it:
Continue with the Azure integration:
Additional items:
Following the discussion we had on the weekly meeting (06.11.2017) and the research about MongoDB and ElasticSearch we have to decide between two candidates: MongoDB and MySQL so we have to read about MongoDB & MySQL and make a comparison between them in order to answer the question what is the best DB for our purposes. All information has to be documented here. (Note - there is an issue about MongoDB - #16 ).
The comparison should include the following criteria:
"A database design starts with a list of the data that you want to include in your database and what you want to be able to do with the database later on. This can all be written in your own language, without any SQL. In this stage you must try not to think in tables or columns, but just think: "What do I need to know?" Don't take this too lightly, because if you find out later that you forgot something, usually you need to start all over. Adding things to your database is mostly a lot of work.
Identifying Entities
The types of information that are saved in the database are called 'entities'. These entities exist in four kinds: people, things, events, and locations. Everything you could want to put in a database fits into one of these categories. If the information you want to include doesn't fit into these categories, than it is probably not an entity but a property of an entity, an attribute. The data elements that you want to save for each entity are called 'attributes'.
The next step is to determine the relationships between the entities and to determine the cardinality of each relationship. The relationship is the connection between the entities, just like in the real world: what does one entity do with the other, how do they relate to each other? For example, customers buy products, products are sold to customers, a sale comprises products, a sale happens in a shop.
The cardinality shows how much of one side of the relationship belongs to how much of the other side of the relationship. First, you need to state for each relationship, how much of one side belongs to exactly 1 of the other side. For example: How many customers belong to 1 sale?; How many sales belong to 1 customer?; How many sales take place in 1 shop?"
(http://www.datanamic.com/support/lt-dez005-introduction-db-modeling.html)
Read about MongoDB & ElasticSearch and make a comparison between them in order to answer the question what is the best DB for our purposes.
Database design is the process of producing a detailed data model of database. This data model contains all the needed logical and physical design choices and physical storage parameters needed to generate a design in a data definition language, which can then be used to create a database. A fully attributed data model contains detailed attributes for each entity (https://en.wikipedia.org/wiki/Database_design).
This issue is the topic issue of the following sub tasks:
In this tutorial I will explain a little about RESTful APIs and how they work.
Our server in the project will expose a RESTful API to the client-side application and using this API the client will be able to interact with the server.
REST is an idea, not a protocol. It goes well with HTTP although it doesn't have to, and in this tutorial I will present an HTTP implementation of a RESTful API.
It requires a basic understanding of HTTP in order to understand this tutorial.
RESTful API is an API that is based on resources. We have different independent resources in our system on which we can perform actions. The actions we can invoke are create, read, update and delete (CRUD).
Each resource is represented using a URI.
For example, /apartments/3
represents the apartment with the ID of 3.
We will send an HTTP request with the URI of a specific resource on which the action is invoked, and we will use one of the following HTTP methods: GET, POST, PUT, DELETE.
GET - fetches the resource from the server.
POST - creates a new resource.
PUT - updates a resource.
DELETE - deletes a resource.
Examples:
GET /apartment/5 -> fetches the apartment with the ID of 5 from the server.
POST /apartments -> creates an apartment.
PUT /apartments/7 -> updates the apartment with the ID of 5.
DELETE /apartments/ 2 -> deletes the apartment with the ID of 5.
REST does not limit us with the format we use to present the data. We can use JSON, XML or any other format. I will use JSON in the examples in this tutorial.
The server should respond according to the request method:
REST APIs that use HTTP make a big use of HTTP response codes.
For example, if we have apartments with IDs 1,2 and 3:
GET /apartments/6 -> 404 Not Found
POST /apartments/ -> 201 Created
PUT / apartments/4 -> 200 OK
DELETE /apartments/5 -> 404 Not Found
DELETE /apartments/1 -> 403 Forbidden (suppose the user can't delete this apartment)
Examples of requests and responses:
POST /apartments/
{
"location": "Technion",
"rooms": 3
}
-----------------------------------------------
201 Created
{
"apartment-id": 1
}
GET /apartments/1
-----------------------------------------------
200 OK
{
"apartment-id": 1,
"location": "Technion",
"rooms": 3
}
PUT /apartments/1
{
"location": "Tel Aviv"
}
-----------------------------------------------
200 OK
GET /apartments/1
-----------------------------------------------
200 OK
{
"apartment-id": 1,
"location": "Tel Aviv",
"rooms": 3
}
DELETE /apartments/1
-----------------------------------------------
200 OK
GET /apartments/1
-----------------------------------------------
404 Not Found
Sometimes we will use PUT in order to create a new resource and not POST. We will do so when we know the ID of the resource we want to create.
For example, suppose we have users in our system, and users/idan
is the user with the username "idan".
If we would like to create a new user with the username "adi", we would send a PUT request to "users/adi".
If we sent a POST request to "users/" we wouldn't have control over the username of the created user.
We can use the query string in order to pass filters, parameters to the servers.
For example, if we want to fetch all the apartments that have 3 rooms in the Technion:
GET /apartments/?rooms=3&location=Technion
-----------------------------------------------------------
200 OK
[
{
"apartment-id": 1,
"rooms": 3,
"location": "Technion"
},
{
"apartment-id": 5,
"rooms": 3,
"location": "Technion"
}
]
REST is very flexible and doesn't limit us when we need to choose a format or when we need to implement it. Also, it is very supported and there are many libraries we can use that support it.
I did some research regarding testing.
It seems to be simplier than i thought. Below I will show some simple example i made.
The library I used is called 'Mocha'.
I've already added it to package.json as "devDependencies" so you only have to run "npm install" to automatically download it to your project directory.
to run the test run "npm test" from the project directory. This will execute the command:
mocha tests/*.test.js
as it is defined in package.json. This command will search all the files in the project's tests directory matching the regex *.test.js and run it.
simple example of a test:
it('should succeed', () => {
if(1 !== 1) {
throw new Error('it should not happen');
}
});
This is the result after running it:
Inside the it() function should be a short informative description about what the test suppose to check.
for example:
it('should add 2 numbers')
it('should log the user')
it('should add an appartment to the list')
Another example is for asynchronose code. This time we need to pass 'done' to the function argument and call it when we finish the test. Note that if you do not use 'done' the 'it' function might finish before the callback runs which then let Mocha assume that the test has passed. Also notice the 'expect' function call I'm using it is another library called "expect" which helps in writing more readable tests. I will not cover it here.
it('should async add two numbers', (done) => {
utils.asyncAdd(4, 3, (sum) => {
expect(sum).toBe(7).toBeA('number');
done();
});
})
The time the tests took is displayed inside the parentheses. This is exceptional! Mocha letting us know that the test took a long time to finish, so something might be laggy in our code.
Define the back-end-UI API based on the HLD.
DB should be configured to allow connections from the logic server
We have to design the structure of our DB i.e. tables, fields, relations, indexes, keys, fields types, etc ...
Elasticsearch is a document oriented database. The Elasticsearch provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents that includes filtering, aggregate statistics and analysis capabilities. Elasticsearch is developed in Java and is released as open source under the terms of the Apache License. Official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy and many other languages. Elasticsearch is the most popular enterprise search engine. Elasticsearch is also easily scalable, supporting clustering and leader election out of the box.
The core of Elasticsearch's intelligent search engine is largely another software project: Lucene. It is perhaps easiest to understand elasticsearch as a piece of infrastructure built around Lucene’s Java libraries. Everything in elasticsearch that pertains to the actual algorithms for matching text and storing optimized indexes of searchable terms is implemented by Lucene. Elasticsearch itself provides a more useable and concise API, scalability, and operational tools on top of Lucene’s search implementation.
Since Elasticsearch is a standalone Java application, getting up and running is a cinch on almost any platform. You’ll want Java 1.7 or newer.
The smallest individual unit of data in Elasticsearch is a field, which has a defined type and has one or many values of that type. A field contains a single piece of data, like the number 42 or the string "Hello, World!", or a single list of data of the same type, such as the array [5, 6, 7, 8].
Documents are collections of fields, and comprise the base unit of storage in Elasticsearch; something like a row in a traditional RDBMS. The reason a document is considered the base unit of storage is because, peculiar to Lucene, all field updates fully rewrite a given document to storage (while preserving unmodified fields). So, while from an API perspective the field is the smallest single unit, the document is the smallest unit from a storage perspective.
The primary data-format Elasticsearch uses is JSON. Given that, all documents must be valid JSON values. A simple document might look like:
{
"_id": 1,
"handle": "ron",
"age": 28,
"hobbies": ["hacking", "the great outdoors"],
"computer": {"cpu": "pentium pro", "mhz": 200}
}
The hobbies and computer fields specifically are rich types; an array and an object (dictionary) respectively, while the other fields are simple string and numeric types.
Elasticsearch reserves some fields for special use. We’ve specified one of these fields in this example: the _id field. A document’s id is unique, and if unassigned will be created automatically. An elasticsearch id would be a primary key in RDBMS parlance.
Each document in Elasticsearch must conform to a user-defined type mapping, analogous to a database schema.A type’s mapping both defines the types of its fields (say integer, string, etc.) and the way in which those properties are indexed. Types are defined with the Mapping API, which associates type names to property definitions e.g:
{
"user": {
"properties": {
"handle": {"type": "string"},
"age": {"type": "integer"},
"hobbies": {"type": "string"},
"computer": {
"properties": {
"cpu": {"type": "string"},
"speed": {"type": "integer"}}}}}
}
Available types:
Type Definition
string Text
integer 32 bit integers
long 64 bit integers
float IEEE float
double Double precision floats
boolean true or false
date UTC Date/Time (JodaTime)
geo_point Latitude / Longitude
There is nothing to declare regarding a field’s array-ness in the mapping. An important thing to remember, however, is that elasticsearch arrays cannot store mixed types. If a field is declared as an integer, it can store one or many integers, but never a mix of types.
The largest single unit of data in elasticsearch is an index. Indexes are logical and physical partitions of documents within elasticsearch. Documents and document types are unique per-index. Indexes have no knowledge of data contained in other indexes. elasticsearch supports cross-index searches. Elasticsearch indexes are most similar to the ‘database’ abstraction in the relational world. An elasticsearch index is a fully partitioned universe within a single running server instance. Documents and type mappings are scoped per index, making it safe to re-use names and ids across indexes.
Full usage example:
// Create an index named 'planet'
PUT /planet
// Create a type called 'hacker'
PUT /planet/hacker/_mapping
{
"hacker": {
"properties": {
"handle": {"type": "string"},
"age": {"type": "long"}}}}
// Create a document
PUT /planet/hacker/1
{"handle": "jean-michel", "age": 18}
// Retrieve the document
GET /planet/hacker/1
// Update the document's age field
POST /planet/hacker/1/_update
{"doc": {"age": 19}}
// Delete the document
DELETE /planet/hacker/1
As said - official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy and many other languages e.g:
C# client:
var client = new ElasticsearchClient();
//index a document under /myindex/mytype/1
var indexResponse = client.Index("myindex","mytype","1", new { Hello = "World" });
Java client:
SearchResponse response = client.prepareSearch("index1", "index2")
.setTypes("type1", "type2")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.termQuery(field, text)) // Query
.setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18)) // Filter
.setFrom(0).setSize(60).setExplain(true)
.get();
Elasticsearch offers two ways of representing geolocations: latitude-longitude points using the geo_point field type, and complex shapes defined in GeoJSON, using the geo_shape field type.
Geo-points allow you to find points within a certain distance of another point, to calculate distances between two points for sorting or relevance scoring, or to aggregate into a grid to display on a map (a geo-point is a single latitude/longitude point on the Earth’s surface).
Example for quering locations within a given distance (Java client):
GeoDistanceFilterBuilder filter = FilterBuilders.geoDistanceFilter("location").point(latitude, longitude).distance(distance,DistanceUnit.KILOMETERS);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withFilter(filter)
.withSort(SortBuilders.geoDistanceSort("site.location").point(latitude, longitude).order(SortOrder.ASC)).build();
searchQuery.addIndices(channelKey);
searchQuery.addTypes("site");
In terms of scaling, an index is divided into one or more shards. This is specified when the index is created and cannot be changed. Thus, an index should be sharded proportionally with the anticipated growth. As more nodes are added to an Elasticsearch cluster, it does a good job at reallocating and moving shards around. As such, Elasticsearch is very easy to scale out.
Elasticsearch does not have transactions - there is no way to rollback a submitted document, and you cannot submit a group of documents and have either all or none of them indexed.
Elasticsearch (and the components it's made of) does not currently handle OutOfMemory-errors very well - It is very important to provide Elasticsearch with enough memory and be careful before running searches with unknown memory requirements on a production cluster.
Elasticsearch does not have any features for authentication or authorization.
More detaild information about basic concepts of Elasticsearch can be found here: https://www.elastic.co/guide/en/elasticsearch/reference/current/_basic_concepts.html
(based on https://www.elastic.co/guide/en/elasticsearch/client/index.html)
this is our taks for this week:
let's Rock !
In this issue we will decide the final structure of our classes.
This class will represent an apartment.
This class will be an abstract class the User-Owner and User-Renter will inherit from.
This class will represent a user that posts apartments for rent.
This class will represent a user that is looking for a place to rent and can review apartments and renters.
This class will represent a comment that will be stored in a list in either Apartment, User-Owner or User-Renter.
This will be an Enum with the following set values.
This will be an Enum with the following set values.
This class will represent an image.
decide on interface, taking into consideration: components, functionality & looks. #25
current pages:
additional features:
@OrAbramovich and I have finished working on first version of the HLD document.
please read it and comment.
link to HLD document: HLD-DOC
Defining the components & function signatures of the Back-end (based on the HLD).
Create a design to our storage architecture.
Create DB server deployment script in order to avoid manual installation (has to support Ubuntu 16.04)
Read about ElasticSearch in order to answer the question whether it's a good DB for our purposes.
DB: Create DB server requirement & deployment doc in the Wiki.
MongoDB is available in C++, C#, Java, Node.js and more…
See: https://docs.mongodb.com/ecosystem/drivers/
As already said, the data is saved in JSON format and documents in the same collection do not need to have the same structure.
For example, let's write a small collection of apartments:
{
_id: APARTMENT_ID
author: USER_1
picture: 'house.jpg'
price: 1500
address:
{
city: 'HAIFA',
street: 'TRUMPELDOR'
number: 10
}
description: 'looking for another friendly roommate for the best apartment in town!'
likes: 2
tags: [AIR_CONDITION, NO_SMOKING, NO_PETS]
comments: [
{
User: USER_2
Message: 'how far is it from the closest market?'
},
{
User: USER_1,
Message: '2 minutes by foot'
}
]
}
As we can see, all the information can be stored in a single collection, while our RDBMS fellow needs: a table to store apartments data, a table to store comments, and a table to store tags. Was it convincing enough?
db.COLLECTION_NAME.insert(document)
db.COLLECTION_NAME.update(CRITERIA, UPDATED_VALUE)
db.COLLECTION_NAME.remove(CRITERIA)
db.COLLECTION_NAME.remove(CRITERIA).justOne()
db.COLLECTION_NAME.find([CRITERIA])
Db.COLLECTION_NAME.find().sort({"FIELD_NAME":1})
[
{
…
Price: 1300
},
{
…
Price: 2000
},
…
]
In order to do so, we will write:
db.apartments.aggregate([{$group : {_id : "$_id", min_price : {$min : "$price"}}}])
mongodump
6/11/17-13/11-17:
1. composed a short comparision between MySQL and MongoDB to futher strengthen our choise of MongoDB (#16).
2. helped Or with the MongoDB tutorial (#28).
13/11/17-20/11/17:
1. working on DB infersturcter (#29).
2. opened Amazon account for virtual machine and open one
the virtual machine is of ubuntu OS and for the MongoDB to work on.
3. sent account and machine info to the rest of the team.
20/11/17 - 26/11/17:
1. finshed DB infersturcter.
2. reserched mongodb queries and started to implement DB API (#49)
27/11/17 - 3/12/17:
1. worked on queries (#55 )
2/12/17-10/12/27:
1. more queries (#82 )
had a heavy workload this week
11/12/17 - 17/12/17:
1. making UI for Apartment page (part of #74 )
18/12/17-24/12/17:
1. finished base of #74".mypart"
2. making changes acording to #108
3. making some mockup forntend pages for #113
25/12/17-7/1/18:
this is all part of #108
1. GUI for apartment page:
a. spliting up parts of the page to make for shorter and clearer code.
b. switched a lot of code to bootstrap templates.
c. comment section and intersted users section now page instead of just a long list.
2. updatedthe apartment model:
a. added a few field regarding the types of rooms in the apartment.
b. added 2 field referring to other costs of the apartment (vaad-bayit and Arnona).
c. added a few more tags to apartment tags.
3.need to connect page to db (pull data from db rather then static dta in page).
8/1/18-15/1/18:
no substantial progress on project on my side because i was unable to install it on my computer
16/1/17 - 22/1/17:
apartment page improvments:
1. part of #108 :
a. split in to componnents
b. better layout, similar to OG mock GUI
2. part of #163 :
a. apartment page is fully dynamic now
Spring semester:
25-31/3/18:
1. reshearched solution for location review feature (#194 )
document with the final result is in the mentioned issue.
8-15/4/18:
1. finished the design for street reviews (#247 #248 #265 #266)
16-23/4/18:
* head of team for the week
1. changed review design acoording to last weeks meeting (#267)
2. implementing 2 of the routes (#276 #274 #275 )
3. tests for the routes
24-30/4/18:
1. added route PATCH /reviews/:id (#277 ):
1.1: updated user scheme to support given reviews.
1.2: updated tests acoordantly.
1.3: added actual route.
1.4 added tests for route.
2. added route DELETE /reviews/:id (#347):
2.3: added actual route.
2.4 added tests for route.
1-7/5/18:
1. researched cleen up protocol for review freshness (#325 ) and started implemeting (#384)
8-14/5/18:
1. implementing cleap protocol:
1. finshed updating existing test.
2. added new reviews for tests. (#391).
3. updated existing routes to support the cleen up (get /reviews and patch /reviews) (#385).
4. finished implementing the protocol in the GET /revies/:lat/:long route (#395 ).
* issues of the week : #385 #391 #392 #394 #395 (if i forgot to mention any of them).
15-22/5/18:
researching Azure functions (serverless) and load balancer.
23-28/5/18:
1. apartment recomandation design (#335 ).
2. preparing data for POC (#455 ).
29/5/18 - 4/6/18:
my week off ;)
5-11/6/18:
* head of team for the week
1. finished apartment notifiaction design #335 .
2. started implementation of design (#335) #534 .
12-18/6/18:
1. finished routes for #534 : POST /searchs and GET:
* GET is the main dunction of the feature
2. opened Azure resource for timed function of GET
19-24/6/18:
in progress:
1. connetcting POST /searchs to frontend #559 #604
2. adding the GET to the timed resource #560 #605 - posponed indefently see #605 for more details
3. added to user manual #603
4. added apartments and users to db for presentation (#613 )
Gathered together to discuss the next stages of the project and we started working on the paper we had to submit.
This week was focused on integrating azure and deploying our website to Azure.
This week I was the team leader
The client story requires us to implement an interactive solution that supports multiple users. The product has to reflect changes made by one user to others so the product has to include both - client & server side.
Client Side -
The options are:
Server Side -
The options are:
week 1
week 2
week 3
week 4
week 5
week 6
week 7
week 8
week 9
week 10
week 11
week 12
``
05.11.2017 - 11.11.2017
12.11.2017 - 18.11.2017
19.11.2017 - 25.11.2017
26.11.2017 - 02.12.2017
03.12.2017 - 09.12.2017
10.12.2017 - 16.12.2017
17.12.2017 - 23.12.2017 (Hanukkah)
24.12.2017 - 31.12.2017
31.12.2017 - 06.01.2018
7.12.2017 - 14.01.2018
15.12.2017 - 21.01.2018
21.12.2017 - 28.01.2018
The project implementation must include a DB to store its data e.g: registered users details, apartments details, etc...
There are various of aspects should be considered:
A ~20 pages tutorial which contains a collection of the information read about: MongoDB and the integration of it with Java (with Java Driver and Spring Data) - The tutorial (which is mostly copy-pasted) covers the core ideas of the above issues alongside practical information relevant to our interests (e.g handling geolocation data, installing on Amazon Linux platform…)
The tutorial includes information about -
Overview
Installation
Querying
Etc
The tutorial is attached as a pdf file (the version attached here is the first one and it will be updated during the work):
MongoDB Tutorial.pdf
We have to define the "must-have" features of the DB engine in order to choose the relevant one.
Features examples:
Create a brief introduction to Amazon S3 + the integration of Java and Javascript with the service (as we plan to use Amazon S3 as our storage service).
So after Chanan opened account for the db,
we also need one for the core site !
I will open webservice on and update you all.
regards!
Attached an eight page Bootstrap tutorial.
Introduction to Bootstrap .docx
UI tasks for the 06.11.2017 - 12.11.2017 (based on the weekly meeting protocol):
Example | Score | Why? |
---|---|---|
![]() |
Bad | Anonymous |
![]() |
OK | Personal trademark |
Example | Score | Why? |
---|---|---|
Moshe Levy II |
Super | Clear identification |
YossiGil |
Excellent | You identify yourself by full name |
IDabran |
Good | == Itai Dabran |
yogi |
OK | Well known nick |
j1046 |
Bad | Who the hell are you? |
zm&4jk |
Worse | Not even pronnounceable |
r2d2 |
Terrible | We are not playing games here |
ghost |
Disaster | Are you a troll or what? |
j10463
/ r2d2
/ bb8
/ biscuit
/ the destroyer
yogi
(Yossi Gil), idarban
(Itai Darban)We must agree on the "must have" features to be included in the project. For each feature listed here there will be opened an issue describing it.
Status Updates:
- First meeting - no status updates.
Open issues and AIs for next week:
- Each team member ( @alonttal @chananbental @iiddaannyy @Danielohayon @omrihuller @OrAbramovich ) has to create issues in the GitHub repository describing/raising a discussion about the general features/modules (Back End, DB, etc.) in the project. Anyone who can contribute to one of the discussions has to make a comment in the relevant issue.
General:
- @AdiOmari introduced us the client story and the general requirements for the project - developing a roommates finding platform.
- Good luck!
According to the client's request - the project has to support the following geo-location abilities:
- Calculating distance between 2 points.
- Locating a point in a map (and saving its geo-location data/displaying it by a geo-location data).
There are various of aspects should be considered:
Hello.
I hope you will find this guide useful. Please let me know if you see any unclear wording or mistakes. #24
Spring is an open source framework created to address the difficulty and complexity of a major application development. It is heavily based on two design principles – Dependency Injection (DI) and Aspect Oriented Programming (AOP) which we will cover later.
.
.
An important thing we need to understand before we dive into the technical stuff is what exactly a REST API is. REST stands for Representational State Transfer. It is an architecture style for designing networked applications. REST API usually works the same as a website does – when you make a call to the server you eventually receive data back over HTTP protocol. REST API treats objects on the server side as resources that can be created, update and destroyed. It basically uses 4 main HTTP request methods:
.
.
One if the things Spring provides is a layered architecture, which helps in breaking our application into different logical units. This is a type of software architecture pattern called Model-View-Controller (MVC). In this pattern, each component has a different responsibility in the overall app:
The Model is the core of the application, containing its data and logic – the thing which gives our app it's personality. The model does not communicate directly with the view.
The View objects are the "pretty face" of the app. The window, buttons, menus and so on, are all view object. They all displayed on the user screen and respond to the user's actions. Even though a view may get a request to handle an event that involved with data, the view won't talk to the model directly. The model will also never talk directly to the view.
To connect between these two snobs, we need a mediator, one that is called a Controller. Controller objects connect the app's view to its core logic and data. in other words, they deliver objects from the model to the view and vise-versa. this method creates a responsive and modular app.
.
.
<modelVersion>4.0.0</modelVersion>
<groupId>io.yearlyproject.roommates</groupId>
<artifactId>roommates</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Roommates</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
What is it? This XML code declares our project as a child of Springboot framework.
Spring sets up a lot of things under the wood. Our project, as a child of Springboot, inherits it all.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<jave.version>1.8</jave.version>
</properties>
What we're going to do now is creating the project's main class.
@SpringBootApplication
above the app class nameSpringAplication.run(RoommatesApp.class, args);
.
.
What a controller does is to decide what to return the client when a request is sent to the server. In java, a controller is basically a class marked with some fancy annotations. It contains code that manages which method to run when a URL access is requested.
Let's add a controller to our project, that what it does is each time we access the localhost we'll receive a greeting.
@RestController
above the class name. public String greetGuests() {
return "Welcome to Roommates website!";
}
Spring needs to know on which pages this method needs to be called. In order to do that, we need to use another annotation. By adding @RequestMapping("/")
above the class name we tell Spring that each time there is a HTTP request (GET,POST,.. ) to the main page of our website it has to excute this method. If we would have written "/greetings" inside the annotation bracket Spring would execute this method every time a client requested /greetings url.
4. Compile and run the application to check the results of what we have done so far.
.
Next we are going to add users to our project. For that we'll need to create 3 classes:
public class User {
private int id;
private String name;
private List<String> appartmentsPublished;
public User(int id, String name, List<String> appartmentsPublished) {
this.id = id;
this.name = name;
this.appartmentsPublished = appartmentsPublished;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public List<String> getAppartmentsPublished() {
return appartmentsPublished;
}
}
@Service
public class UserService {
private List<User> usersList = new ArrayList<>(Arrays.asList(
new User(1,"Alon", Arrays.asList("1","3")),
new User(2,"Or", Arrays.asList("2")),
new User(3,"Oren", Arrays.asList(""))
));
public List<User> getUsers() {
return usersList;
}
}
Note the usage of @Service
above the class name. when Spring sees @service it creates a singleton of the class during the app initialization. Imagine in the future how this getUsers() method can do all kinds of more advance things, like getting all the users from the database and such.
3. UserController class: this class is going to handle REST requests for users.
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/users")
public List<User> getUsers(){
return userService.getUsers();
}
}
Note the @RestController and @RequestMapping annotations which we've already covered. Besides that, notice @Autowired
marked above userService variable. This is a Spring annotation which markes the variable as needs a dependency injection. Spring will inject the singleton instance it created for UserService and inject it into this userService variable.
Now that we run the application and go to localhost:8080/users we will see all the hard-coded users in JSON format.
this is what we've got so far:
.
Let's make things a bit more complicated. What if we don’t want to get ALL the users, but we want to get a specific user from the server? Spring allows us to also do that, and we will now see how.
public Optional<User> getUser(int id) {
return usersList.stream().filter(user -> user.getId() == id).findFirst();
}
@RequestMapping("/users/{id}")
public User getUser(@PathVariable int id) {
return userService.getUser(id).orElse(null);
}
So what did we do here? You can see that now @RequestMapping
argument has this {id} in it. This tell Spring that the URI contains an argument which is going to be used in this method. this parameter needs to be marked with @PathVariable
, as you can see in the example above.
3. Now if we compile and run the app, and then go to http://localhost:8080/users/1 we will see that we only get Alon's record. If we try to go to http://localhost:8080/users/5 we'll receive a blank page since there is not user with id "5".
.
before we start, download Postman from chrome store. This tool will help us do POST requests to the server without the need of a UI.
.
public void addUser(User user) {
usersList.add(user);
}
RequestMapping("/users")
it will be a GET request by default. @RequestMapping(method=RequestMethod.POST, value="/users")
public void addUser(@RequestBody User user) {
userService.addUser(user);
}
Again, we also need to annotate the parameter with @RequestBody
. This annotation tells Spring that the POST data can be found in the HTTP request payload.
3. We also need User to have a default constructor:
public User() {}
Because we don't have an UI yet, will use Postman to send a POST request to our server.
let's start with an example:
public class User {
private Email email = new Email();
public void sendMessage(String msg) {
this.email.send(msg);
}
}
In this scenario, email is hard-coded into the User class body. This means that if we'll want to change the email service to some other (maybe more advance) service in the future it will be a harder task. Not to mention the difficulty if it is used in more classes. Another thing to consider is changing this email service to maybe Facebook or Whatsapp messaging – this will require a complete redesign of the class.
Even more importantly, testing can become very irritating. Because the User class is so strictly bounded to the Email class it cannot be tested without testing both of them. Imaging how it will feel like to see our mailbox blown up by emails sent by ourselves after a few sunny days of testing. Do we really want to send a real email every time we run a test? Apparently, there is no way to mock emails with the current implementation.
Let's do a second try:
public class User {
private MessageService msgSrv;
public User(MessageService msgSrv){
this. msgSrv = msgSrv;
}
public void sendMessage(String msg) {
this.msgSrv.send(msg);
}
}
We also need to make sure that Email implements MessageService. With this implementation, we are solving all of the above-mentioned problems.
But it still has a downside – every user creation requires many more lines of code now! i.e. the code becomes very verbose, especially if we decide to add more parameters to the User's constructor.
DI is a design pattern which we used in the above example. We removed the dependency resolution from compile-time to runtime and improved our classes to be loosely coupled, extendable and maintainable.
@Component
public class User {
//@Autowired
private MessageService msgSrv;
@Autowired
public User(MessageService msgSrv){
this. msgSrv = msgSrv;
}
//@Autowired
//public void setMessageService(MessageService msgSrv){
// this. msgSrv = msgSrv;
//}
public void sendMessage(String msg) {
this.msgSrv.send(msg);
}
}
Every Spring application has a Spring Container. By adding @component annotations above the class definition, we are adding these classes into the Spring Container. this allows Spring to be aware of them and manage them for us. Classes which are inside the Spring Container are called Spring Beans. Other annotations for Spring beans are: @repository, @service, @controller, each one having a different meaning to the Spring framework.
We also need to add @component above MessageService class so Spring will be able to inject it.
The @Autowired annotation tells Spring where we want the injection to be applied. The entities which are able to be marked using Spring DI annotations are: fields, constructors and setters. In the above example I'm showing all the options, in this case I chose to annotate the constructor.
2. The next thing we need to do is to create a configuration class that will configure what type of objects we want to inject.
@Configuration
@ComponentScan(value={…})
Public class DIConfiguration{
@Bean
Public MessageService getMessageService(){
return new HomingPigeon();
}
}
This division to configuration classes allows us to specify different configurations for different purposes. For instance, we can write a configuration that will be used in development, another one that will be used in production and other for testing.
@Configuration
tells Spring to treat this class as a configuration class. When that being interpreted into the Spring framework and can look for @bean inside it.
The @ComponentScan
the comes right after that defines where (in what packages) Spring should look for beans that require injects particular to this configuration.
Lastly @Bean
are the configuration itself. methods are used in order to match the interface to its implementation. In the above example, it injects HomingPigeon each time MessageService is required.
3. To drive everything up, we need to add the following code (note the in JUnit testing the methid is a bit different):
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DIConfiguration.class);
User user = context.getBean(User.class);
//we do things with user, like:
user.sendMessage("Your apartment ad was published successfully.");
//a bit of boilerplate for closing the context
context.close();
with the few annotations we used previously, AnnotationConfigApplicationContext can do its trick.
There is also a way to do DI with Spring using XML configuration file, which I will not cover here.
In OOP modularity of application is achieved by creating seperation of concerns between different classes. For example, if we have a User class we can create a Logger class to monitor user actions. Anyhow, the logger's methods will have to be called explicitly somewhere inside the user method to perform the logging. The problem with this design is that we have to add service code lines to the user's methods that are not linked to thier core buisness logic. In addition to that, we would probably want to use the logger in many other methods and class, making us to write the same code over and over again.
This is where AOP comes into play. We can use it to increase modularity by adding additional behavior (logging, security, transactions) without dirty the buisness code itself. It allows us to write separate pointcut specifications that specify what happens before or after the target-method executes! For example we can say: "log all methods calls that are annotated with @ log' or "run encryption code on data returned by methods which their names start with 'secured' ".
Before diving into implementation details, we have to get familiar with AOP terminology:
In order to use AspectJ, include these 3 dependencies to pom.xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.12</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
Spring provides five kinds of advice
@Before
- run advice before the execution of join point.@After
- run advice after the execution of join point (obviously). The advice will be executed both after method return and exception throw.@AfterReturning
– only after regular return of method.@AfterThrowing
– only after exception is thrown.@Around
– wraps the join point method and is executed before and after it.Public class Apartment {
private String id;
private int price = 0;
public Apartment(String id){
this.id = id;
}
public void getID(){
return id;
}
public void setPrice(int price){
if(price < 0){
throw new RuntimeException();
}else{
this.price = price;
}
}
}
Our ambition is to create a simple logger to track apartments usage, Let's do it!
@Component
@Aspect
@EnableAspectJAutoProxy
Public class LoggerAspect{
@AfterReturning("execution(path.to.Apartment.*(*)")
public void logAfter(JoinPoint jp){
System.out.println(jp.getSignature().getName() +" in " + jp.getTarget().getClass() + " finished successfully");
}
@AfterThrowing("within(path.to.Apartment)")
public void logFailures(JoinPoint jp){
System.out.prinln(jp.getSignature().getName()+" with args: "+jp.getArgs()+" in " + jp.getTarget().getClass() + " failed")
}
}
Here we've created a simple aspect class that logs every successful method execution of the Apartment class. The advice can recieve a JoinPoint object as parameter which can help dredge useful information regards the joinpoint object. We have also created an aspect that logs every method of Apartment class each time it throws an exception.
Few things to note:
@Component
@Aspect
@EnableAspectJAutoProxy
Public class LoggerAspect{
//…
@Around(@annotation(path.to.anotation.TimeMeasured)")
Public Object logTime(ProceedingJoinPoint pjp)
int startMillies = System.currentTimeMillis();
try{
value = pjp.proceed();
} catch( Throwable e) {
e.printStackTrace();
}
Int endMillies = System.currentTimeMillis();
System.out.prinln(jpj.getSignature().getName() + " took " + (endMillies - startMillies) + " milliseconds.");
Return value;
}
}
@around advice is required to include ProceedingJoinPoint as parameter. The proceed() method invokes the target joinpoint. It is also the advice responsibility to return the target's value. So basically, the advice precede and follows the target-method execution.
I hope you noticed the use of @annotation in the pointcut definition. In this context it means "run the advice every time you see a method annotated with @TimeMeasured".
Spring AspectJ can only work on Spring Beans, so we have to always remember to define the joinpoint classes as Beans.
lastly we can run our application:
//Config.class is some random class configuring which package should be scanned by Spring
ApplicationContext context = new AnnotationConfigurationApplicationContext(Config.class)
Apartment apartment = context.getBean("apartment",1);
//.. do some things with apartment
context.close();
use MongoDB tutorial to start using the database for further use (tutorial in #28)
Vue is a progressive framework for building UI. It is component oriented and uses templates in order to create and view layer of the application.
Vue, like other frameworks (like Angular) adds more power to the HTML and allows us to write more declarative code which is generated, by Vue, to a valid HTML code that browsers understand.
Here I will refer only to the differences that are more likely to be relevant to our needs, for a fuller comparison click here.
I won't get into details here because I believe that Angular is irrelevant in our case - it is too heavy and hard to learn for our case.
I believe that the best way to learn something is by using examples. Here I will build a simple application which displays a list of apartments and allows removing and deleting apartments from the list.
Using this tool is not obligatory, but using it allows us to write our components in a more organized way.
Webpack is a bundling tool. It get as an input a Javascript file in our case, and then goes after all its dependencies, "compiles" them and outputs a single bundle - a single script file. We can think about it like compiling many C files into one executable file.
Vue provides vue-loader for Webpack. This extension to Webpack allows us to write single-file-components, which are eventually "compiled" into a valid Javascript code that browsers can execute.
In order to use this, we will use NPM. We can go to https://nodejs.org, download and install it and now we have Node Package Manager which will be used to installing and running Webpack.
After installation finishes, we will navigate to the path where we want to open a directory for our project. Then we will open our CLI and run the following:
npm install -g vue-cli
vue init webpack-simple roomates
cd roomates
npm install
npm run dev
Our default browser should open at this point and display a page with Vue logo.
For this tutorial, we will look at the index.html
file and it the src
folder. index.html
file is our base file, this file contains a single element with "app" id.
In the src
folder we have main.js
:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
Here we import Vue and App component. Then we create a new Vue instance and inform Vue that the element with the "app" id is our application element. Vue will now replace this element with our App component.
Now we will go and explore src/App.vue
which contains our application:
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
<li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
<li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>
In the template tag we will write our template. This is HTML code that has some additional features added by Vue. we will learn about them later.
<script>
export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
Here we export our component. The data function returns an object which contains the data that will be injected to our template.
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
These are standard CSS rules. We can change <style>
to <style scoped>` to get scoped styling.
Firstly we will delete the template and style tags contents.
We want our app to contain a text field, which adds an apartment to a displayed list of apartments when we hit enter,
For our example, each list item will also be a component.
In the src
folder we will create a new components
folder. In this folder we will create a ListItem.vue
file:
<template>
<li>
{{ text }}
<button @click="removeMe">x</button>
</li>
</template>
Our template is a simple list item HTML element with some Vue options.
{{ text }}
means "write here the value of the text variable".
@click
means "onclick", when clicking we invoke the removeMe
method.
<script>
export default {
name: 'list-item',
props: ['itemIndex', 'itemText'],
data: function() {
return {
text: this.itemText,
index: this.itemIndex
}
},
methods: {
removeMe: function() {
this.$emit('remove', this.index);
}
}
}
</script>
Here we export our component.
props
element is an array that defines variables parameters the parent component can pass.data
is a function return a object that contains the variables of the component (such as text).methods
is an object that contains the methods defined in this component.So, we receive the index and the text of this list element. We display the text of the item and a button for removing it. When the button is clicked we run removeMe
.
$emit
is a function that triggers an event. The parent will listen to this event and will handle it. Here we trigger an event named "remove" (we can use any name we want) and pass our index as a parameter.
Now we will open src/App.vue
:
<template>
<div>
<input type="text" @keyup.enter="addItem" />
<ul>
<li
is="list-item"
v-for="(apartment, index) in apartments"
:item-index="index"
:item-text="apartment"
@remove="removeItem"
></li>
</ul>
</div>
</template>
We define here an input element and a list.
We declare that when a keybourd key up event is triggered and the key pressed is enter we invoke addItem.
Also we define a list. Each list item is a ListItem component according to the is
attribute. Generally we would use a <list-item>
tag instead of the is
attribute. Here we must use li
tag because we are in a ul
so we use the is
attribute.
v-for="(apartment, index) in apartments"
means that we iterate over the apartment variable and for each iteration we display another list item, where apartment
is the current element and index
is its index.:item-index="index"
means we pass the index (the colon at the beginning replaces the v-bind
and indicates that index
is a variable and not a string literal) to the item-index
prop of the list-item component.:item-text="apartment"
same. We pass the apartment
variable to the item-text
prop.@remove="removeItem"
- when remove event triggers we invoke the removeItem
method.<script>
import ListItem from './components/ListItem.vue'
export default {
name: 'app',
components: {
ListItem
},
data () {
return {
apartments: ['ex1', 'ex2', 'ex3']
}
},
methods: {
removeItem: function(index) {
this.apartments.splice(index, 1);
},
addItem: function(e) {
this.apartments.push(e.target.value);
}
}
}
</script>
Here we import our component and name it as ListItem. We register it in the components
field.
At the beginning we have 3 example apartments in the list.
removeItem
goes to the apartment array and just removes the element in the specified index. The beauty here is the fact that mutating the array will automatically change the UI, Vue does that for us.addItem
just adds a new item to the array, and again the list is updated automatically.That's it! We can now remove and add items to our list. We built a small application with components and used Webpack.
There are many more options that Vue offers, you can read more here.
Back-end:
Front-end:
Back end:
Front end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Back-end:
Front-end:
Front end:
Back-end:
Front-end:
Back end:
Front-end:
Back-end:
Front-end:
Write HLD document based on the following template:
13.11.17: @alonttal & @OrAbramovich - work in progress
Write the back-end API which is exposed to the UI based on the HLD.
link to the back-end API document: Back-end API
implement the queries that are metioned in #38
UI design: define components in Vue.JS, functions, pages, dependencies (based on the HLD).
Back-end should be able to communicate with the DB instance
There are various of aspects should be considered:
The goal:
Finding a good roommate can be a challenge. If you’re moving to a new city or simply don’t know anyone who is looking for a roommate, you may have to take your roommate search online. The project is about developing a friendly & powerful roommate search service for students. The service is going to be focused on the student needs.
The platform will let the students to :
- Post / view available apartments.
- Use search filters to find relevant apartments/roommmates.
First phase - plan and design the infrastructure of the platform:
- Choosing the main must have features (see #8 )
- Choosing geo-location services provider (see #7 )
- Choosing programming language & framework to be used in the project (see #6 )
- Choosing DB engine to be used in the project (see #5 )
- Choosing the delivered product (see #4 )
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.