Anda

Notes of study, work and life


  • Home

  • Tags28

  • Categories2

  • Archives29

  • Search

[Notes] Git notes

Posted on 2019-04-28 | In CS
Symbols count in article: 512 | Reading time ≈ 1 mins.

Create a remote repository and push

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git init
git add .
git commit -am 'init'

git config --local user.name username
git config --local user.email email

git config --list //check config

git config --local core.ignorecase false // turn case sensitivity off

// use http to connect
curl -u username https://api.github.com/user/repos -d '{"name":"RepoName"}'

// update
git remote add origin git@github.com:username/RepoName.git

git push origin master

[Notes] Cloud Computing Basic

Posted on 2019-04-18 | In CS
Symbols count in article: 11k | Reading time ≈ 10 mins.

Implement verifyLogin and getFullname

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Get the first name and last name and concat them to full name, given the userId
*/
@Override
public String getFullname(String userId) {
if (conn == null) return null;
String name = "";
try {
String sql = "SELECT first_name, last_name FROM users WHERE user_id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, userId);
ResultSet res = stmt.executeQuery();
if (res.next()) name = String.join(" ", res.getString("first_name"), res.getString("last_name"));
} catch (Exception e) {
e.printStackTrace();
}
return name;
}

/**
* Verify the userId and password
*/
@Override
public boolean verifyLogin(String userId, String password) {
if (conn == null) return false;
try {
String sql = "SELECT user_id FROM users WHERE user_id = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, userId);
stmt.setString(2, password);
ResultSet res = stmt.executeQuery();
if (res.next()) return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

Make search result aware of favorite history

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* get the info from request, query, and response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String userId = request.getParameter("user_id");
double lat = Double.parseDouble(request.getParameter("lat"));
double lon = Double.parseDouble(request.getParameter("lon"));

String keyword = request.getParameter("term");

// Connect db first
DBConnection conn = DBConnectionFactory.getConnection();
List<Item> items = conn.searchItems(lat, lon, keyword);

Set<String> favorite = conn.getFavoriteItemIds(userId);
conn.close();

JSONArray array = new JSONArray();
try {
for (Item item : items) {
JSONObject obj = item.toJSONObject();

// check if current item is a favorite item
// this field is required by front end to control the fav status
obj.put("favorite", favorite.contains(item.getItemId()));
array.put(obj);

}
} catch (Exception e) {
e.printStackTrace();
}
RpcHelper.writeJSONArray(response, array);
}

What’s Cloud Computing

Cloud computing is the delivery of on-demand computing resources—everything from applications to data centers—over the Internet on a pay-for-use basis.

Since 2006 when Amazon introduced the Elastic Compute Cloud

Features:

  • scalability,
  • flexibility,
  • on-demand,
  • reduced labor cost and data center cost, handled by SREs

Bad

  • data safety and privacy
  • cannot control downtime

Types

  • private cloud (VMware)
  • public cloud (Microsoft Azure, Google App Engine, Amazon EC2)
  • hybrid cloud

Amazon EC2

Elastic Compute Cloud (EC2)

EC2 allows scalable deployment of applications by providing a Web service through which a user can boot an Amazon Machine Image to create a virtual machine, which Amazon calls an “instance”, containing any software desired. A user can create, launch, and terminate server instances as needed, paying by the hour for active servers, hence the term “elastic”.

Launch an instance (Ubuntu linux)

Step 1, go to http://aws.amazon.com, sign into your account and then open EC2 dashboard. Launch an instance.

Step 2, Select the Ubuntu Server 16.04 image.

Step 3, Use t2.micro as instance, which is free tier eligible. Click next instead of launch.

Step 4, Jump to security group setup. You need to add 2 more TCP ports: 80, 8080.

Step 5, Click Launch, you will be asked to create a new key pair and download the private key. You can name it as mykey.pem

Connect to the instance

Mac

Open your terminal, run:

1
2
chmod 600 ~/Downloads/mykey.pem
ssh -i ~/Downloads/mykey.pem ubuntu@YOUR_INSTANCE_IP

if asked “Are you sure you want to continue connecting (yes/no)? ”, type “yes”, enter.

You are now on the remote server, you can play with Linux commands. hostname, ifconfig, whoami, uptime, pwd, ls

Windows

Windows (Putty)

  • Download Putty and Puttygen from https://the.earth.li/~sgtatham/putty/latest/x86/putty.zip

  • Open Puttygen, “Conversions”->”Import key”, select mykey.pem file, Save private key as mykey.ppk

14. Cloud Computing-2019-4-17-20-13-19.png

  • Open Putty, enter host ip, in SSH->Auth, choose your ppk file

14. Cloud Computing-2019-4-17-20-13-30.png

  • Click Open, enter the username ubuntu

14. Cloud Computing-2019-4-17-20-13-42.png

Install Java

Step 1, In your instance’s terminal, execute the following commands:

  • sudo apt-get update
  • sudo apt-get install default-jre

Step 2, You can verify with

  • java -version

Install MySQL

Step 1, sudo apt-get install mysql-server. When you are asked for new mysql password, use “root”.

Step 2, after installation, type mysql -u root -p in your terminal, then input the “root” as password.

Step 3, In the mysql shell, paste the following SQL statements to install the tables:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DROP DATABASE IF EXISTS myproject;

CREATE DATABASE myproject;

USE myproject;

CREATE TABLE items (item_id VARCHAR(255) NOT NULL, name VARCHAR(255), rating FLOAT, address VARCHAR(255), image_url VARCHAR(255), url VARCHAR(255), distance FLOAT, PRIMARY KEY ( item_id));

CREATE TABLE categories (item_id VARCHAR(255) NOT NULL, category VARCHAR(255) NOT NULL, PRIMARY KEY ( item_id, category), FOREIGN KEY (item_id) REFERENCES items(item_id));

CREATE TABLE users (user_id VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, first_name VARCHAR(255), last_name VARCHAR(255), PRIMARY KEY ( user_id ));
CREATE TABLE history (user_id VARCHAR(255) NOT NULL, item_id VARCHAR(255) NOT NULL, last_favor_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (user_id, item_id), FOREIGN KEY (item_id) REFERENCES items(item_id), FOREIGN KEY (user_id) REFERENCES users(user_id));

INSERT INTO users VALUES ("1111", "3229c1097c00d497a0fd282d586be050", "John", "Smith");

Step 4, Type “exit” to quit mysql shell.

Install Tomcat 9

Step 1, Execute the following commands

1
2
3
4
5
6
7
8
cd /opt/
sudo wget http://apache.mirrors.hoobly.com/tomcat/tomcat-9/v9.0.19/bin/apache-tomcat-9.0.19.tar.gz
sudo tar xzf apache-tomcat-9.0.8.tar.gz
sudo ln -s apache-tomcat-9.0.8 tomcat
echo "export CATALINA_HOME=\"/opt/tomcat\"" >> ~/.bashrc
source ~/.bashrc
cd /opt/tomcat
sudo bin/startup.sh

Step 2, Verify with http://YOUR_INSTANCE_IP:8080/

Run Jupiter on EC2

WAR file (or Web application ARchive) is a JAR file used to distribute a collection of JavaServer Pages, Java Servlets, Java classes, XML files, tag libraries, static web pages (HTML and related files) and other resources that together constitute a web application.

Step 1, Open Eclipse and MAMP, verify your website works correctly on local environment:
http://localhost:8080/Jupiter/

Step 2, open your MySQLDBUtil.java, change and make sure port is 3306, and username and password are root.

3306 is default port in MySQL

Step 3, In Eclipse, select File -> Export -> Web->war File, save the war file to disk.

Step 4, Copy the war file to your instance.

MAC:
Open a new terminal window and type:

1
scp -i ~/Downloads/mykey.pem  ~/Downloads/Jupiter.war ubuntu@YOUR_INSTANCE_IP:~/

Windows (MSYS2):

1
scp -i /c/Users/<YOUR_USERNAME>/Downloads/mykey.pem  /c/Users/<YOUR_PATH>/Jupiter.war ubuntu@YOUR_INSTANCE_IP:~/

Windows (putty):
use WinSCP, https://winscp.net/download/WinSCP-5.13.2-Setup.exe

14. Cloud Computing-2019-4-18-10-31-3.png

Click Advanced->SSH->Authentication->Private key file: choose *.ppk

14. Cloud Computing-2019-4-18-10-31-14.png

Drag the Jupiter.war to the left (into /home/ubuntu/).

14. Cloud Computing-2019-4-18-10-31-26.png

Step 5, Both Mac and Windows, back to your terminal/putty, type the following command

1
sudo cp ~/Jupiter.war /opt/tomcat/webapps/

Step 6, Wait for a few seconds, then you can verify the server on your browser:
http://YOUR_INSTANCE_IP:8080/Jupiter/

Redeploy application: redo step 3-5.

Debug configuration

此处需要将eclipse的jdk jre compiler全部设为1.8并重新编译,即可解决版本问题。

(optional) Change the HTTP port from 8080 to 80

Step 1, On the remote command-line terminal, edit the tomcat configuration by:

1
sudo vim /opt/tomcat/conf/server.xml

Step 2, Press i to enter edit mode, scroll down to find the following line (around line 69):

1
2
<Connector port="8080" protocol="HTTP/1.1"
change "8080" to "80"

Step 3, Press ESC to exit edit mode, then type :wq to save and exit.

Step 4, Restart tomcat by:

1
2
sudo /opt/tomcat/bin/shutdown.sh
sudo /opt/tomcat/bin/startup.sh

Step 5, Visit http://YOUR_IP_ADDRESS/Jupiter/ to see if the server is started correctly.

此处端口设为80,以后访问时就不需要再额外输入端口号了

(optional) Make tomcat auto start when Linux boots

Step 1, On you instance’s terminal, type the following command:

1
sudo vim /etc/init.d/tomcat

Step 2, Press i to enter the INSERT mode, then paste the following contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash

### BEGIN INIT INFO
# Provides: tomcat
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/Stop Tomcat server
### END INIT INFO


PATH=/sbin:/bin:/usr/sbin:/usr/bin

start() {
sh /opt/tomcat/bin/startup.sh
}

stop() {
sh /opt/tomcat/bin/shutdown.sh
}

case $1 in
start|stop) $1;;
restart) stop; start;;
*) echo "Run as $0 <start|stop|restart>"; exit 1;;
esac

