commit 10011418f5d40c307a862dcd03ac4a2e40cfa3f2 Author: arul Date: Wed Jun 25 03:05:49 2025 +0530 Java Rest API with sqlite and simple web frontend diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..da17c5c --- /dev/null +++ b/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + com.test + java-project + jar + 1.0-SNAPSHOT + java-project + http://maven.apache.org + + + + + io.javalin + javalin + 5.6.3 + + + + com.fasterxml.jackson.core + jackson-databind + 2.15.0 + + + + org.xerial + sqlite-jdbc + 3.45.1.0 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 17 + 17 + + + + + diff --git a/purchase.db b/purchase.db new file mode 100644 index 0000000..dc8b710 Binary files /dev/null and b/purchase.db differ diff --git a/src/main/java/com/curlCommand.md b/src/main/java/com/curlCommand.md new file mode 100644 index 0000000..8c362e5 --- /dev/null +++ b/src/main/java/com/curlCommand.md @@ -0,0 +1,72 @@ +CURL COMMAND TUTORIAL + +--- + +### 1. + +```bash +curl http://localhost:7070/total +``` + +* **What it does:** + Sends an HTTP GET request to your API’s `/total` endpoint. +* **Purpose:** + Fetches the total profit so far from your server. +* **Response you got:** + + ```json + {"totalProfit":12000.0} + ``` + + This means the total sum of all purchased products recorded so far is ₹12,000. + +--- + +### 2. + +```bash +curl http://localhost:7070/turl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' +``` + +* **What you tried to do:** + Looks like you tried to send a POST request to `/purchase` to add a new product "Camera Drone" priced at 12000. + +* **Why it’s wrong / problematic:** + The syntax is incorrect and malformed. You are mixing a GET request to `/turl` with `-X POST http://localhost:7070/purchase`, which doesn’t make sense for `curl`. + The command has extra URL (`http://localhost:7070/purchase`) placed incorrectly after `-X POST`, which should only be followed by the HTTP method, not another URL. + +* **Correct form:** + + ```bash + curl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' + ``` + +* This correctly sends a POST request to `/purchase` endpoint with a JSON body specifying the product and price. + +--- + + +### Summary of key curl options used: + +* `curl [URL]` — by default, sends a GET request to the URL. + +* `-X POST` — explicitly sets HTTP method to POST (used to send data). + +* `-H "Content-Type: application/json"` — adds HTTP header specifying the request body is JSON. + +* `-d '{"product":"Camera Drone","price":12000}'` — the JSON data to send in the body of the POST request. + +--- + +If you want to test adding a new purchase and then check total, this sequence is correct: + +```bash +curl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' +curl http://localhost:7070/total +``` + +This will record the new product and then return the updated total profit. + +--- + +If you want, I can help you build some shell scripts or alias commands to make testing easier! Just say the word. diff --git a/src/main/java/com/test/App.java b/src/main/java/com/test/App.java new file mode 100644 index 0000000..87b416e --- /dev/null +++ b/src/main/java/com/test/App.java @@ -0,0 +1,114 @@ +package com.test; + +//Custom Classes Imported below +import com.test.PurchaseDAO; + +// Import necessary classes +import java.util.Map; +import java.util.HashMap; +import java.util.Scanner; + +import io.javalin.Javalin; +import io.javalin.http.Context; +import io.javalin.plugin.bundled.CorsPluginConfig; + +public class App { + + // Create a Constructor object to hold user and product info + Constructor construct = new Constructor("Arul", 24, "India, TN"); + + // Counter to track number of products purchased + int productIndex = 0; + + // Map to store product name as key and price as value + Map purchasedProductDetails = new HashMap<>(); + + // Scanner object to read input from console + Scanner scanner = new Scanner(System.in); + + PurchaseDAO db = new PurchaseDAO(); // Initializing DB + + // Method to record a purchase + public void recordPurchase(String product, double price) { + productIndex++; // Increment product count + construct.setProductName(product); // Set product name + construct.setProductPrice(price); // Set product price + construct.setTotalProductsPurchased(productIndex); // Update total + makeList(); // Add to local Map + db.insertPurchase(product, price); // Save to DB + } + + // Read user input from console (for CLI use) + public void printAndRead() { + System.out.println("[+] Enter the Product " + productIndex + " Name:"); + String productName = scanner.nextLine(); + System.out.println("[+] Enter price of the Product"); + Double productPrice = scanner.nextDouble(); + scanner.nextLine(); // Consume newline + recordPurchase(productName, productPrice); + } + + // Add product and price to Map + public void makeList() { + purchasedProductDetails.put(construct.getProductName(), construct.getProductPrice()); + } + + // Calculate total from DB and print + public void calculateTotalProfit() { + double sum = db.getTotalProfit(); // ✅ From DB + System.out.println("Total profit: ₹" + sum); + } + + // 🟢 Start API server + public void startApi() { + Javalin app = Javalin.create(config -> { + // ✅ Enable CORS for frontend origin + config.plugins.enableCors(cors -> { + cors.add(CorsPluginConfig::anyHost); // Or use allowHost("http://localhost:8080") + }); + }).start(7070); + + // Set JSON response type + app.before(ctx -> ctx.contentType("application/json")); + + // 🔸 POST /purchase → Record purchase + app.post("/purchase", ctx -> { + Map data = ctx.bodyAsClass(Map.class); + String product = data.get("product").toString(); + double price = Double.parseDouble(data.get("price").toString()); + recordPurchase(product, price); + ctx.status(200).result("Recorded: " + product + " for ₹" + price); + }); + + // 🔹 GET /total → Return total profit + app.get("/total", ctx -> { + double sum = db.getTotalProfit(); + ctx.json(Map.of( + "totalProfit", sum, + "customerName", construct.name, + "customerAge", construct.age, + "customerRegion", construct.region + )); + }); + } + + // 🚀 Main Method + public static void main(String[] args) { + App app = new App(); + app.startApi(); // Start server + + // Optional CLI (not needed for frontend, just for manual entry) + int flag = 0; + while (flag != 1) { + System.out.println("Proceed Adding Products? (Y/N)"); + String userInput = app.scanner.nextLine(); + if (userInput.equalsIgnoreCase("Y")) { + app.printAndRead(); + } else { + app.calculateTotalProfit(); + flag = 1; + app.scanner.close(); + } + } + } +} diff --git a/src/main/java/com/test/Constructor.java b/src/main/java/com/test/Constructor.java new file mode 100644 index 0000000..a432447 --- /dev/null +++ b/src/main/java/com/test/Constructor.java @@ -0,0 +1,62 @@ +package com.test; + +public class Constructor { + + // User info fields + String name; + int age; + String region; + + // Product-related fields (private for encapsulation) + private String purchaseProduct; + private double productPrice; + private double profitOfTheDay; + private int totalProductsPurchased; + + // Constructor to initialize user details + public Constructor(String name, int age, String region) { + this.age = age; + this.name = name; + this.region = region; + } + + // Getter for product name + public String getProductName() { + return purchaseProduct; + } + + // Getter for product price + public double getProductPrice() { + return productPrice; + } + + // Getter for profit of the day (not used yet in App) + public double getProfitOfTheDay() { + return profitOfTheDay; + } + + // Setter for product name + public void setProductName(String purchaseProduct) { + this.purchaseProduct = purchaseProduct; + } + + // Setter for product price + public void setProductPrice(double productPrice) { + this.productPrice = productPrice; + } + + // Setter for profit of the day + public void setProfitOfTheDay(double profitOfTheDay) { + this.profitOfTheDay = profitOfTheDay; + } + + // Setter for total products purchased + public void setTotalProductsPurchased(int totalProductsPurchased) { + this.totalProductsPurchased = totalProductsPurchased; + } + + // Getter for total products purchased + public int getTotalProductsPurchased() { + return totalProductsPurchased; + } +} diff --git a/src/main/java/com/test/PurchaseDAO.java b/src/main/java/com/test/PurchaseDAO.java new file mode 100644 index 0000000..000aa66 --- /dev/null +++ b/src/main/java/com/test/PurchaseDAO.java @@ -0,0 +1,57 @@ +package com.test; + +import java.sql.*; + +public class PurchaseDAO { + +private static final String DB_URL = "jdbc:sqlite:purchase.db"; + +public PurchaseDAO(){ + try(Connection conn = DriverManager.getConnection(DB_URL); + Statement stmt = conn.createStatement()) + { + String sql = "CREATE TABLE IF NOT EXISTS purchases (" + + "id INTEGER PRIMARY KEY AUTOINCREMENT," + + "product TEXT NOT NULL," + + "price REAL NOT NULL);"; + stmt.execute(sql); + + } + catch(SQLException e){ + e.printStackTrace(); + } +} + +public void insertPurchase(String product, double price){ + + String sql = "INSERT INTO purchases (product, price) VALUES (?,?)"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(sql)){ + + pstmt.setString(1, product); + pstmt.setDouble(2, price); + pstmt.executeUpdate(); + } + catch(SQLException e){ + e.printStackTrace(); + } +} + +public double getTotalProfit(){ + + double total = 0; + String sql = "SELECT SUM(price) FROM purchases"; + try(Connection conn = DriverManager.getConnection(DB_URL); + Statement stmt = conn.createStatement(); + ResultSet res = stmt.executeQuery(sql)){ + if(res.next()){ + total = res.getDouble(1); + } + } + catch(SQLException e){ + e.printStackTrace(); + } + return total; + } + +} diff --git a/src/main/java/com/test/frontend/app.js b/src/main/java/com/test/frontend/app.js new file mode 100644 index 0000000..8191fbf --- /dev/null +++ b/src/main/java/com/test/frontend/app.js @@ -0,0 +1,54 @@ +// Wait until the DOM (HTML page) is fully loaded +document.addEventListener("DOMContentLoaded", function () { + // Grab form elements and buttons + const form = document.getElementById("purchaseForm"); + const resultDiv = document.getElementById("result"); + const totalBtn = document.getElementById("totalBtn"); + + // 🟩 Handle form submission (Add new Purchase) + form.addEventListener("submit", function (event) { + event.preventDefault(); // Prevent page refresh + + // Get product and price values from form + const product = document.getElementById("product").value; + const price = parseFloat(document.getElementById("price").value); + + const data = { product: product, price: price }; + + // Send POST request to /purchase endpoint + fetch("http://localhost:7070/purchase", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then(function (response) { + return response.text(); // Expecting plain text response + }) + .then(function (data) { + resultDiv.innerText = data; // Show server response + form.reset(); // Clear form inputs + }) + .catch(function (error) { + resultDiv.innerText = "Error: " + error; // Show error if any + }); + }); + + // 🟦 Handle "Show Total Profit" button click (GET from /total) + totalBtn.addEventListener("click", function () { + fetch("http://localhost:7070/total") + .then((response) => response.json()) // Expect JSON response + .then((data) => { + // Format and display returned data + const output = ` +Name: ${data.customerName} +Age: ${data.customerAge} +Region: ${data.customerRegion} +Total Profit: ₹${data.totalProfit} + `; + resultDiv.innerText = output; + }) + .catch((error) => { + resultDiv.innerText = "Error: " + error; // Display fetch error + }); + }); +}); diff --git a/src/main/java/com/test/frontend/index.html b/src/main/java/com/test/frontend/index.html new file mode 100644 index 0000000..42eaaeb --- /dev/null +++ b/src/main/java/com/test/frontend/index.html @@ -0,0 +1,37 @@ + + + + + + Purchase Tracker + + + + + + + + + +
+

