- Timestamp:
- 01/10/25 19:07:51 (5 days ago)
- Branches:
- master
- Children:
- cd64b06
- Parents:
- 53bad7e
- Location:
- backend/GlobeGuru-backend
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
backend/GlobeGuru-backend/src/main/java/DatabaseUtil.java
r53bad7e r1c51912 3 3 import java.time.LocalDateTime; 4 4 import java.util.ArrayList; 5 import java.util.HashMap; 5 6 import java.util.List; 7 import java.util.Map; 6 8 7 9 public class DatabaseUtil { … … 29 31 "hotelName TEXT, " + 30 32 "country TEXT, " + 31 "price REAL, " +32 33 "dateRange TEXT, " + 33 34 "numberOfPeople INTEGER, " + … … 35 36 "newPrice REAL DEFAULT 0)" 36 37 ); 37 38 38 PreparedStatement stmt3 = conn.prepareStatement( 39 39 "CREATE TABLE IF NOT EXISTS savedOptions (" + 40 "userId INTEGER, " + 41 "optionId INTEGER, " + 42 "FOREIGN KEY(userId) REFERENCES users(id), " + 43 "FOREIGN KEY(optionId) REFERENCES options(id), " + 44 "UNIQUE(userId, optionId))" 40 "userId INTEGER," + 41 "detailId INTEGER," + 42 "FOREIGN KEY(userId) REFERENCES users(id)," + 43 "FOREIGN KEY(detailId) REFERENCES optionDetails(id)," + 44 "UNIQUE(userId, detailId))" 45 ); 46 PreparedStatement stmt4 = conn.prepareStatement( 47 "CREATE TABLE IF NOT EXISTS optionDetails (" + 48 "id INTEGER PRIMARY KEY AUTOINCREMENT, " + 49 "optionId INTEGER NOT NULL, " + 50 "type TEXT, " + 51 "board TEXT, " + 52 "amenities TEXT, " + 53 "price REAL," + 54 "FOREIGN KEY(optionId) REFERENCES options(id))" 45 55 )) { 56 46 57 stmt1.executeUpdate(); 47 58 stmt2.executeUpdate(); 48 59 stmt3.executeUpdate(); 60 stmt4.executeUpdate(); 49 61 } 50 62 } … … 136 148 public static List<Option> queryOptions(String destination, String dateQuery, int numPeople, boolean dateFlag) throws SQLException { 137 149 List<Option> options = new ArrayList<>(); 138 String sql = "SELECT * FROM options WHERE (country LIKE ? OR hotelName LIKE ?)"; 139 System.out.println(dateQuery); 150 String sql = "SELECT o.*, od.id AS detail_id, od.type, od.board, od.amenities, od.price AS detail_price " + 151 "FROM options o " + 152 "LEFT JOIN optionDetails od ON o.id = od.optionId " + 153 "WHERE (o.country LIKE ? OR o.hotelName LIKE ?)"; 154 140 155 if (dateQuery != null && !dateQuery.isEmpty() && !dateFlag) { 141 sql += (" AND dateRange = ?"); 142 } //append date 143 if (dateFlag) { //search only from dates 144 sql += " AND dateRange LIKE ?"; 145 } 146 if(numPeople != 0) { //with number of people 147 sql += " AND numberOfPeople = ?"; 148 } 149 150 System.out.println("Searching for dest:" + destination + "\n" + sql); 156 sql += " AND o.dateRange = ?"; 157 } 158 if (dateFlag) { 159 sql += " AND o.dateRange LIKE ?"; 160 } 161 if (numPeople != 0) { 162 sql += " AND o.numberOfPeople = ?"; 163 } 164 151 165 try (Connection conn = getConnection(); 152 166 PreparedStatement stmt = conn.prepareStatement(sql)) { 153 167 stmt.setString(1, "%" + destination + "%"); 154 168 stmt.setString(2, "%" + destination + "%"); 169 int paramIndex = 3; 155 170 if (dateQuery != null && !dateQuery.isEmpty() && !dateFlag) { 156 stmt.setString( 3, dateQuery);171 stmt.setString(paramIndex++, dateQuery); 157 172 } 158 173 if (dateFlag) { 159 stmt.setString(3, dateQuery + "%"); 160 } 161 if(numPeople != 0) { 162 stmt.setInt(4, numPeople); 163 } 174 stmt.setString(paramIndex++, dateQuery + "%"); 175 } 176 if (numPeople != 0) { 177 stmt.setInt(paramIndex, numPeople); 178 } 179 164 180 try (ResultSet rs = stmt.executeQuery()) { 165 181 while (rs.next()) { 166 182 Option option = new Option(); 167 option.setId(rs.getInt(" id"));183 option.setId(rs.getInt("detail_id")); 168 184 option.setLink(rs.getString("link")); 169 185 option.setImgSrc(rs.getString("imgSrc")); 170 186 option.setHotelName(rs.getString("hotelName")); 171 187 option.setCountry(rs.getString("country")); 172 option.setPrice(rs.getFloat("price"));173 188 option.setDateRange(rs.getString("dateRange")); 174 189 option.setNumPeople(rs.getInt("numberOfPeople")); 190 option.setType(rs.getString("type")); 191 option.setBoard(rs.getString("board")); 192 option.setAmenities(rs.getString("amenities")); 193 option.setPrice(rs.getFloat("detail_price")); 175 194 options.add(option); 176 195 } 177 196 } 178 197 } 179 System.out.println("Found " + options.size()); 198 199 System.out.println("Found " + options.size() + " options"); 180 200 return options; 181 201 } 182 202 183 public static boolean saveFavoriteOption(int userId, int optionId) throws SQLException { 184 String sql = "INSERT INTO savedOptions (userId, optionId) VALUES (?, ?) ON CONFLICT DO NOTHING"; 203 204 public static boolean saveFavoriteOption(int userId, int detailId) throws SQLException { 205 String sql = "INSERT INTO savedOptions (userId, detailId) VALUES (?, ?) ON CONFLICT DO NOTHING"; 185 206 try (Connection conn = getConnection(); 186 207 PreparedStatement stmt = conn.prepareStatement(sql)) { 187 208 stmt.setInt(1, userId); 188 stmt.setInt(2, optionId);209 stmt.setInt(2, detailId); 189 210 return stmt.executeUpdate() > 0; 190 211 } … … 192 213 193 214 194 public static boolean removeFavoriteOption(int userId, int optionId) throws SQLException { 195 String sql = "DELETE FROM savedOptions WHERE userId = ? AND optionId = ?"; 215 216 public static boolean removeFavoriteOption(int userId, int detailId) throws SQLException { 217 String sql = "DELETE FROM savedOptions WHERE userId = ? AND detailId = ?"; 196 218 try (Connection conn = getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) { 197 219 stmt.setInt(1, userId); 198 stmt.setInt(2, optionId);220 stmt.setInt(2, detailId); 199 221 return stmt.executeUpdate() > 0; 200 222 } 201 223 } 224 202 225 203 226 public static List<Option> getSavedTripsByUser(int userId) throws SQLException { 204 227 List<Option> savedTrips = new ArrayList<>(); 205 String sql = "SELECT options.* FROM savedOptions JOIN options ON savedOptions.optionId = options.id WHERE savedOptions.userId = ?"; 228 String sql = "SELECT od.id AS detail_id, o.*, od.* FROM savedOptions so " + 229 "JOIN optionDetails od ON so.detailId = od.id " + 230 "JOIN options o ON od.optionId = o.id " + 231 "WHERE so.userId = ?"; 206 232 try (Connection conn = getConnection(); 207 233 PreparedStatement stmt = conn.prepareStatement(sql)) { … … 210 236 while (rs.next()) { 211 237 Option option = new Option(); 212 option.setId(rs.getInt(" id"));238 option.setId(rs.getInt("detail_id")); 213 239 option.setLink(rs.getString("link")); 214 240 option.setImgSrc(rs.getString("imgSrc")); 215 241 option.setHotelName(rs.getString("hotelName")); 216 242 option.setCountry(rs.getString("country")); 243 option.setDateRange(rs.getString("dateRange")); 244 option.setNumPeople(rs.getInt("numberOfPeople")); 245 option.setType(rs.getString("type")); 246 option.setBoard(rs.getString("board")); 247 option.setAmenities(rs.getString("amenities")); 217 248 option.setPrice(rs.getFloat("price")); 218 option.setDateRange(rs.getString("dateRange"));219 option.setPriceChanged(rs.getBoolean("isPriceChanged"));220 option.setNewPrice(rs.getInt("newPrice"));221 249 savedTrips.add(option); 222 250 } … … 225 253 return savedTrips; 226 254 } 255 227 256 228 257 … … 274 303 } 275 304 276 public static void saveOptionToDatabase(Option option) { 277 String sql = "INSERT INTO options (link, imgSrc, hotelName, country, price, dateRange,numberOfPeople, isPriceChanged, newPrice) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; 305 public static int saveOptionToDatabase(Option option) { 306 String sql = "INSERT INTO options (link, imgSrc, hotelName, country, dateRange,numberOfPeople, isPriceChanged, newPrice) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; 307 int id = 0; 278 308 try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db"); 279 309 PreparedStatement stmt = conn.prepareStatement(sql)) { … … 282 312 stmt.setString(3, option.getHotelName()); 283 313 stmt.setString(4, option.getCountry()); 284 stmt.setFloat(5, option.getPrice()); 285 stmt.setString(6, option.getDateRange()); 286 stmt.setInt(7,option.getNumPeople()); 287 stmt.setBoolean(8, option.isPriceChanged()); 288 stmt.setFloat(9, option.getNewPrice()); 314 stmt.setString(5, option.getDateRange()); 315 stmt.setInt(6,option.getNumPeople()); 316 stmt.setBoolean(7, option.isPriceChanged()); 317 stmt.setFloat(8, option.getNewPrice()); 318 stmt.executeUpdate(); 319 try(ResultSet genKey = stmt.getGeneratedKeys()){ 320 if(genKey.next()){ 321 id = genKey.getInt(1); 322 } 323 } 324 } catch (SQLException e) { 325 e.printStackTrace(); 326 } 327 return id; 328 } 329 330 public static void saveOptionDetails(int id, String type, String board, String amenity, float price) { 331 String sql = "INSERT INTO optionDetails (optionId, type, board, amenities, price) VALUES (?, ?, ?, ?, ?)"; 332 333 try (Connection conn = getConnection(); 334 PreparedStatement stmt = conn.prepareStatement(sql)) { 335 stmt.setInt(1, id); 336 stmt.setString(2, type); 337 stmt.setString(3, board); 338 stmt.setString(4, amenity); 339 stmt.setFloat(5, price); 289 340 stmt.executeUpdate(); 290 341 } catch (SQLException e) { … … 292 343 } 293 344 } 294 295 345 296 346 public static void dropOptions() throws SQLException { … … 350 400 } 351 401 402 public static List<Option> fetchAllOptions() { 403 List<Option> options = new ArrayList<>(); 404 String sql = "SELECT * FROM options"; 405 406 try (Connection conn = DriverManager.getConnection("jdbc:sqlite:globe_guru.db"); 407 PreparedStatement stmt = conn.prepareStatement(sql); 408 ResultSet rs = stmt.executeQuery()) { 409 while (rs.next()) { 410 Option option = new Option(); 411 option.setId(rs.getInt("id")); 412 option.setLink(rs.getString("link")); 413 option.setImgSrc(rs.getString("imgSrc")); 414 option.setHotelName(rs.getString("hotelName")); 415 option.setCountry(rs.getString("country")); 416 option.setPrice(rs.getFloat("price")); 417 option.setDateRange(rs.getString("dateRange")); 418 option.setPriceChanged(rs.getBoolean("isPriceChanged")); 419 option.setNewPrice(rs.getInt("newPrice")); 420 option.setNumPeople(rs.getInt("numberOfPeople")); 421 options.add(option); 422 } 423 424 } catch (SQLException e) { 425 e.printStackTrace(); 426 } 427 return options; 428 } 429 352 430 } -
backend/GlobeGuru-backend/src/main/java/Option.java
r53bad7e r1c51912 8 8 private String link; 9 9 private String imgSrc; 10 private String type; 11 private String board; 12 private String amenities; 13 10 14 private int numPeople; 11 15 //Price changing … … 26 30 } 27 31 32 public String getType() { 33 return type; 34 } 35 36 public void setType(String type) { 37 this.type = type; 38 } 39 40 public String getBoard() { 41 return board; 42 } 43 44 public void setBoard(String board) { 45 this.board = board; 46 } 47 48 public String getAmenities() { 49 return amenities; 50 } 51 52 public void setAmenities(String amenities) { 53 this.amenities = amenities; 54 } 55 28 56 public boolean isEmpty(){ 29 return (hotelName == null || country == null || price == 0 ||link == null || imgSrc == null);57 return (hotelName == null || country == null || link == null || imgSrc == null); 30 58 } 31 59 public String getHotelName() { -
backend/GlobeGuru-backend/src/main/java/ScraperThread.java
r53bad7e r1c51912 39 39 } 40 40 41 p rivateWebDriver driver;41 public WebDriver driver; 42 42 43 43 private void initializeWebDriver() { … … 70 70 wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("div.sodrzina"))); 71 71 break; 72 default:73 System.out.println("URL not recognized for waiting condition.");74 // Handle other URLs if needed75 72 } 76 73 … … 92 89 Option existingOption = DatabaseUtil.findOption(option); 93 90 if (existingOption != null) { 94 if (existingOption.equals(option) || existingOption.getPrice() != option.getPrice()) {91 if (existingOption.equals(option)) { 95 92 option.setPriceChanged(true); 96 93 option.setNewPrice(option.getPrice()); … … 112 109 if (parentDiv != null) { 113 110 childDivs = parentDiv.select("div.destinacija"); 114 System.out.println(childDivs.size());115 111 childDivs.removeIf(div -> div.attr("style").contains("display:none") || div.attr("style").contains("display: none")); 116 112 System.out.println("Filtered childDivs size: " + childDivs.size()); … … 119 115 Option newOption = optionParser(data,numPeople); 120 116 if (newOption != null) { 121 Option existingOption = DatabaseUtil.findOption(newOption); 122 if (existingOption != null) { 123 if (existingOption.equals(newOption) || existingOption.getPrice() != newOption.getPrice()) { 124 newOption.setPriceChanged(true); 125 newOption.setNewPrice(newOption.getPrice()); 126 } 127 DatabaseUtil.updateOptionInDatabase(newOption); 128 } else if (optionSet.add(newOption)) { 117 if (optionSet.add(newOption)) { 129 118 uniqueOptions.add(newOption); 130 DatabaseUtil.saveOptionToDatabase(newOption); 119 120 newOption.setId(DatabaseUtil.saveOptionToDatabase(newOption)); 121 scrapeOptionInfo(newOption); 131 122 System.out.println("Parsed " + newOption); 132 123 } … … 142 133 } 143 134 } 144 145 146 147 private Option optionParser(String data, int numPeople) { 135 private void scrapeOptionInfo(Option option) { 136 String url = option.getLink(); 137 if(url.contains("magelantravel.mk")) { 138 System.out.println("Scraping info for " + option.getHotelName()); 139 String[] dates = option.getDateRange().split(" - "); 140 url += "&checkin=" + dates[0] + "&checkout=" + dates[1] + "&adult=" + option.getNumPeople(); 141 142 driver.get(url); 143 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } //data fetch 144 String pageSource = driver.getPageSource(); 145 Document doc = Jsoup.parse(pageSource); 146 Elements roomOptions = doc.select(".tblroom > tbody > tr"); 147 for (Element roomOption : roomOptions) { 148 String type = roomOption.select("a.tblroom-type").text(); 149 150 String board = roomOption.select(".rezervacija-objekt").text(); 151 if(board.length() > 2){ 152 board = board.substring(0,2); 153 } 154 if(board.isEmpty() || type.isEmpty()){ 155 continue; 156 } 157 Elements amenityElement = roomOption.select(".objekt-opis"); 158 String amenity = (amenityElement != null ? amenityElement.text() : ""); 159 System.out.println(amenity + " " + board + " " + type ); 160 String priceText = roomOption.select(".tbl-cena").text().replace("€", "").trim(); 161 float price; 162 if (!priceText.isEmpty()) { 163 price = Float.parseFloat(priceText); 164 }else continue; 165 166 DatabaseUtil.saveOptionDetails(option.getId(), type,board,amenity, price); 167 } 168 } 169 } 170 private Option optionParser(String data, int numPeople){ 148 171 Document doc = Jsoup.parse(data); 149 172 Option created = new Option(); … … 162 185 } 163 186 if (created.isEmpty()) { 164 System.out.println(created);165 187 return null; 166 188 } 189 //scrapeOptionInfo(created); 167 190 return created; 168 191 } … … 181 204 Element countryElement = doc.selectFirst("l.ponuda-lokacija"); 182 205 created.setCountry(countryElement != null ? countryElement.text() : null); 183 Element priceElement = doc.selectFirst("div.ponuda-cena");206 //Element priceElement = doc.selectFirst("div.ponuda-cena"); 184 207 Element dateElement = doc.selectFirst("l.ponuda-opis.termin"); 185 208 created.setDateRange(dateElement != null ? dateElement.text() : null); 186 float price = Float.parseFloat(priceElement != null ? priceElement.text().replaceAll("[^\\d.]", "") : "0");187 created.setPrice(price); 209 /*float price = Float.parseFloat(priceElement != null ? priceElement.text().replaceAll("[^\\d.]", "") : "0"); 210 created.setPrice(price);*/ 188 211 return created; 189 212 } … … 198 221 String country = countryP.text().replaceAll("leto hoteli", ""); 199 222 created.setCountry(country); 200 Element priceElem = doc.selectFirst("span.hotel-price");223 /*Element priceElem = doc.selectFirst("span.hotel-price"); 201 224 String priceText = priceElem.text(); 202 225 float price = 0; … … 204 227 price = Float.parseFloat(priceText.replace("€", "")); 205 228 } 206 created.setPrice(price); 229 created.setPrice(price);*/ 207 230 String[] queryParams = link.split("[?&]"); 208 231 String startDateStr = null; -
backend/GlobeGuru-backend/src/main/resources/URLsJSON.json
r53bad7e r1c51912 2 2 "agencyurls": 3 3 [ 4 "https://magelantravel.mk/" ,5 "https://booking.escapetravel.mk/" 4 "https://magelantravel.mk/" 5 6 6 ] 7 7 } -
backend/GlobeGuru-backend/target/classes/URLsJSON.json
r53bad7e r1c51912 2 2 "agencyurls": 3 3 [ 4 "https://magelantravel.mk/" ,5 "https://booking.escapetravel.mk/" 4 "https://magelantravel.mk/" 5 6 6 ] 7 7 } -
backend/GlobeGuru-backend/target/classes/lastUpdateTime.json
r53bad7e r1c51912 1 1 { 2 "lastUpdateTime" : "2025-01- 09T19:56:28.178946100"2 "lastUpdateTime" : "2025-01-10T18:31:22.019011800" 3 3 }
Note:
See TracChangeset
for help on using the changeset viewer.