Step 3, Press Esc to exit INSERT mode, then type :wq to save and quit.

Step 4, Make the new file executable:

1
sudo chmod +x /etc/init.d/tomcat

Step 5, update bashrc to catch your script:

1
sudo update-rc.d tomcat defaults

Step 6, (optional) you can use sudo /etc/init.d/tomcat restart to manually restart tomcat.

(optional) Make tomcat auto restart everyday

Your web app may be not that stable to run for months. You can restart it every night to keep it healthy.

Step 1, On you instance’s terminal, type the following command:

1
sudo crontab -e

Step 2, Input 3 to select vim.basic as the editor

Step 3, Move the cursor to the end, press i to enter edit mode. Input the following, It means restart tomcat at 1:00 and 13:00 UTC everyday.:

1
0 1,13   *   *   *   sudo /etc/init.d/tomcat restart

定时在1:00和13:00tomcat重启

Step 4, Press Esc to exit INSERT mode, then type :wq to save and quit.

Remote debug:

You can check Java error from Tomcat runtime log. Location:

1
/opt/tomcat/logs/localhost.<date>.log
  • Check tomcat process:
    ps aux|grep tomcat
1
root     17273 78.3  7.9 2225932 80404 pts/0   Sl   20:30   0:02 /usr/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/opt/tomcat -Dcatalina.home=/opt/tomcat -Djava.io.tmpdir=/opt/tomcat/temp org.apache.catalina.startup.Bootstrap start

17273 is the process id

  • To kill the process
1
Sudo kill -9 17273

[Notes] AJAX Basic

Posted on 2019-04-18 | Edited on 2019-04-17 | In CS
Symbols count in article: 9.8k | Reading time ≈ 9 mins.

What is AJAX?

AJAX is not a programming language.
AJAX just uses a combination of:

  • A browser built-in XMLHttpRequest object (to request data from a web server)
  • JavaScript and HTML DOM (to display or use the data)

AJAX 可以实现异步通信

How AJAX Works

13. AJAX Basic-2019-4-17-13-40-54.png

How to use AJAX

The keystone of AJAX is the XMLHttpRequest object.

creating an XMLHttpRequest object

1
var xhttp = new XMLHttpRequest();

send a request to a server, we use the open() and send() methods of the XMLHttpRequest object

1
2
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();

13. AJAX Basic-2019-4-17-13-46-10.png

GET or POST?

GET is simpler and faster than POST, and can be used in most cases.
However, always use POST requests when:

  • A cached file is not an option (update a file or database on the server).
  • Sending a large amount of data to the server (POST has no size limitations).
  • Sending user input (which can contain unknown characters), POST is more robust and secure than GET.

Project

demo of our web applications: http://34.211.21.63/Event/

Complete HTML/CSS/Javascript code

http://jsbin.com/hocukukiva/edit?html,css,js

将JSBin里面的代码分别放在:

1
2
3
/WebContent/index.html
/WebContent/styles/main.css
/WebContent/scripts/main.js

访问: http://localhost:8080/Jupiter

自动跳转至index.html
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset

1
2
3
4
5
6
7
font-size: 0.9em; 
/* means 0.9 * parent's font-size */

.top-nav {
/* flex means listed from left to right */
flex: 1;
}

JavaScript

Step 1 ()() Run the scripts

1
2
3
4
// Run all following scripts
(function() {

})()

Step 2 Gloval Variables

1
2
3
4
var user_id = '1111';
var user_fullname = 'John Smith';
var lng = -122.08;
var lat = 37.38;

step3: main function(entrance)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
init();
/* step4: define init function */
function init() {
// Register event listeners
$('nearby-btn').addEventListener('click', loadNearbyItems);
// $('fav-btn').addEventListener('click', loadFavoriteItems);
// $('recommend-btn').addEventListener('click', loadRecommendedItems);

var welcomeMsg = $('welcome-msg');
welcomeMsg.innerHTML = 'Welcome, ' + user_fullname;

// step 7
initGeoLocation();
}

step5: create $ function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* A helper function that creates a DOM element <tag options...>
*/
function $(tag, options) {
if (!options) {
return document.getElementById(tag);
}
var element = document.createElement(tag);

for ( var option in options) {
if (options.hasOwnProperty(option)) {
element[option] = options[option];
}
}
return element;
}

step6: create AJAX helper function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* @param method - GET|POST|PUT|DELETE
* @param url - API end point
* @param callback - This the successful callback
* @param errorHandler - This is the failed callback
*/
function ajax(method, url, data, callback, errorHandler) {
var xhr = new XMLHttpRequest();

xhr.open(method, url, true);

// 判断request
xhr.onload = function() {
// 判断 resopnse
if (xhr.status === 200) {
// callback 属于回调函数
callback(xhr.responseText);
} else if (xhr.status === 403) {
onSessionInvalid();
} else {
errorHandler();
}
};

xhr.onerror = function() {
console.error("The request couldn't be completed.");
errorHandler();
};

if (data === null) {
xhr.send();
} else {
xhr.setRequestHeader("Content-Type",
"application/json;charset=utf-8");
xhr.send(data);
}
}

step 7: initGeoLocation function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function initGeoLocation() {
if (navigator.geolocation) {
// step 8
// get current position by browser.
navigator.geolocation.getCurrentPosition(onPositionUpdated,
onLoadPositionFailed, {
maximumAge : 60000
});
showLoadingMessage('Retrieving your location...');
} else {
// step 9
onLoadPositionFailed();
}
}

step 8: onPositionUpdated function

1
2
3
4
5
6
7
function onPositionUpdated(position) {
lat = position.coords.latitude;
lng = position.coords.longitude;

// step 11
loadNearbyItems();
}

step 9: onLoadPositionFailed function

1
2
3
4
5
6
function onLoadPositionFailed() {
console.warn('navigator.geolocation is not available');

//step 10
getLocationFromIP();
}

step 10: getLocationFromIP function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getLocationFromIP() {
// Get location from http://ipinfo.io/json
var url = 'http://ipinfo.io/json'
var req = null;
ajax('GET', url, req, function(res) {
var result = JSON.parse(res);
if ('loc' in result) {
var loc = result.loc.split(',');
lat = loc[0];
lng = loc[1];
} else {
console.warn('Getting location by IP failed.');
}
// step 11
loadNearbyItems();
});
}

