diff --git a/README.md b/README.md
index d20aaf9..5719434 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+[](https://classroom.github.com/a/339Lr3BJ)
### How the tests work (and Docker requirement)
This project ships with an end‑to‑end CLI integration test suite that uses Testcontainers to spin up a temporary MySQL database.
@@ -111,3 +112,38 @@ VG (extra credit)
- Create a `DataSource` once at startup (using the connection settings above) and inject it into your repositories by constructor injection. For a minimal setup, you can implement a small `SimpleDriverManagerDataSource` that delegates to `DriverManager.getConnection(...)`. This keeps repositories independent of configuration and lets you upgrade to a connection pool (e.g., HikariCP) later without changing repository code.
- Define `AccountRepository` and `MoonMissionRepository` and provide JDBC implementations.
- In `Main`, resolve configuration, construct the `DataSource`, instantiate repositories.
+
+
+# Databas-JDBC Laboration (3)
+
+Detta projekt är en Java-applikation som använder JDBC för att interagera med en MySQL-databas. Denna applikation hanterar konton och rymduppdrag.
+
+## Funktioner
+
+- Logga in med användarnamn och lösenord.
+- Lista alla rymduppdrag.
+- Hämta ett specifikt uppdrag baserat på mission_id.
+- Räkna antal uppdrag för ett specifikt år.
+- Skapa nytt konto.
+- Uppdatera lösenord för ett konto.
+- Ta bort ett konto.
+
+## Användning
+
+1. Starta programmet via IntelliJ eller kommandoraden.
+2. Logga in med ett existerande konto (eller skapa ett nytt via menyn).
+3. Följ menyn för att utföra olika operationer på databasen.
+
+## Olika teknologier
+
+- Java 25
+- JDBC
+- MySQL
+- Maven
+
+## Testning
+
+I detta projekt används Maven för att köra integrationstester. Kör tester med:
+
+```bash
+./mvnw clean verify
diff --git a/pom.xml b/pom.xml
index 002ff66..4e39704 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,6 +16,7 @@
5.20.0
+
com.mysql
mysql-connector-j
@@ -46,11 +47,13 @@
1.21.3
test
+
org.testcontainers
mysql
1.21.3
+
diff --git a/src/main/java/com/example/Main.java b/src/main/java/com/example/Main.java
index 6dc6fbd..597a044 100644
--- a/src/main/java/com/example/Main.java
+++ b/src/main/java/com/example/Main.java
@@ -2,56 +2,201 @@
import java.sql.Connection;
import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
+import java.util.Scanner;
public class Main {
- static void main(String[] args) {
+ public static void main(String[] args) {
+ // Om vi kör i DevMode: Starta testdatabasen, via Docker/Testcontainers.
if (isDevMode(args)) {
DevDatabaseInitializer.start();
}
+ // Startar programlogiken.
new Main().run();
}
public void run() {
- // Resolve DB settings with precedence: System properties -> Environment variables
+ // Hämtar databasinställningar.
String jdbcUrl = resolveConfig("APP_JDBC_URL", "APP_JDBC_URL");
String dbUser = resolveConfig("APP_DB_USER", "APP_DB_USER");
String dbPass = resolveConfig("APP_DB_PASS", "APP_DB_PASS");
+ // Om någon databasinställning skulle saknas, så avbryts programmet.
if (jdbcUrl == null || dbUser == null || dbPass == null) {
throw new IllegalStateException(
- "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS " +
- "as system properties (-Dkey=value) or environment variables.");
+ "Missing DB configuration. Provide APP_JDBC_URL, APP_DB_USER, APP_DB_PASS as system properties (-Dkey=value) or environment variables."
+ );
}
+ // Skapar anslutning till databasen.
try (Connection connection = DriverManager.getConnection(jdbcUrl, dbUser, dbPass)) {
+ // För att läsa input av användaren i terminalen, så används Scanner.
+ Scanner scanner = new Scanner(System.in);
+
+ // Loggar in med användarnamn och lösenord.
+ System.out.print("Username: ");
+ String username = scanner.nextLine();
+ System.out.print("Password: ");
+ String password = scanner.nextLine();
+
+ // En SQL-fråga för att kontrollera användarnamn och lösenord.
+ String loginSql = "SELECT * FROM account WHERE name = ? AND password = ?";
+ try (PreparedStatement stmt = connection.prepareStatement(loginSql)) {
+ stmt.setString(1, username);
+ stmt.setString(2, password);
+ try (ResultSet rs = stmt.executeQuery()) {
+ // Om ingen rad hittas, så misslyckas inloggningen.
+ if (!rs.next()) {
+ System.out.println("Invalid username or password");
+ return; // Avslutar run() om inloggningen misslyckas.
+ }
+ }
+ }
+ // Fortsätter programmet efter lyckad inloggning.
+ System.out.println("Login successful!");
+
+ // En meny-loop.
+ boolean running = true;
+ while (running) {
+ System.out.println("\nMenu:");
+ System.out.println("1) List moon missions");
+ System.out.println("2) Get moon mission by ID");
+ System.out.println("3) Count missions for a year");
+ System.out.println("4) Create account");
+ System.out.println("5) Update account password");
+ System.out.println("6) Delete account");
+ System.out.println("0) Exit");
+ System.out.print("Choose an option: ");
+
+ // Läser in användarens menyval.
+ switch (scanner.nextLine()) {
+ case "1" -> listMissions(connection);
+ case "2" -> getMissionById(connection, scanner);
+ case "3" -> countMissionsByYear(connection, scanner);
+ case "4" -> createAccount(connection, scanner);
+ case "5" -> updatePassword(connection, scanner);
+ case "6" -> deleteAccount(connection, scanner);
+ case "0" -> {
+ running = false;
+ System.out.println("Exiting program...");
+ }
+ default -> System.out.println("Invalid option.");
+ }
+ }
+
} catch (SQLException e) {
+ // Om något skulle gå fel med databasen.
throw new RuntimeException(e);
}
- //Todo: Starting point for your code
}
- /**
- * Determines if the application is running in development mode based on system properties,
- * environment variables, or command-line arguments.
- *
- * @param args an array of command-line arguments
- * @return {@code true} if the application is in development mode; {@code false} otherwise
- */
+ // Listar alla rymduppdrag.
+ private void listMissions(Connection conn) throws SQLException {
+ try (PreparedStatement stmt = conn.prepareStatement("SELECT spacecraft FROM moon_mission");
+ ResultSet rs = stmt.executeQuery()) {
+ System.out.println("Moon missions:");
+ while (rs.next()) {
+ System.out.println(rs.getString("spacecraft"));
+ }
+ }
+ }
+
+ // Hämtar ett specifikt uppdrag baserat på mission_id.
+ private void getMissionById(Connection conn, Scanner scanner) throws SQLException {
+ System.out.print("Enter mission_id: ");
+ String id = scanner.nextLine();
+ try (PreparedStatement stmt = conn.prepareStatement(
+ "SELECT spacecraft, launch_date FROM moon_mission WHERE mission_id = ?")) {
+ stmt.setString(1, id);
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+
+ // Hämtar årtal från launch_date.
+ int year = rs.getDate("launch_date").toLocalDate().getYear();
+ System.out.println("Mission: " + rs.getString("spacecraft") + ", Year: " + year);
+ } else {
+ System.out.println("Mission not found.");
+ }
+ }
+ }
+ }
+
+ // Räknar hur många uppdrag som skedde ett specifikt år.
+ private void countMissionsByYear(Connection conn, Scanner scanner) throws SQLException {
+ System.out.print("Enter year: ");
+ String year = scanner.nextLine();
+ try (PreparedStatement stmt = conn.prepareStatement(
+ "SELECT COUNT(*) AS count FROM moon_mission WHERE YEAR(launch_date) = ?")) {
+ stmt.setString(1, year);
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+ System.out.println("Year: " + year + ", Number of missions: " + rs.getInt("count"));
+ }
+ }
+ }
+ }
+
+ // Skapar ett nytt konto.
+ private void createAccount(Connection conn, Scanner scanner) throws SQLException {
+ System.out.print("First name: ");
+ String firstName = scanner.nextLine();
+ System.out.print("Last name: ");
+ String lastName = scanner.nextLine();
+ System.out.print("SSN: ");
+ String ssn = scanner.nextLine();
+ System.out.print("Password: ");
+ String password = scanner.nextLine();
+
+ try (PreparedStatement stmt = conn.prepareStatement(
+ "INSERT INTO account (first_name, last_name, ssn, password) VALUES (?, ?, ?, ?)")) {
+ stmt.setString(1, firstName);
+ stmt.setString(2, lastName);
+ stmt.setString(3, ssn);
+ stmt.setString(4, password);
+ stmt.executeUpdate();
+ System.out.println("Account created!");
+ }
+ }
+
+ // Uppdaterar ett lösenord för ett konto.
+ private void updatePassword(Connection conn, Scanner scanner) throws SQLException {
+ System.out.print("User ID: ");
+ String userId = scanner.nextLine();
+ System.out.print("New password: ");
+ String newPassword = scanner.nextLine();
+
+ try (PreparedStatement stmt = conn.prepareStatement("UPDATE account SET password = ? WHERE user_id = ?")) {
+ stmt.setString(1, newPassword);
+ stmt.setString(2, userId);
+ int rows = stmt.executeUpdate();
+ System.out.println(rows > 0 ? "Password updated!" : "User not found.");
+ }
+ }
+
+ // Tar bort ett konto.
+ private void deleteAccount(Connection conn, Scanner scanner) throws SQLException {
+ System.out.print("User ID: ");
+ String userId = scanner.nextLine();
+
+ try (PreparedStatement stmt = conn.prepareStatement("DELETE FROM account WHERE user_id = ?")) {
+ stmt.setString(1, userId);
+ int rows = stmt.executeUpdate();
+ System.out.println(rows > 0 ? "Account deleted!" : "User not found.");
+ }
+ }
+
+ // Avgör om programmet körs i DevMode.
private static boolean isDevMode(String[] args) {
- if (Boolean.getBoolean("devMode")) //Add VM option -DdevMode=true
- return true;
- if ("true".equalsIgnoreCase(System.getenv("DEV_MODE"))) //Environment variable DEV_MODE=true
- return true;
- return Arrays.asList(args).contains("--dev"); //Argument --dev
+ if (Boolean.getBoolean("devMode")) return true;
+ if ("true".equalsIgnoreCase(System.getenv("DEV_MODE"))) return true;
+ return Arrays.asList(args).contains("--dev");
}
- /**
- * Reads configuration with precedence: Java system property first, then environment variable.
- * Returns trimmed value or null if neither source provides a non-empty value.
- */
+ // Läser värden från system properties eller environment variabler.
private static String resolveConfig(String propertyKey, String envKey) {
String v = System.getProperty(propertyKey);
if (v == null || v.trim().isEmpty()) {
@@ -59,4 +204,4 @@ private static String resolveConfig(String propertyKey, String envKey) {
}
return (v == null || v.trim().isEmpty()) ? null : v.trim();
}
-}
+}
\ No newline at end of file