package crud; import java.sql.*; import io.javalin.Javalin; import io.javalin.http.Context; import io.javalin.rendering.template.JavalinJte; import static io.javalin.rendering.template.TemplateUtil.model; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static Logger logger; private static Connection connection; public static void main(String[] args) throws SQLException { logger = LoggerFactory.getLogger(App.class); connection = DriverManager.getConnection("jdbc:postgresql:books"); initializeDB(); Javalin.create(config -> { config.requestLogger.http((ctx, ms) -> { // log each request logger.info("" + ctx.statusCode() + " " + ctx.method() + " " + ctx.path()); }); config.fileRenderer(new JavalinJte()); // render using JTE }) // now set up all the routes .get("/", App::listRoute) .get("/list", App::listRoute) .post("/add", App::addRoute) .get("/view", App::viewRoute) .get("/edit", App::editGetRoute) .post("/edit", App::editPostRoute) .get("/delete", App::deleteGetRoute) .post("/delete", App::deletePostRoute) .start(7070); } // set up the tables if needed // insert sample data if needed private static void initializeDB() throws SQLException { Statement statement = connection.createStatement(); statement.executeUpdate(""" CREATE TABLE IF NOT EXISTS books( id SERIAL PRIMARY KEY, title TEXT, author TEXT ) """); ResultSet rs = statement.executeQuery("SELECT count(*) AS c FROM books"); rs.next(); if (rs.getInt("c") == 0) { // the books table is empty, so add some sample data statement.executeUpdate(""" INSERT INTO books(title, author) VALUES ('Types and Programming Languages', 'Benjamin C. Pierce'), ('Database Systems: The Complete Book', 'Hector Garcia-Molina, Jeff Ullman, and Jennifer Widom') """); } statement.close(); } //////////////////////////////////////////////////////////////////////////// // Rest of this file contains the implementation of the routes //////////////////////////////////////////////////////////////////////////// private static void listRoute(Context ctx) throws SQLException { // ctx.render uses JTE to instantiate a template with given params // // see app/src/main/jte/list.html for the definition of this template ctx.render("list.html", model("books", Book.list(connection))); } private static void viewRoute(Context ctx) throws SQLException { String idParam = ctx.queryParam("id"); if (idParam == null) { ctx.status(400); ctx.result("must provide id query param"); return; } Integer targetId = 0; try { targetId = Integer.parseInt(idParam); } catch (NumberFormatException e) { ctx.status(400); ctx.result("id '" + idParam + "' does not appear to be an integer"); return; } Book book = Book.getById(connection, targetId); if (book == null) { ctx.status(400); ctx.result("no book with id " + targetId); return; } ctx.render("view.html", model("book", book)); } private static void editGetRoute(Context ctx) throws SQLException { String idParam = ctx.queryParam("id"); if (idParam == null) { ctx.status(400); ctx.result("must provide id query param"); return; } Integer targetId = 0; try { targetId = Integer.parseInt(idParam); } catch (NumberFormatException e) { ctx.status(400); ctx.result("id '" + idParam + "' does not appear to be an integer"); return; } Book book = Book.getById(connection, targetId); if (book == null) { ctx.status(400); ctx.result("no book with id " + targetId); return; } ctx.render("edit.html", model("book", book)); } private static void editPostRoute(Context ctx) throws SQLException { String idParam = ctx.formParam("id"); if (idParam == null) { ctx.status(400); ctx.result("malformed edit POST request missing id param"); return; } Integer targetId = 0; try { targetId = Integer.parseInt(idParam); } catch (NumberFormatException e) { ctx.status(400); ctx.result("malformed edit POST request: id '" + idParam + "' does not appear to be an integer"); return; } String titleParam = ctx.formParam("title"); if (titleParam == null) { ctx.status(400); ctx.result("malformed edit POST request missing title param"); return; } String authorParam = ctx.formParam("author"); if (authorParam == null) { ctx.status(400); ctx.result("malformed edit POST request missing author param"); return; } Book book = Book.getById(connection, targetId); if (book == null) { ctx.status(400); ctx.result("malformed our out of date edit POST request: no book with id " + targetId); return; } book.title = titleParam; book.author = authorParam; book.save(connection); ctx.redirect("/list"); } private static void deleteGetRoute(Context ctx) throws SQLException { String idParam = ctx.queryParam("id"); if (idParam == null) { ctx.status(400); ctx.result("must provide id query param"); return; } Integer targetId = 0; try { targetId = Integer.parseInt(idParam); } catch (NumberFormatException e) { ctx.status(400); ctx.result("id '" + idParam + "' does not appear to be an integer"); return; } Book book = Book.getById(connection, targetId); if (book == null) { ctx.status(400); ctx.result("no book with id " + targetId); return; } ctx.render("delete.html", model("book", book)); } private static void deletePostRoute(Context ctx) throws SQLException { String idParam = ctx.formParam("id"); if (idParam == null) { ctx.status(400); ctx.result("malformed delete POST request missing id param"); return; } Integer targetId = 0; try { targetId = Integer.parseInt(idParam); } catch (NumberFormatException e) { ctx.status(400); ctx.result("malformed delete POST request: id '" + idParam + "' does not appear to be an integer"); return; } Book book = Book.getById(connection, targetId); if (book == null) { ctx.status(400); ctx.result("malformed our out of date delete POST request: no book with id " + targetId); return; } book.delete(connection); ctx.redirect("/list"); } private static void addRoute(Context ctx) throws SQLException { String titleParam = ctx.formParam("title"); if (titleParam == null) { ctx.status(400); ctx.result("malformed add POST request missing title param"); return; } String authorParam = ctx.formParam("author"); if (authorParam == null) { ctx.status(400); ctx.result("malformed add POST request missing author param"); return; } Book b = Book.create(connection, titleParam, authorParam); logger.info(b.toString()); ctx.redirect("/list"); } }