step 11: loadNearbyItems function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* API #1 Load the nearby items API end point: [GET]
* /Dashi/search?user_id=1111&lat=37.38&lon=-122.08
*/
function loadNearbyItems() {
console.log('loadNearbyItems');
// step 12
activeBtn('nearby-btn');

// The request parameters
var url = './search';
var params = 'user_id=' + user_id + '&lat=' + lat + '&lon=' + lng;
var req = JSON.stringify({});

// step 13
// display loading message
showLoadingMessage('Loading nearby items...');

// make AJAX call
ajax('GET', url + '?' + params, req,
// successful callback
function(res) {
var items = JSON.parse(res);
if (!items || items.length === 0) {
// step 14
showWarningMessage('No nearby item.');
} else {
// step 16
listItems(items);
}
},
// failed callback
function() {
// step 15
showErrorMessage('Cannot load nearby items.');
});
}

step 12: activeBtn function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* A helper function that makes a navigation button active
*
* @param btnId - The id of the navigation button
*/
function activeBtn(btnId) {
var btns = document.getElementsByClassName('main-nav-btn');

// deactivate all navigation buttons
for (var i = 0; i < btns.length; i++) {
btns[i].className = btns[i].className.replace(/\bactive\b/, '');
}

// active the one that has id = btnId
var btn = $(btnId);
btn.className += ' active';
}

step 13: showLoadingMessage function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function showLoadingMessage(msg) {
var itemList = $('item-list');
itemList.innerHTML = '<p class="notice"><i class="fa fa-spinner fa-spin"></i> '
+ msg + '</p>';
}

/** step 14: showWarningMessage function **/
function showWarningMessage(msg) {
var itemList = $('item-list');
itemList.innerHTML = '<p class="notice"><i class="fa fa-exclamation-triangle"></i> '
+ msg + '</p>';
}

/** step15: showErrorMessage function **/
function showErrorMessage(msg) {
var itemList = $('item-list');
itemList.innerHTML = '<p class="notice"><i class="fa fa-exclamation-circle"></i> '
+ msg + '</p>';
}

step16: listItems function

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @param items - An array of item JSON objects
*/
function listItems(items) {
// Clear the current results
var itemList = $('item-list');
itemList.innerHTML = '';

for (var i = 0; i < items.length; i++) {
// step 17
addItem(itemList, items[i]);
}
}

step17: addItem function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
* Add item to the list
* @param itemList - The <ul id="item-list"> tag
* @param item - The item data (JSON object)
*/
function addItem(itemList, item) {
var item_id = item.item_id;

// create the <li> tag and specify the id and class attributes
var li = $('li', {
id : 'item-' + item_id,
className : 'item'
});

// set the data attribute
li.dataset.item_id = item_id;
li.dataset.favorite = item.favorite;

// item image
if (item.image_url) {
li.appendChild($('img', {
src : item.image_url
}));
} else {
li.appendChild($('img', {
src : 'https://assets-cdn.github.com/images/modules/logos_page/GitHub-Mark.png'
}))
}
// section
var section = $('div', {});

// title
var title = $('a', {
href : item.url,
target : '_blank',
className : 'item-name'
});
title.innerHTML = item.name;
section.appendChild(title);

// category
var category = $('p', {
className : 'item-category'
});
category.innerHTML = 'Category: ' + item.categories.join(', ');
section.appendChild(category);

var stars = $('div', {
className : 'stars'
});

for (var i = 0; i < item.rating; i++) {
var star = $('i', {
className : 'fa fa-star'
});
stars.appendChild(star);
}

if (('' + item.rating).match(/\.5$/)) {
stars.appendChild($('i', {
className : 'fa fa-star-half-o'
}));
}

section.appendChild(stars);

li.appendChild(section);

// address
var address = $('p', {
className : 'item-address'
});

address.innerHTML = item.address.replace(/,/g, '<br/>').replace(/\"/g,
'');
li.appendChild(address);

// favorite link
var favLink = $('p', {
className : 'fav-link'
});

favLink.onclick = function() {
changeFavoriteItem(item_id);
};

favLink.appendChild($('i', {
id : 'fav-icon-' + item_id,
className : item.favorite ? 'fa fa-heart' : 'fa fa-heart-o'
}));

li.appendChild(favLink);

itemList.appendChild(li);
}

[Notes] Simple Recommendation System

Posted on 2019-04-17 | In CS
Symbols count in article: 9.2k | Reading time ≈ 8 mins.

Continue to implement get history

Implement getFavoriteItemsmethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* Get the favorite items given userId in the history table
* userId -> itemId -> favorite items
*/
@Override
public Set<Item> getFavoriteItems(String userId) {
if (conn == null) return new HashSet<Item>();
Set<Item> favoriteItems = new HashSet<Item>();
Set<String> itemIds = getFavoriteItemIds(userId);

try {
String sql = "SELECT * FROM items WHERE item_id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
for (String itemId: itemIds) {
stmt.setString(1, itemId);
// executeQuery returns a table(ResultSet)
ResultSet res = stmt.executeQuery();
ItemBuilder builder = new ItemBuilder();
// iterator
while (res.next()) {
builder.setItemId(res.getString("item_id"));
builder.setName(res.getString("name"));
builder.setAddress(res.getString("address"));
builder.setImageUrl(res.getString("image_url"));
builder.setUrl(res.getString("url"));
builder.setCategories(getCategories(itemId));
builder.setDistance(res.getDouble("distance"));
builder.setRating(res.getDouble("rating"));


favoriteItems.add(builder.build());
}

}
} catch (SQLException e) {
e.printStackTrace();
}
return favoriteItems;
}

Next, let’s try getFavoriteItemIds and getCategories

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* Given userId, query history table, get corresponding item_id.
*/
@Override
public Set<String> getFavoriteItemIds(String userId) {
if (conn == null) return new HashSet<String>();
Set<String> favoriteItemIds = new HashSet<String>();
try {
String sql = "SELECT * FROM history WHERE user_id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, userId);
ResultSet res = stmt.executeQuery();
while (res.next()) {
favoriteItemIds.add(res.getString("item_id"));
}
} catch (SQLException e) {
e.printStackTrace();
}

return favoriteItemIds;
}

/**
* Given itemId, query categories table, get corresponding categories
*/
@Override
public Set<String> getCategories(String itemId) {
if (conn == null) return new HashSet<>();
Set<String> categories = new HashSet<String>();
try {
String sql = "SELECT category FROM categories WHERE item_id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, itemId);
ResultSet res = stmt.executeQuery();
while (res.next()) {
categories.add(res.getString("category"));
}

} catch (SQLException e) {
e.printStackTrace();
}
return categories;
}

Get back to ItemHistory.java, update doGet method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Get the user_id from request, query the favorite items, and handle the response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userId = request.getParameter("user_id");
JSONArray array = new JSONArray();

DBConnection conn = DBConnectionFactory.getConnection();
Set<Item> items = conn.getFavoriteItems(userId);
for (Item item: items) {
JSONObject obj = item.toJSONObject();
try {
obj.append("favorite", true);
} catch (JSONException e) {
e.printStackTrace();
}
array.put(obj);
}
RpcHelper.writeJSONArray(response, array);
}

test with http://localhost:8080/Jupiter/history?user_id=1111

Recommendation System

Widely exists in industry and it is a popular interview question.

Facebook: news feed, friends, ‘Do you know this friend?’的例子

LinkedIn: jobs, companies, acquaintances, ‘Are you interested in this job?’的例子

Amazon: 电饭锅的例子

Google Ads: 两颗红豆的例子

Engineering Design

  1. Given a user, fetch all the events (ids) this user has visited. (which table? which API?)

    1
    2
    //history: history_id, user_id, item_id, last_favor_time.
    Set<String> itemIds = getFavoriteItemIds(userId);
  2. given all these events, what are the categories? (which table? which API?)

    1
    2
    //categories: item_id, category.
    Set<String> categories = getCategories(itemId);
  3. given these categories, what are the events that belong to them (which table? which API?)

1
2
//external API
List<Item> items = searchItems(userId, lat, lon, category);
  1. filter events that this user has visited

12. Simple Recommendation System-2019-4-17-11-58-6.png

Code Implementation

Add a new package src/algorithm. Add GeoRecommendation.java.

Idea of this algorithm: First get the current user’s favourite items, then get all categories of this user’s favorites, sort them by descending order. Then get these categories, search items again, sort this items with distance(Ascending order), and add those items to the result. Category > Distance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public List<Item> recommendItems(String userId, double lat, double lon) {
List<Item> recommendedItems = new ArrayList<Item>();
DBConnection conn = DBConnectionFactory.getConnection();
// 1. Get all favorite itemIds
Set<String> favoriteItemIds = conn.getFavoriteItemIds(userId);

// 2. Get all categories by favorite items, sort by count
// Use a map to store category and its counts
Map<String, Integer> allCategories = new HashMap<>();
for (String itemId: favoriteItemIds) {
Set<String> categories = conn.getCategories(itemId);
for (String category: categories) {
allCategories.put(category, allCategories.getOrDefault(category, 0) + 1);
}
}

// Sort the category
// avoid integer overflow, Use Integer.compare(int, int)
List<Entry<String, Integer>> categoryList = new ArrayList<>(allCategories.entrySet());

// more occurrences first
Collections.sort(categoryList, new Comparator<Entry<String, Integer>>(
) {

@Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
return Integer.compare(o2.getValue(), o1.getValue());
}
});