Product Purchase Tracker

+ + +
+ + + + + + + +
+ + + + + +
+
+ + diff --git a/src/main/java/com/test/frontend/styles.css b/src/main/java/com/test/frontend/styles.css new file mode 100644 index 0000000..073d532 --- /dev/null +++ b/src/main/java/com/test/frontend/styles.css @@ -0,0 +1,28 @@ +body { + font-family: sans-serif; + background-color: #f4f4f4; + padding: 20px; +} + +.container { + max-width: 500px; + margin: auto; + background: white; + padding: 20px; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* optional visual polish */ +} + +input, +button { + display: block; + width: 100%; + margin-top: 10px; + padding: 8px; + font-size: 1rem; +} + +#result { + margin-top: 20px; + white-space: pre-wrap; /* keep newlines and wrap long lines */ +} diff --git a/target/classes/com/curlCommand.md b/target/classes/com/curlCommand.md new file mode 100644 index 0000000..8c362e5 --- /dev/null +++ b/target/classes/com/curlCommand.md @@ -0,0 +1,72 @@ +CURL COMMAND TUTORIAL + +--- + +### 1. + +```bash +curl http://localhost:7070/total +``` + +* **What it does:** + Sends an HTTP GET request to your API’s `/total` endpoint. +* **Purpose:** + Fetches the total profit so far from your server. +* **Response you got:** + + ```json + {"totalProfit":12000.0} + ``` + + This means the total sum of all purchased products recorded so far is ₹12,000. + +--- + +### 2. + +```bash +curl http://localhost:7070/turl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' +``` + +* **What you tried to do:** + Looks like you tried to send a POST request to `/purchase` to add a new product "Camera Drone" priced at 12000. + +* **Why it’s wrong / problematic:** + The syntax is incorrect and malformed. You are mixing a GET request to `/turl` with `-X POST http://localhost:7070/purchase`, which doesn’t make sense for `curl`. + The command has extra URL (`http://localhost:7070/purchase`) placed incorrectly after `-X POST`, which should only be followed by the HTTP method, not another URL. + +* **Correct form:** + + ```bash + curl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' + ``` + +* This correctly sends a POST request to `/purchase` endpoint with a JSON body specifying the product and price. + +--- + + +### Summary of key curl options used: + +* `curl [URL]` — by default, sends a GET request to the URL. + +* `-X POST` — explicitly sets HTTP method to POST (used to send data). + +* `-H "Content-Type: application/json"` — adds HTTP header specifying the request body is JSON. + +* `-d '{"product":"Camera Drone","price":12000}'` — the JSON data to send in the body of the POST request. + +--- + +If you want to test adding a new purchase and then check total, this sequence is correct: + +```bash +curl -X POST http://localhost:7070/purchase -H "Content-Type: application/json" -d '{"product":"Camera Drone","price":12000}' +curl http://localhost:7070/total +``` + +This will record the new product and then return the updated total profit. + +--- + +If you want, I can help you build some shell scripts or alias commands to make testing easier! Just say the word. diff --git a/target/classes/com/test/App.class b/target/classes/com/test/App.class new file mode 100644 index 0000000..7270abb Binary files /dev/null and b/target/classes/com/test/App.class differ diff --git a/target/classes/com/test/Constructor.class b/target/classes/com/test/Constructor.class new file mode 100644 index 0000000..056e71e Binary files /dev/null and b/target/classes/com/test/Constructor.class differ diff --git a/target/classes/com/test/PurchaseDAO.class b/target/classes/com/test/PurchaseDAO.class new file mode 100644 index 0000000..ab8ad59 Binary files /dev/null and b/target/classes/com/test/PurchaseDAO.class differ diff --git a/target/classes/com/test/frontend/app.js b/target/classes/com/test/frontend/app.js new file mode 100644 index 0000000..8191fbf --- /dev/null +++ b/target/classes/com/test/frontend/app.js @@ -0,0 +1,54 @@ +// Wait until the DOM (HTML page) is fully loaded +document.addEventListener("DOMContentLoaded", function () { + // Grab form elements and buttons + const form = document.getElementById("purchaseForm"); + const resultDiv = document.getElementById("result"); + const totalBtn = document.getElementById("totalBtn"); + + // 🟩 Handle form submission (Add new Purchase) + form.addEventListener("submit", function (event) { + event.preventDefault(); // Prevent page refresh + + // Get product and price values from form + const product = document.getElementById("product").value; + const price = parseFloat(document.getElementById("price").value); + + const data = { product: product, price: price }; + + // Send POST request to /purchase endpoint + fetch("http://localhost:7070/purchase", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then(function (response) { + return response.text(); // Expecting plain text response + }) + .then(function (data) { + resultDiv.innerText = data; // Show server response + form.reset(); // Clear form inputs + }) + .catch(function (error) { + resultDiv.innerText = "Error: " + error; // Show error if any + }); + }); + + // 🟦 Handle "Show Total Profit" button click (GET from /total) + totalBtn.addEventListener("click", function () { + fetch("http://localhost:7070/total") + .then((response) => response.json()) // Expect JSON response + .then((data) => { + // Format and display returned data + const output = ` +Name: ${data.customerName} +Age: ${data.customerAge} +Region: ${data.customerRegion} +Total Profit: ₹${data.totalProfit} + `; + resultDiv.innerText = output; + }) + .catch((error) => { + resultDiv.innerText = "Error: " + error; // Display fetch error + }); + }); +}); diff --git a/target/classes/com/test/frontend/index.html b/target/classes/com/test/frontend/index.html new file mode 100644 index 0000000..42eaaeb --- /dev/null +++ b/target/classes/com/test/frontend/index.html @@ -0,0 +1,37 @@ + + + + + + Purchase Tracker + + + + + + + + + +
+

Product Purchase Tracker

+ + +
+ + + + + + + +
+ + + + + +
+
+ + diff --git a/target/classes/com/test/frontend/styles.css b/target/classes/com/test/frontend/styles.css new file mode 100644 index 0000000..073d532 --- /dev/null +++ b/target/classes/com/test/frontend/styles.css @@ -0,0 +1,28 @@ +body { + font-family: sans-serif; + background-color: #f4f4f4; + padding: 20px; +} + +.container { + max-width: 500px; + margin: auto; + background: white; + padding: 20px; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* optional visual polish */ +} + +input, +button { + display: block; + width: 100%; + margin-top: 10px; + padding: 8px; + font-size: 1rem; +} + +#result { + margin-top: 20px; + white-space: pre-wrap; /* keep newlines and wrap long lines */ +} diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..d8516fd --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,3 @@ +com/test/PurchaseDAO.class +com/test/App.class +com/test/Constructor.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..3b5afb6 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,3 @@ +/home/arul/apiServerProject/java-project/src/main/java/com/test/App.java +/home/arul/apiServerProject/java-project/src/main/java/com/test/Constructor.java +/home/arul/apiServerProject/java-project/src/main/java/com/test/PurchaseDAO.java