// 3. do search based on category, filter out favorite events, sort by distance

Set<Item> visitedItems = new HashSet<Item>();
for (Entry<String ,Integer> category: categoryList) {
List<Item> items = conn.searchItems(lat, lon, category.getKey());
List<Item> filteredItems = new ArrayList<Item>();
for (Item item: items) {
// if not visited again and not already in the favorite list, add to recommendation list
if (!favoriteItemIds.contains(item.getItemId()) && !visitedItems.contains(item)) {
filteredItems.add(item);
}
}

// sort the items in filtered items. less distance first
Collections.sort(filteredItems, new Comparator<Item>() {

@Override
public int compare(Item o1, Item o2) {
return Double.compare(o1.getDistance(), o2.getDistance());
}
});

visitedItems.addAll(items);
recommendedItems.addAll(filteredItems);
}

return recommendedItems;
}

Step 2, Go to src/rpc/RecommendItem.java, implement doGet()method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Get the lat and lon and current userId, return a list of recommended items
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userId = request.getParameter("user_id");
double lat = Double.parseDouble(request.getParameter("lat"));
double lon = Double.parseDouble(request.getParameter("lon"));

GeoRecommendation recommendation = new GeoRecommendation();
List<Item> items = recommendation.recommendItems(userId, lat, lon);

JSONArray result = new JSONArray();
try {
for(Item item: items) {
result.put(item.toJSONObject());
}
} catch (Exception e) {
e.printStackTrace();
}
RpcHelper.writeJSONArray(response, result);
}

Step 3, De-duplicate items in recommendation results.

Since we’re using set to save results from our recommendation function, we need do the de-duplication based on item_id. So go to Item.java, add hashCode() and equals().

Eclipse provides an easy way to add this two methods. Careful, only select itemId when generating these methods.

[Notes] JavaScript Basic 2

Posted on 2019-04-16 | In CS
Symbols count in article: 3.1k | Reading time ≈ 3 mins.

Scope chain

In JavaScript there are two types of scope:

  • Local scope
  • Global scope
    JavaScript has function scope: Each function creates a new scope.

Scope determines the accessibility (visibility) of these variables.

Variables defined inside a function are not accessible (visible) from outside the function.

11. JavaScript Basic 2-2019-4-16-14-55-3.png

Scope chain

The scope chain property of each execution context is simply a collection of the current context variable object + all parent’s lexical variable objects.

11. JavaScript Basic 2-2019-4-16-14-55-8.png

11. JavaScript Basic 2-2019-4-16-15-12-31.png

this in JavaScript

11. JavaScript Basic 2-2019-4-16-14-56-38.png

1
2
3
4
5
6
7
8
<script>
function add(a, b) {
this.a = 19;
// window is a father object in JS
// 如果函数调用中没指定当前是类还是函数(是否有new),this默认指window
console.log('a' in window); // return true
}
</script>

Closure

Definition

A closure is a function having access to the parent scope, even after the parent function has closed.

11. JavaScript Basic 2-2019-4-16-15-34-31.png

Closure here includes the annonymous function and the local variable arg. Here the local variable won’t be released even add() is ended.

examples:
11. JavaScript Basic 2-2019-4-16-15-45-18.png

BOM & DOM

BOM

There are no official standards for the Browser Object Model (BOM).
Since modern browsers have implemented (almost) the same methods and properties for JavaScript interactivity, it is often referred to, as methods and properties of the BOM.

The BOM (Browser Object Model) consists of the objects navigator, history,screen, location and document which are children of window

DOM

The Document Object Model (DOM) connects web pages to scripts or programming languages. Usually that means JavaScript. The DOM model represents a document with a logical tree. DOM methods allow programmatic access to the tree; with them you can change the document’s structure, style or content. DOM nodes can have event handlers attached to them. Once an event is triggered, the event handlers get executed.

Document Object

  • When an HTML document is loaded into a web browser, it becomes a document object.
  • The document object is the root node of the HTML document.

11. JavaScript Basic 2-2019-4-16-15-58-16.png

Finding HTML Elements

Method Description
document.getElementById(id) Find an element by element id
document.getElementsByTagName(name) Find elements by tag name
document.getElementsByClassName(name) Find elements by class name

Changing HTML Elements

Method Description
element.innerHTML = new html content Change the inner HTML of an element
element.attribute = new value Change the attribute value of an HTML element
element.setAttribute(attribute, value) Change the attribute value of an HTML element
element.style.property = new style Change the style of an HTML element

Adding and Deleting Elements

Method Description
document.createElement(element) Create an HTML element
document.removeChild(element) Remove an HTML element
document.appendChild(element) Add an HTML element
document.replaceChild(element) Replace an HTML element
document.write(text) Write into the HTML output stream

11. JavaScript Basic 2-2019-4-16-16-6-14.png

Event

  1. Capturing phase – the event goes down to the element.
  2. Bubbling phase – the event bubbles up from the element.
    11. JavaScript Basic 2-2019-4-16-16-7-19.png

DOM0 - onclick

11. JavaScript Basic 2-2019-4-16-16-20-12.png

Don’t write JS code inline.

DOM2 - addEventListener

11. JavaScript Basic 2-2019-4-16-16-31-8.png

11. JavaScript Basic 2-2019-4-16-16-31-24.png

捕获阶段与冒泡阶段区别在于谁先触发

Example:

11. JavaScript Basic 2-2019-4-16-16-40-14.png

[Notes] MySQL Basic 2

Posted on 2019-04-16 | In CS
Symbols count in article: 9.1k | Reading time ≈ 8 mins.

Save search results to database

  1. Under db.mysql package, create class/MySQLConnection.java.
  2. Implement DBConnection interface
  3. Implement both close method and constructor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// connection
private Connection conn;

// constructor
public MySQLConnection() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection(MySQLDBUtil.URL);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* close the connection
*/
@Override
public void close() {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
  1. implement searchItems() in MySQLConnection. Previously we call TicketMasterAPI.search from our SearchItem servlet directly. But actually our recommendation code also needs to call the same search function, so we make a designated function here to do the search call.
    The code is simply copied from what we’ve already had in SearchItem.java.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Search Item. Same as TMAPI search item.
*/
@Override
public List<Item> searchItems(double lat, double lon, String term) {
// Get the items from TM
TicketMasterAPI tmAPI = new TicketMasterAPI();
List<Item> items = tmAPI.search(lat, lon, term);
// Save the items to the db
for (Item item: items) {
saveItem(item);
}
return items;
}
  1. after searchItem, let’s try saveItem to save data into database. Again, careful with the import suggestions. Always choose java.sql.*.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Save single item into db
*/
@Override
public void saveItem(Item item) {
if (conn == null) {
return;
}
try {
String sql = "INSERT IGNORE INTO items VALUES (?, ?, ?, ?, ?, ?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
// Index starts from 1
stmt.setString(1, item.getItemId());
stmt.setString(2, item.getName());
stmt.setDouble(3, item.getRating());
stmt.setString(4, item.getAddress());
stmt.setString(5, item.getImageURL());
stmt.setString(6, item.getUrl());
stmt.setDouble(7, item.getDistance());
stmt.execute();

// set categories
sql = "INSERT IGNORE INTO categories VALUES(?, ?)";
stmt = conn.prepareStatement(sql);
for (String category: item.getCategories()) {
stmt.setString(1, item.getItemId());
stmt.setString(2, category);
stmt.execute();
}

} catch (SQLException e) {
e.printStackTrace();
}

}

Use PreparedStatement and stmt.settring() can effectively avoid SQL injection.

PreparedStatement is faster than raw String. Only have to create it once.

  1. SQL injection. Turns the input to the SQL statement, and makes the query always true.
1
2
3
4
5
6
7
8
9
10
11
12

// SQL injection
// Example:
// SELECT * FROM users WHERE username = '<username>' AND password = '<password>';
//
// sql = "SELECT * FROM users WHERE username = '" + username + "'
// AND password = '" + password + "'"
//
// username: aoweifjoawefijwaoeifj
// password: 123456' OR '1' = '1
//
// SELECT * FROM users WHERE username = 'aoweifjoawefijwaoeifj' AND password = '123456' OR '1' = '1'
  1. update DBConnectionFactory.
1
2
3
4
5
6
7
8
9
10
11
public static DBConnection getConnection(String db) {
switch (db) {
case "mysql":
return new MySQLConnection();
case "mongodb":
// return new MongoDBConnection();
return null;
default:
throw new IllegalArgumentException("Invalid db: " + db);
}
}
  1. In src/rpc/SearchItem.java, add a private dbconnection field and update doGet().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub

double lat = Double.parseDouble(request.getParameter("lat"));
double lon = Double.parseDouble(request.getParameter("lon"));

String keyword = request.getParameter("term");

// Connect db first then search
DBConnection conn = DBConnectionFactory.getConnection();
List<Item> items = conn.searchItems(lat, lon, keyword);

JSONArray array = new JSONArray();
try {
for (Item item : items) {
JSONObject obj = item.toJSONObject();
array.put(obj);
}
} catch (Exception e) {
e.printStackTrace();
}
RpcHelper.writeJSONArray(response, array);
}

Implement set/unset favorite related functions

  1. let’s try setFavoriteItem and unsetFavoriteItem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* Operate on History table.
* insert favorite information.
*/
@Override
public void setFavoriteItems(String userId, List<String> itemIds) {
if (conn == null) {
return;
}
try {
String sql = "INSERT IGNORE INTO history (?, ?)";
PreparedStatement stmt = conn.prepareStatement(sql);
for (String itemId: itemIds) {
stmt.setString(1, userId);
stmt.setString(2, itemId);
stmt.execute();
}
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* Delete favorite information
*/
@Override
public void unsetFavoriteItems(String userId, List<String> itemIds) {
if (conn == null) {
return;
}
try {
String sql = "DELETE FROM history WHERE user_id = ? AND item_id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
for (String itemId: itemIds) {
stmt.setString(1, userId);
stmt.setString(2, itemId);
stmt.execute();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
  1. create a new servlet called ItemHistory, update the url mapping to \history

  2. create a new function in RpcHelper.java to parse HTTP request body. Imagine the input HTTP request looks like:

1
2
3
4
5
6
7
{
user_id = “1111”,
favorite = [
“abcd”,
“efgh”,
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Read the http request and parse it as a JSONObject.
* @param request
* @return
*/
public static JSONObject readJsonObject(HttpServletRequest request) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = request.getReader();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
return new JSONObject(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
  1. update doPost() and doDelete in ItemHistory.java to use this new function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Get the set favourite request and do the corresponding operation
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// get userId, itemIDs from request
JSONObject input = RpcHelper.readJsonObject(request);
String userId = input.getString("user_id");
JSONArray fav_array = input.getJSONArray("favorite");
List<String> itemIds = new ArrayList<>();
for (int i = 0; i < fav_array.length(); i++) {
itemIds.add(fav_array.get(i).toString());
}

// connect db and update the table
DBConnection conn = DBConnectionFactory.getConnection();
conn.setFavoriteItems(userId, itemIds);
conn.close();
RpcHelper.writeJSONObject(response, new JSONObject().put("result", "SUCCESS"));

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* Same as doPost(), but change setFavoriteItems() to unsetFavoriteItems()
*/
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  1. open postman, switch to post method, use http://localhost:8080/Jupiter/history, then copy the following JSON object into body. Replace item_id1 and item_id2 with the real item_id exist in your item table.
1
2
3
4
5
6
7
{
'user_id':'1111',
'favorite' : [
'item_id1',
'item_id2'
]
}
  1. now let’s send another request to test our delete function. Open another tab in postman, switch method to delete, use http://localhost:8080/Jupiter/history, then copy the following JSON object into body. Again replace item_id1 with the real item_id exist in your history table.
    1
    2
    3
    4
    5
    6
    {
    'user_id':'1111',
    'favorite' : [
    'item_id1',
    ]
    }

[Notes] JavaScript Basic

Posted on 2019-04-14 | In CS
Symbols count in article: 8.2k | Reading time ≈ 7 mins.

Linking JavaScript file and html file

Adding JavaScript into an HTML Document

You can add JavaScript code in an HTML document by employing the dedicated HTML tag<script> that wraps around JavaScript code.
The <script> tag can be placed in the <head> section of your HTML, in the <body> section, or after the </body> close tag, depending on when you want the JavaScript to load.

Method 1: Inline Mode

9. JavaScript Basic-2019-4-13-18-32-30.png

不便于代码分离

Method 2: using <script> tag

The <script> tag can be placed in the <head> section of your HTML, in the <body> section, or after the </body> close tag, depending on when you want the JavaScript to load.

  • Internal Style
  • External Style
  • 9. JavaScript Basic-2019-4-13-18-38-21.png

浏览器先执行完<script>tag才会渲染其他组件

JavaScript Fundamentals

variables

  • three ways of variable declaration:
    • let
    • var
    • const

We use those three keywords to create variables in JavaScript. Example: let message; or var message; or const message;

  1. var variables are defined from the beginning of the function, no matter where the definition is.
  2. var has no block scope.
  3. var can be declared many times, but let and const cannot in the same scope.
  4. const is used to declare a constant (unchanging) variable(immutable)
  5. let has only block scope, while var can be global

Data Types

JavaScript is “dynamically typed”, meaning that there are data types, but variables are not bound to any of them.

Date types: Number, String, Boolean, Object, Function, Null, Undefined

  • Number - The number type serves both for integer and floating point numbers: 123, 12.22..

    Note: NaN belong to the type number but it’s not “normal” numbers. NaN represents an error.

  • String - A string may consist of only one character or many of them. Double and single quotes have no difference between them in JavaScript. E.g. ‘aba’, “I am a string.”

  • Boolean - The boolean type has only two values: true and false.

  • Null - A special value which is for unknown values.

    In JavaScript null is not a “reference to a non-existing object” or a “null pointer” like in some other languages.
    It’s just a special value which has the sense of “nothing”, “empty” or “value unknown”.

    Example: var age = null;
    The code above states that the age is unknown or empty for some reason.

  • Undefined - A special value which is for unassigned values. The meaning of undefined is “value is not assigned”.

Undefined 和 null 不是数据类型,而是特殊值

  • Function and Object will cover on the following section.

typeof Operator

returns the type of the argument. It’s useful when we want to process values of different types differently, or just want to make a quick check.
e.g. typeof “abc” - string

Comparisons

A comparison returns a value. The value is of the boolean type: true or false.

  • Greater/less than: a > b, a < b.
  • Greater/less than or equals: a >= b, a <= b.
  • Equality check is written as a == b (please note the double equation sign =. A single symbol a = b would mean an assignment).
  • Not equals. In maths the notation is ≠, in JavaScript it’s written as an assignment with an exclamation sign before it: a != b.

Note:
A regular equality check == has a problem. It cannot differ 0 from false:

1
2
0 == false  // true
“” == false // true

That’s because operands of different types are converted to a number by the equality operator ==. An empty string, just like false, becomes a zero.

1
Number(false) => 0, Number(“”) => 0

What to do if we’d like to differentiate 0 from false?

A strict equality operator === checks the equality without type conversion.
In other words, if a and b are of different types, then a===b immediately returns false without an attempt to convert them.

1
0 === false // false

Function

Functions are the main “building blocks” of the program. They allow the code to be called many times without repetition.

  1. Function Declaration
    9. JavaScript Basic-2019-4-14-9-38-10.png

The function keyword goes first, then goes the name of the function, then a list of parameters between the parentheses (empty in the example above) and finally the code of the function, also named “the function body”, between curly braces.

  1. Function Expression
    9. JavaScript Basic-2019-4-14-9-42-42.png

The meaning of these code samples is the same: “create a function and put it into the variable sayHi”.

Object

  1. Objects are used to store keyed collections of various data and more complex entities.

e.g. Dog object: age, name, color, breed attributes, and run() activity.

  1. How to create an instance of object

    1. using new keyword

      E.g.

      1
      2
      3
      var car = new Car();
      car.color = “red”;
      car.type = “suv”;
    2. using literal {} 字面量
      E.g. var car = { color: ‘red’, type: ‘suv’};

  2. Use . or [] to visit attributes.

    eg

    1
    2
    3
    t2.name; 
    t2['age'];
    t2['run'](); // function call
  3. example
    9. JavaScript Basic-2019-4-14-9-49-37.png

Primitive Type VS. Reference Type

  1. Numbers, Strings, Booleans, and the null and undefined types are primitive.
  2. Objects, and functions are reference types.

Difference:

  1. A primitive type has a fixed size in memory. For example, a number occupies eight bytes of memory, and a boolean value can be represented with only one bit. A reference type does not have a fixed size in memory.

  2. Primitive types are assigned/copied “as a whole value”, but reference types are stored and copied “by reference”.

  • A variable stores not the object itself, but its “address in memory”, in other words “a reference” to it.

  • When an object variable is copied.the reference is copied, the object is not duplicated.

Pass by reference and pass by value

  1. In JavaScript primitive types are copied and passed by value and objects are copied and passed by reference value.

9. JavaScript Basic-2019-4-14-10-5-3.png

  1. In terms of function:

    1. In Pass by Value, function is called by directly passing the value of the variable as the argument. Changing the argument inside the function doesn’t affect the variable passed from outside the function.

    2. In Pass by Reference, function is called by directly passing the reference/address of the variable as the argument. Changing the argument inside the function affect the variable passed from outside the function.

    3. example
      9. JavaScript Basic-2019-4-14-10-10-25.png

##
Hoisting 变量提升

Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution.

  1. Execution Context

    • Global execution context (GEC): This is the default execution context in which JS code start it’s execution when the file first loads in the browser.
    • Functional execution context (FEC): Functional execution context is defined as the context created by the execution of code inside a function. Each function has its own execution context.
  2. Execution context stack

    • Execution context stack is a stack data structure to store all the execution stacks created while executing the JS code.
    • Global execution context is present by default in execution context stack and it is at the bottom of the stack.
    • While executing global execution context code, if JS engines finds a function call, it creates functional execution context of that function and pushes that function execution context on top of execution context stack.
    • JS engine executes the function whose execution context is at the top of the execution context stack.
    • Once all the code of the function is executed, JS engines pop’s out that function’s execution context and start’s executing the function which is below it.
  3. JavaScript engine creates the execution context in the following two stages: Creation phase and Execution phase.

  • In creation phase, JS engine performs the following task:

    • creates the activation object or the variable object: activation object is a special object in JS which contain all the variables, function arguments and inner functions declarations information.
    • creates the scope chain: Once the activation object gets created, JS engine initializes the scope chain which is a list of all the variables objects inside which the current function exists. This also includes the variable object of global execution context. Scope chain also contains the current function variable object.
    • determines the value of this: After the scope chain, JavaScript engine initialize the value of ‘this’.
  • In the execution phase, JS engines will again scan through the function to update the variable object with the values of the variables and will execute the code.

[Notes] MySQL Basic

Posted on 2019-04-13 | Edited on 2019-04-16 | In CS
Symbols count in article: 12k | Reading time ≈ 11 mins.

Database and Database-Management System

What is Database?

A database is an organized collection of data.

What is Database-Management System?

A database-management system (DBMS) is a computer-software application that interacts with end-users, other applications, and the database itself to capture and analyze data. A general-purpose DBMS allows the definition, creation, querying, update, and administration of databases.

Why do we need Database?

We need to store some data set, a list of events with id, name, address, and date. What will you do? Text File? Excel?

  1. The size of list is large( > 1 million users).
  2. Add some constraints to some data, such as ID of each user should be different.
  3. Create relations between different kind of data, such as users saved some events before.
  4. Quickly retrieve data based on given condition, such as retrieve all events happened in San Francisco.
  5. Quickly update or delete data based on given condition, such as update all favorite events for a given user.
  6. Need access control on the data, meaning only authorized users can have access to the data set.
  7. Allow multiple users access(add, search, update, delete) the data set at the same time.

A DBMS allows you to fulfill all requirement above easily.

Create our database by using MAMP

MAMP stands for “My Apache, MySQL, and PHP”. MAMP is an integrated platform you can install on your machine which allows you to have access to a local MySQL server and its PHP server.

Click Preferences -> Ports. Make sure Apache Port is 8888 and MySQL port is 8889. Don’t worry about the Nginx port.

Start Server->open phpMyAdmin->create new project myproject->use utf8_general_ci as the collation

Relational DBMS

ER (entity-relationship) model:

  • Entity
  • Relation: connect different entities

MySQL

Basic Concepts

  • Table: a collection of attributions. Similar to what you’ve seen in an excel chart. Each column is an attribute of an entity, and each row is a record/instance of an entity.
  • Row: a single, implicitly structured data item in a table
  • Column: a set of data values of a particular simple type, one for each row of the table
  • Schema: blueprint of how table is constructed.

Project Structure

  • 8. MySQL Basic-2019-4-13-12-58-35.png
  • CREATE TABLE history (item_id, user_id, ,... FOREIGN KEY item_id REFERENCE item(item_id))

  • users - store user information.

User_id(primary key) password firstname lastname
1111 abcd Rick Sun
2222 efgh Matt Yan
  • items - store item information.
item_id(primary key) name rating url
abcd event1 5 www.example1.com
efgh event1 0 www.example2.com
  • category - store item-category relationship

It’s an implementation detail, we could save category in item table, but there will be more string join/split manipulations in our code, so let’s save them in a separate table.

item_id category
abcd party
efgh party
efgh sports

Set item_id and category both as Primary Key, to map multiple items to multiple items.

  • history - store user favorite history
User_id(foreign key) => user(user_id) item_id time
1111 abcd 01/01/2018
1111 efgh 01/02/2018
2222 efgh 01/03/2018

A few more concept:

  • Unique key: a key in a relational database that is unique for each record.
  • Primary key: Also a key that is unique for each record. Cannot be NULL and used as a unique identifier.
  • Foreign key: a key used to link two tables together. A FOREIGN KEY is a field (or collection of fields) in one table that refers to the PRIMARY KEY in another table.
  • Index: improves the speed of data retrieval operations on a database table at the cost of additional writes and storage space to maintain the index data structure. MySQL will create index on column which is declared as key.

SQL

  • SEQUEL (Structured English QUEry Language)

Structured Query Language is a programming language, which is used to communicate with DBMS. The standard language for relational DBMS.

Create tables in Java program

Connect to database from our Java program by JDBC

Just like our Java servlet classes. JDBC provides interfaces and classes for writing database operations. Technically speaking, JDBC (Java Database Connectivity) is a standard API that defines how Java programs access database management systems. Since JDBC is a standard specification, one Java program that uses the JDBC API can connect to any database management system (DBMS), as long as a driver exists for that particular DBMS.

  • download JDBC archive from http://dev.mysql.com/downloads/connector/j/
  • add the .jar file into your Eclipse lib. You can drag .jar file to WebContent/WEB-INF/lib directly, or copy that file and paste it (if it does not exist).
  • For DB related functions, please always use: import java.sql.xxx;

Create our db related package

  • create a new package named db, then add a new interface called DBConnection. Will add support to MySQL and MongoDB later.

  • Add the basic function signature

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    public interface DBConnection {
    /**
    * Close the connection.
    */
    public void close();

    /**
    * Insert the favorite items for a user.
    *
    * @param userId
    * @param itemIds
    */
    public void setFavoriteItems(String userId, List<String> itemIds);

    /**
    * Delete the favorite items for a user.
    *
    * @param userId
    * @param itemIds
    */
    public void unsetFavoriteItems(String userId, List<String> itemIds);

    /**
    * Get the favorite item id for a user.
    *
    * @param userId
    * @return itemIds
    */
    public Set<String> getFavoriteItemIds(String userId);

    /**
    * Get the favorite items for a user.
    *
    * @param userId
    * @return items
    */
    public Set<Item> getFavoriteItems(String userId);

    /**
    * Gets categories based on item id
    *
    * @param itemId
    * @return set of categories
    */
    public Set<String> getCategories(String itemId);

    /**
    * Search items near a geolocation and a term (optional).
    *
    * @param userId
    * @param lat
    * @param lon
    * @param term
    * (Nullable)
    * @return list of items
    */
    public List<Item> searchItems(double lat, double lon, String term);

    /**
    * Save item into db.
    *
    * @param item
    */
    public void saveItem(Item item);

    /**
    * Get full name of a user. (This is not needed for main course, just for demo
    * and extension).
    *
    * @param userId
    * @return full name of the user
    */
    public String getFullname(String userId);

    /**
    * Return whether the credential is correct. (This is not needed for main
    * course, just for demo and extension)
    *
    * @param userId
    * @param password
    * @return boolean
    */
    public boolean verifyLogin(String userId, String password);
    }
  • Create a concrete class DBConnectionFactory, this class is used to create db instance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class DBConnectionFactory {
    // This should change based on the pipeline.
    private static final String DEFAULT_DB = "mysql";

    public static DBConnection getConnection(String db) {
    switch (db) {
    case "mysql":
    // return new MySQLConnection();
    return null;
    case "mongodb":
    // return new MongoDBConnection();
    return null;
    default:
    throw new IllegalArgumentException("Invalid db: " + db);
    }
    }

    public static DBConnection getConnection() {
    return getConnection(DEFAULT_DB);
    }

    }

create MySQL version of DBConnection implementation

  • create another package db.mysql, which will only contains mysql version of DBConnection implementation. Then create MySQLDBUtil class in db.mysql package.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class MySQLDBUtil {
    private static final String HOSTNAME = "localhost";
    private static final String PORT_NUM = "8889"; // change it to your mysql port number
    public static final String DB_NAME = "myproject";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";
    public static final String URL = "jdbc:mysql://"
    + HOSTNAME + ":" + PORT_NUM + "/" + DB_NAME
    + "?user=" + USERNAME + "&password=" + PASSWORD
    + "&autoReconnect=true&serverTimezone=UTC";
    //jdbc:mysql://localhost:8889/myproject?user=root&password=root&autoReconnect=true&serverTimezone=UTC
    }
  • create a new class called MySQLTableCreation to automatically reset our tables in our database. So in the future, you can run this function every time when you think the data stored in you DB is messed up.

  • first let’s try to connect to MySQL through JDBC connection. Be careful, always use java.sql.* when eclipse ask you to import DB related packages.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class MySQLTableCreation {
    // Run this as Java application to reset db schema.
    public static void main(String[] args) {
    try {
    // This is java.sql.Connection. Not com.mysql.jdbc.Connection.
    Connection conn = null;

    // Step 1 Connect to MySQL.
    try {
    System.out.println("Connecting to " + MySQLDBUtil.URL);
    Class.forName("com.mysql.jdbc.Driver").getConstructor().newInstance();
    conn = DriverManager.getConnection(MySQLDBUtil.URL);
    } catch (SQLException e) {
    e.printStackTrace();
    }


    if (conn == null) {
    return;
    }

    System.out.println("Import is done successfully.");
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
  • Question: What does this do Class.forName(“com.mysql.jdbc.Driver”).newInstance()?
    Answer: Ensure the driver is registered. We use Class.forName("com.mysql.jdbc.Driver").getConstructor().newInstance(); to register jdbc.Driver class to DriverManager, then create an instance of it using conn = DriverManager.getConnection(MySQLDBUtil.URL);

    此处为反射机制的应用

  • after connect to MySQL, let’s try to drop old tables if they’re existed.
    Syntax: DROP TABLE IF EXISTS table_name;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // Step 2 Drop tables in case they exist.
    Statement stmt = conn.createStatement();
    String sql = "DROP TABLE IF EXISTS categories";
    stmt.executeUpdate(sql);

    sql = "DROP TABLE IF EXISTS history";
    stmt.executeUpdate(sql);

    sql = "DROP TABLE IF EXISTS items";
    stmt.executeUpdate(sql);

    sql = "DROP TABLE IF EXISTS users";
    stmt.executeUpdate(sql);
  • create 4 tables: User, Item, Category, History. Syntax:

    1
    2
    3
    4
    5
    6
    CREATE TABLE table_name (
    column1 datatype,
    column2 datatype,
    column3 datatype,
    ....
    );
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // Step 3 Create new tables
    sql = "CREATE TABLE items ("
    + "item_id VARCHAR(255) NOT NULL,"
    + "name VARCHAR(255),"
    + "rating FLOAT,"
    + "address VARCHAR(255),"
    + "image_url VARCHAR(255),"
    + "url VARCHAR(255),"
    + "distance FLOAT,"
    + "PRIMARY KEY (item_id))";
    stmt.executeUpdate(sql);

    sql = "CREATE TABLE categories ("
    + "item_id VARCHAR(255) NOT NULL,"
    + "category VARCHAR(255) NOT NULL,"
    + "PRIMARY KEY (item_id, category),"
    + "FOREIGN KEY (item_id) REFERENCES items(item_id))";
    stmt.executeUpdate(sql);

    sql = "CREATE TABLE users ("
    + "user_id VARCHAR(255) NOT NULL,"
    + "password VARCHAR(255) NOT NULL,"
    + "first_name VARCHAR(255),"
    + "last_name VARCHAR(255),"
    + "PRIMARY KEY (user_id))";
    stmt.executeUpdate(sql);

    sql = "CREATE TABLE history ("
    + "user_id VARCHAR(255) NOT NULL,"
    + "item_id VARCHAR(255) NOT NULL,"
    + "last_favor_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,"
    + "PRIMARY KEY (user_id, item_id),"
    + "FOREIGN KEY (item_id) REFERENCES items(item_id),"
    + "FOREIGN KEY (user_id) REFERENCES users(user_id))";
    stmt.executeUpdate(sql);

VarChar 指的是变长数组

last_favor_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 指的是如果没有给值,默认用当前时间填充

com.mysql.jdbc.Driver is deprecated, change to com.mysql.cj.jdbc.Driver

  • Add a fake user. We don’t have register function in our application, so let’s create a user in our database. Syntax:

    1
    2
    INSERT INTO table_name (column1, column2, column3, ...)
    VALUES (value1, value2, value3, ...);
    1
    2
    3
    4
    5
    // Step 4: insert data
    sql = "INSERT INTO users VALUES ("
    + "'1111', '3229c1097c00d497a0fd282d586be050', 'John', 'Smith')";
    System.out.println("Executing query: " + sql);
    stmt.executeUpdate(sql);

[Notes] CSS Basic 2

Posted on 2019-04-13 | Edited on 2019-04-12 | In CS
Symbols count in article: 5k | Reading time ≈ 5 mins.

Box Model

Introduction

  • The CSS box model is essentially a box that wraps around every HTML element. It consists of: margins, borders, padding, and the actual content.

Components

  • Content - The content of the box, where text and images appear
  • Padding - Clears an area around the content. The padding is transparent
  • Border - A border that goes around the padding and content
  • Margin - Clears an area outside the border. The margin is transparent
  • 7. CSS Basic 2-2019-4-12-18-45-25.png

Every element on a page is a rectangular box.

Types of box model

There are actually two types of box model, one is W3C standard, the other is IE model. Basically they all calculate the element width and height based on the content width, content height, padding and border, but their formula are different:

  1. W3C standard

    1
    2
    3
    4
    5
    6
    7
    8
    outer box (element space size)
    Element space width = content width + padding + border + margin
    Element space height = content height + padding + border + margin


    inner box (element size)
    Element width = content width + padding + border
    Element height = content height + padding + border
  2. IE box model

    1
    2
    3
    4
    outer box (element space size)
    Element space width = content width + margin
    Element space height = content height + margin
    (content width including padding and border)
  • 7. CSS Basic 2-2019-4-12-19-6-37.png
  • In order to make sure we apply the same box model to all browsers, CSS3 provides us with the new box-sizing property: box-sizing: content-box || border-box || inherit

Margin Collapsing

  • 7. CSS Basic 2-2019-4-12-19-35-16.png
  • 7. CSS Basic 2-2019-4-12-19-35-26.png

Layout

  • Definition: the “display” property

Block

  • A block-level element starts on a new line and stretches out to the left and right as far as it can.

Inline

  • An inline element can wrap some text inside a paragraph without disrupting the flow of that paragraph.

center element

  • margin: 0 auto; Centers the block elements to the center of the container.
  • text-align: center; Centers the text content.
  • display:flex; justify-content: center; Centers the items in a flex box horizontally.
  • display:flex; align-items: center; Centers the items in a flex box vertically.

Floating

Definition

  • The float CSS property specifies that an element should be placed along the left or right side of its container, allowing text and inline elements to wrap around it. The element is removed from the normal flow of the web page, though still remaining a part of the flow.

  • How floated elements are positioned: when an element is floated, it is taken out of the normal flow of the document (though still remaining part of it). It is shifted to the left, or right, until it touches the edge of its containing box, or another floated element.

Syntax

  • float: none|left|right|initial|inherit;

  • The float property can have one of the following values:

    • left - The element floats to the left of its container
    • right- The element floats to the right of its container
    • none - The element does not float (will be displayed just where it occurs in the text). This is default
    • inherit - The element inherits the float value of its parent

Important Facts

  1. float first

    • When a container has multiple elements, some of them are floating, some of them are not, remember to put all the floating elements in front of the non-floating ones! Browsers try to figure out the spacing for those floating ones first.

    • 7. CSS Basic 2-2019-4-12-20-18-51.png

  2. clear

    • The clear property specifies on which sides of an element the floating elements are not allowed to float.
    • .clear { clear: both; /* it can be left|right|both */ }
  3. inline-block

    • Floating works great, but as you see we need to apply the .clear to clear out the floating even for a block element. There is another way to achieve the floating effect, that is to use inline-block display.

    • similar to inline, inline-block allows multiple elements to layout on the same line, the beauty of it is that elements can automatically wrap around if the wrapper container is too small, and if you add a block element right after an inline-block element, we don’t need to use the ugly .clear fix.

    • 可实现左右排版

Position

static (default)

  • Default value, means the element is not positioned! A static element is said to be not positioned and an element with its position set to anything else is said to be positioned.

relative

  • The top, right, bottom and left properties of a relatively-positioned element will cause it to be adjusted away from its original position. Other content will not be adjusted to fit into any gap left by the element.
  • 7. CSS Basic 2-2019-4-12-20-47-22.png

absolute

  • The top, right, bottom and left properties of an absolute-positioned element will cause it to be positioned relatively to the nearest positioned ancestor.
  • 7. CSS Basic 2-2019-4-12-20-48-9.png

fixed

  • A fixed element is positioned relative to the viewport, which means it always stays in the same place even if the page is scrolled.

Examples

  • 7. CSS Basic 2-2019-4-12-20-53-11.png
  • 7. CSS Basic 2-2019-4-12-20-53-25.png
  • 7. CSS Basic 2-2019-4-12-20-53-36.png

  • Trick: 子容器绝对定位(相对于父容器), 父容器相对定位。

Z-index

Definition

  • The z-index property specifies the stack order of an element.

  • An element with greater stack order is always in front of an element with a lower stack order.

  • Note: z-index only works on positioned elements (position:absolute, position:relative, or position:fixed).
  • 7. CSS Basic 2-2019-4-12-21-21-49.png

  • Code http://jsbin.com/rafomem/20/edit?html,css,output

[Notes] TicketMaster API 2

Posted on 2019-04-12 | In CS
Symbols count in article: 7.8k | Reading time ≈ 7 mins.

TicketMaster API 2

Benifits of builder class


  • Easier to use because you don’t need to call a constructor with long parameter list
  • Easier to implement because you don’t need to provide constructors with different combinations of private fields.

TicketMasterAPI.java


Add getAddress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* get the Address from the JSONObject
* @param event
* @return A String of address
* @throws JSONException
*/
private String getAddress(JSONObject event) throws JSONException {
if (!event.isNull("_embedded")) {
JSONObject embedded = event.getJSONObject("_embedded");

if (!embedded.isNull("venues")) {
JSONArray venues = embedded.getJSONArray("venues");

for (int i = 0; i < venues.length(); ++i) {
JSONObject venue = venues.getJSONObject(i);

StringBuilder sb = new StringBuilder();

if (!venue.isNull("address")) {
JSONObject address = venue.getJSONObject("address");

if (!address.isNull("line1")) {
sb.append(address.getString("line1"));
}
if (!address.isNull("line2")) {
sb.append(" ");
sb.append(address.getString("line2"));
}
if (!address.isNull("line3")) {
sb.append(" ");
sb.append(address.getString("line3"));
}
}

if (!venue.isNull("city")) {
JSONObject city = venue.getJSONObject("city");

if (!city.isNull("name")) {
sb.append(" ");
sb.append(city.getString("name"));
}
}

if (!sb.toString().equals("")) {
return sb.toString();
}
}
}
}

return "";
}

Add getImageURL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// {"images": [{"url": "www.example.com/my_image.jpg"}, ...]}
/**
* Get the image URL from a JSONOBject
* @param event
* @return A String of image URL
* @throws JSONException
*/
private String getImageUrl(JSONObject event) throws JSONException {
if (!event.isNull("images")) {
JSONArray images = event.getJSONArray("images");

for (int i = 0; i < images.length(); ++i) {
JSONObject image = images.getJSONObject(i);

if (!image.isNull("url")) {
return image.getString("url");
}
}
}

return "";
}

Add getCategories

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// {"classifications" : [{"segment": {"name": "music"}}, ...]}
/**
* Get a set of categories from a JSONObject
* @param event
* @return A set of string
* @throws JSONException
*/
private Set<String> getCategories(JSONObject event) throws JSONException {
Set<String> categories = new HashSet<>();
if (!event.isNull("classifications")) {
JSONArray classifications = event.getJSONArray("classifications");
for (int i = 0; i < classifications.length(); i++) {
JSONObject classification = classifications.getJSONObject(i);
if (!classification.isNull("segment")) {
JSONObject segment = classification.getJSONObject("segment");
if (!segment.isNull("name")) {
String name = segment.getString("name");
categories.add(name);
}
}
}
}

return categories;
}

Add getItemList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Convert JSONArray to a list of item objects.
/**
* Convert JSONArray to a list of item objects
* @param events
* @return A list of Item objects
* @throws JSONException
*/
private List<Item> getItemList(JSONArray events) throws JSONException {
List<Item> itemList = new ArrayList<>();

for (int i = 0; i < events.length(); ++i) {
JSONObject event = events.getJSONObject(i);

ItemBuilder builder = new ItemBuilder();

if (!event.isNull("name")) {
builder.setName(event.getString("name"));
}

if (!event.isNull("id")) {
builder.setItemId(event.getString("id"));
}

if (!event.isNull("url")) {
builder.setUrl(event.getString("url"));
}

if (!event.isNull("rating")) {
builder.setRating(event.getDouble("rating"));
}

if (!event.isNull("distance")) {
builder.setDistance(event.getDouble("distance"));
}

builder.setCategories(getCategories(event));
builder.setAddress(getAddress(event));
builder.setImageUrl(getImageUrl(event));

itemList.add(builder.build());
}

return itemList;
}

Modify Search()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* Search the JSONArray results through TM API
* @param lat latitude
* @param lon longitude
* @param keyword keyword is optional
* @return JSONArray
*/
public List<Item> search(double lat, double lon, String keyword) {
List<Item> ret = new ArrayList<Item>();
if (keyword == null) keyword = DEFAULT_KEYWORD;
// translate keyword into URL-supported format
try {
keyword = java.net.URLEncoder.encode(keyword, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
// Get geoPoint
String geoHash = GeoHash.encodeGeohash(lat, lon, 8);
// Create query
// 50 is default search radius
String query = String.format("apikey=%s&geoPoint=%s&keyword=%s&radius=%s", API_KEY, geoHash, keyword, 50);
// Create URL
try {
// create a HTTP URL connection
HttpURLConnection connection = (HttpURLConnection) new URL(URL + "?" + query).openConnection();
// get the response code EG. 200/success, 404/fail
int responseCode = connection.getResponseCode();
// print res
System.out.println("\nSending \"GET\" request to URL : " + URL + "?" + query);
System.out.println("\nResponse Code: " + responseCode);
// check responseCode (Implement it later)
if (responseCode != 200) {

}
// read and write the response content
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
connection.disconnect();
// write the response to a JSON object
JSONObject obj = new JSONObject(response.toString());
// check the result
if (obj.isNull("_embedded")) {
return ret;
}
// get the events from the whole JSON and return the events field of it as a JSON Array.
JSONObject embedded = obj.getJSONObject("_embedded");
JSONArray events = embedded.getJSONArray("events");
ret = getItemList(events);
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}

Modify doGet() in searchItem Servlet


/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub

    double lat = Double.parseDouble(request.getParameter("lat"));
    double lon = Double.parseDouble(request.getParameter("lon"));

    String keyword = request.getParameter("term");
    TicketMasterAPI tmAPI = new TicketMasterAPI();
    List<Item> items = tmAPI.search(lat, lon, keyword);

    JSONArray array = new JSONArray();
    try {
        for (Item item : items) {
            JSONObject obj = item.toJSONObject();
            array.put(obj);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    RpcHelper.writeJSONArray(response, array);
}

Test result

  • test on http://localhost:8080/Jupiter/search?lat=37.38&lon=-122.08
  • 6. TicketMasterAPI 2-2019-4-12-15-47-9.png
123

Anda Luo

Notes of study, work and life
29 posts
2 categories
28 tags
GitHub E-Mail
© 2019 Anda Luo | 277k | 4:12
Powered by Hexo v3.8.0
|
Theme – NexT.Muse v7.0.1