Java Servlet

Java Servlet CRUD with Image (Java Servlet CRUD with Image)

Introduction

Java Servlet-based applications have been widely used for building dynamic, database-driven web applications. In this tutorial, we will explore how to create a CRUD (Create, Read, Update, Delete) application using Java Servlets with image upload functionality. This application will integrate several key components: Jakarta EE 9+, Apache Tomcat 10+, and MySQL Database. We will also be utilizing JSTL (Jakarta Standard Tag Library) to simplify the JSP pages and create a more maintainable and cleaner codebase.

In this example, we will build a blog post management system where users can add, list, edit, and delete blog posts along with an image upload feature. The system will allow users to upload an image while creating or editing a post, which will be saved in the server’s directory. The application is structured to use the Servlet API for server-side processing and JSP pages to display the user interface, following the best practices for Jakarta EE.

This guide will walk you through the necessary steps, from configuring the dependencies to setting up the application logic. Whether you’re new to Java web applications or looking to enhance your existing knowledge, this tutorial will help you understand the process of building a full-fledged CRUD application with image support.

Prerequisites

  1. Jakarta EE 9+ (or Jakarta EE 10)
  2. Apache Tomcat 10+ (supports Jakarta EE)
  3. MySQL Database
  4. Eclipse IDE (or any IDE supporting Jakarta EE)
  5. MySQL Connector/J (JDBC Driver)
  6. Jakarta Standard Tag Library (JSTL) (included in Jakarta EE)

Project Struture:

BlogApp/
│── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── com/
│   │   │   │   ├── blogapp/
│   │   │   │   │   ├── dao/
│   │   │   │   │   │   ├── PostDAO.java
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── Post.java
│   │   │   │   │   ├── servlet/
│   │   │   │   │   │   ├── AddPostServlet.java
│   │   │   │   │   │   ├── EditPostServlet.java
│   │   │   │   │   │   ├── DeletePostServlet.java
│   │   │   │   │   │   ├── ListPostsServlet.java
│   │   │   │   │   ├── util/
│   │   │   │   │   │   ├── DBConnection.java
│   │   ├── webapp/
│   │   │   ├── META-INF/
│   │   │   ├── WEB-INF/
│   │   │   │   ├── web.xml
│   │   │   │   ├── lib/ (for manual JAR dependencies if not using Maven)
│   │   │   ├── uploads/ (for storing uploaded images)
│   │   │   ├── css/
│   │   │   │   ├── styles.css
│   │   │   ├── jsp/
│   │   │   │   ├── listPosts.jsp
│   │   │   │   ├── addPost.jsp
│   │   │   │   ├── editPost.jsp
│   │   │   ├── index.jsp (optional, main page)
│── pom.xml (if using Maven)
│── README.md

Step 1: Update Dependencies

  1. Add Jakarta EE Dependencies:
    • If you’re using Maven, add the following dependencies to your pom.xml:
<dependencies>
    <!-- Jakarta Servlet API -->
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>6.0.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- Jakarta JSTL -->
    <dependency>
        <groupId>jakarta.servlet.jsp.jstl</groupId>
        <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>jakarta.servlet.jsp.jstl</artifactId>
        <version>3.0.0</version>
    </dependency>

    <!-- MySQL Connector/J -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>
  1. Add JARs Manually (if not using Maven):
    • Download the following JARs and add them to WEB-INF/lib:
      • jakarta.servlet-api.jar
      • jakarta.servlet.jsp.jstl-api.jar
      • jakarta.servlet.jsp.jstl.jar
      • mysql-connector-java.jar

 

Data Base connection :

DBConnection.java

package com.blogapp.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/blogdb"; // Change `blogdb` to your database name
    private static final String USER = "root"; // Change `root` to your MySQL username
    private static final String PASSWORD = ""; // Change `""` to your MySQL password if any
    private static Connection connection = null;

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver"); // Load MySQL Driver
            connection = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("Database Connected Successfully!");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("Database connection failed!");
        }
    }

    public static Connection getConnection() {
        return connection;
    }
}

Database and Table

Database: blogapp

You can create the database using:

CREATE DATABASE blogapp;
USE blogapp;

1. posts Table

This table stores blog posts, including images.

CREATE TABLE posts (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    image VARCHAR(255) DEFAULT NULL, -- Stores image filename/path
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

 

Fields Explanation:

  • id → Unique ID for each blog post.
  • title → Title of the blog post.
  • content → Content/body of the post.
  • image → Stores the image filename (you can save images in a folder like uploads/).
  • created_at → Stores the timestamp when the post is created.

 


Step 2: Create a PostDAO.java  file

package com.blogapp.dao;

import com.blogapp.model.Post;
import com.blogapp.util.DBConnection;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class PostDAO {
    private Connection connection;

    public PostDAO(Connection connection) {
        this.connection = connection;
    }

    // Create a new post
    public boolean addPost(Post post) {
        String sql = "INSERT INTO posts (title, content, image, created_at) VALUES (?, ?, ?, ?)";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setString(1, post.getTitle());
            statement.setString(2, post.getContent());
            statement.setString(3, post.getImage());
            statement.setTimestamp(4, new Timestamp(System.currentTimeMillis()));

            int rowsAffected = statement.executeUpdate();
            return rowsAffected > 0;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    // Get all posts
    public List<Post> getAllPosts() {
        List<Post> posts = new ArrayList<>();
        String sql = "SELECT * FROM posts ORDER BY created_at DESC";
        try (Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery(sql)) {

            while (resultSet.next()) {
                Post post = new Post();
                post.setId(resultSet.getInt("id"));
                post.setTitle(resultSet.getString("title"));
                post.setContent(resultSet.getString("content"));
                post.setImage(resultSet.getString("image"));
                post.setCreatedAt(resultSet.getTimestamp("created_at"));
                posts.add(post);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return posts;
    }

    // Get a post by its ID
    public Post getPostById(int id) {
        Post post = null;
        String sql = "SELECT * FROM posts WHERE id = ?";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setInt(1, id);
            try (ResultSet resultSet = statement.executeQuery()) {
                if (resultSet.next()) {
                    post = new Post();
                    post.setId(resultSet.getInt("id"));
                    post.setTitle(resultSet.getString("title"));
                    post.setContent(resultSet.getString("content"));
                    post.setImage(resultSet.getString("image"));
                    post.setCreatedAt(resultSet.getTimestamp("created_at"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return post;
    }

    // Update an existing post
    public boolean updatePost(Post post) {
        String sql = "UPDATE posts SET title = ?, content = ?, image = ? WHERE id = ?";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setString(1, post.getTitle());
            statement.setString(2, post.getContent());
            statement.setString(3, post.getImage());
            statement.setInt(4, post.getId());

            int rowsAffected = statement.executeUpdate();
            return rowsAffected > 0;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    // Delete a post by its ID
    public boolean deletePost(int id) {
        String sql = "DELETE FROM posts WHERE id = ?";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setInt(1, id);
            int rowsAffected = statement.executeUpdate();
            return rowsAffected > 0;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }
}

2.1 Write Modal Class

package com.blogapp.model;

import java.sql.Timestamp;

public class Post {
    private int id;
    private String title;
    private String content;
    private String image;
    private Timestamp createdAt;

    // Default constructor
    public Post() {}

    // Constructor with all fields
    public Post(int id, String title, String content, String image, Timestamp createdAt) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.image = image;
        this.createdAt = createdAt;
    }

    // Getter and Setter for id
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    // Getter and Setter for title
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    // Getter and Setter for content
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    // Getter and Setter for image
    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    // Getter and Setter for createdAt
    public Timestamp getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Timestamp createdAt) {
        this.createdAt = createdAt;
    }

    // Optional: toString method for easy printing
    @Override
    public String toString() {
        return "Post{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", image='" + image + '\'' +
                ", createdAt=" + createdAt +
                '}';
    }
}

 


Step 3: Update JSP Files with JSTL

Use JSTL tags in your JSP files for cleaner and more maintainable code.

listPosts.jsp with JSTL

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>List Posts</title>
</head>
<body>
    <h1>Blog Posts</h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Content</th>
            <th>Image</th>
            <th>Created At</th>
            <th>Actions</th>
        </tr>
        <c:forEach var="post" items="${posts}">
            <tr>
                <td>${post.id}</td>
                <td>${post.title}</td>
                <td>${post.content}</td>
                <td>
                    <c:if test="${not empty post.image}">
                        <img src="uploads/${post.image}" width="100">
                    </c:if>
                </td>
                <td>${post.createdAt}</td>
                <td>
                    <a href="editPost?id=${post.id}">Edit</a>
                    <a href="deletePost?id=${post.id}" onclick="return confirm('Are you sure?')">Delete</a>
                </td>
            </tr>
        </c:forEach>
    </table>
    <br>
    <a href="addPost.jsp">Add New Post</a>
</body>
</html>

addPost.jsp with JSTL

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Add Post</title>
</head>
<body>
    <h1>Add New Post</h1>
    <form action="addPost" method="post" enctype="multipart/form-data">
        <label for="title">Title:</label>
        <input type="text" id="title" name="title" required><br><br>
        <label for="content">Content:</label>
        <textarea id="content" name="content" required></textarea><br><br>
        <label for="image">Image:</label>
        <input type="file" id="image" name="image" accept="image/*"><br><br>
        <input type="submit" value="Add Post">
    </form>
</body>
</html>

editPost.jsp with JSTL

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Edit Post</title>
</head>
<body>
    <h1>Edit Post</h1>
    <form action="editPost" method="post" enctype="multipart/form-data">
        <input type="hidden" name="id" value="${post.id}">
        <label for="title">Title:</label>
        <input type="text" id="title" name="title" value="${post.title}" required><br><br>
        <label for="content">Content:</label>
        <textarea id="content" name="content" required>${post.content}</textarea><br><br>
        <label for="image">Image:</label>
        <input type="file" id="image" name="image" accept="image/*"><br><br>
        <c:if test="${not empty post.image}">
            <p>Current Image: <img src="uploads/${post.image}" width="100"></p>
        </c:if>
        <input type="submit" value="Update Post">
    </form>
</body>
</html>

Step 4: Update Servlets for Jakarta EE

Replace javax.servlet with jakarta.servlet in all servlets. For example:

AddPostServlet.java (Updated for Jakarta EE)

package com.blogapp.servlet;

import com.blogapp.dao.PostDAO;
import com.blogapp.model.Post;
import com.blogapp.util.DBConnection;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;

@WebServlet("/addPost")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, // 2MB
        maxFileSize = 1024 * 1024 * 10, // 10MB
        maxRequestSize = 1024 * 1024 * 50) // 50MB
public class AddPostServlet extends HttpServlet {
    private static final String UPLOAD_DIR = "uploads";

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String title = request.getParameter("title");
        String content = request.getParameter("content");

        // Get the absolute path of the application
        String applicationPath = request.getServletContext().getRealPath("");
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;

        // Create the upload directory if it doesn't exist
        File uploadDir = new File(uploadFilePath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        String fileName = "";
        for (Part part : request.getParts()) {
            fileName = getFileName(part);
            if (fileName != null && !fileName.isEmpty()) {
                part.write(uploadFilePath + File.separator + fileName);
            }
        }

        Post post = new Post();
        post.setTitle(title);
        post.setContent(content);
        post.setImage(fileName);

        Connection connection = DBConnection.getConnection();
        PostDAO postDAO = new PostDAO(connection);
        if (postDAO.addPost(post)) {
            response.sendRedirect("listPosts");
        } else {
            response.sendRedirect("addPost.jsp");
        }
    }

    private String getFileName(Part part) {
        String contentDisp = part.getHeader("content-disposition");
        String[] tokens = contentDisp.split(";");
        for (String token : tokens) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length() - 1);
            }
        }
        return null;
    }
}



ListPostServlet.java

 

package web;

import java.io.IOException;
import java.sql.Connection;
import java.util.List;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import model.Post;
import Dao.PostDAO;
import util.DBConnection;

@WebServlet("/ListPostServlet")
public class ListPostServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    public ListPostServlet() {
        super();
    }

    @SuppressWarnings("resource")
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Connection connection = DBConnection.getConnection();
        if (connection == null) {
            response.getWriter().append("Database connection failed.");
            return;
        }
        
        PostDAO postDAO = new PostDAO(connection);
        
        // Handle delete operation
        String mode = request.getParameter("mode");
        String postIdParam = request.getParameter("id");
        if ("del".equals(mode) && postIdParam != null) {
            try {
                int postId = Integer.parseInt(postIdParam);
                postDAO.deletePost(postId);
            } catch (NumberFormatException e) {
                response.getWriter().append("Invalid post ID.");
                return;
            }
        }
        
        // Fetch and display posts
        List<Post> posts = postDAO.getAllPosts();
        request.setAttribute("posts", posts);
        request.getRequestDispatcher("listPosts.jsp").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

EditPostServlet.java

package web;

import model.Post;
import Dao.PostDAO;
import util.DBConnection;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;

@WebServlet("/editPost")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, // 2MB
        maxFileSize = 1024 * 1024 * 10, // 10MB
        maxRequestSize = 1024 * 1024 * 50) // 50MB
public class EditPostServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final String UPLOAD_DIR = "uploads";

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int id = Integer.parseInt(request.getParameter("id"));
        Connection connection = DBConnection.getConnection();
        PostDAO postDAO = new PostDAO(connection);
        Post post = postDAO.getPostById(id);

        if (post != null) {
            request.setAttribute("post", post);
            request.getRequestDispatcher("editPost.jsp").forward(request, response);
        } else {
            response.sendRedirect("listPosts");
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int id = Integer.parseInt(request.getParameter("id"));
        String title = request.getParameter("title");
        String content = request.getParameter("content");

        // File upload handling
        String applicationPath = request.getServletContext().getRealPath("");
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;

        File uploadDir = new File(uploadFilePath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        String fileName = "";
        for (Part part : request.getParts()) {
            fileName = getFileName(part);
            if (fileName != null && !fileName.isEmpty()) {
                part.write(uploadFilePath + File.separator + fileName);
            }
        }

        Connection connection = DBConnection.getConnection();
        PostDAO postDAO = new PostDAO(connection);
        Post existingPost = postDAO.getPostById(id);

        if (existingPost != null) {
            existingPost.setTitle(title);
            existingPost.setContent(content);
            if (!fileName.isEmpty()) {
                existingPost.setImage(fileName); // Update image if a new one is uploaded
            }

            if (postDAO.updatePost(existingPost)) {
                response.sendRedirect("ListPostServlet");
            } else {
                response.sendRedirect("editPost.jsp?id=" + id);
            }
        } else {
            response.sendRedirect("listPosts");
        }
    }

    private String getFileName(Part part) {
        String contentDisp = part.getHeader("content-disposition");
        for (String token : contentDisp.split(";")) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length() - 1);
            }
        }
        return null;
    }
}

 


Step 5: Deploy and Test

  1. Deploy the application to Apache Tomcat 10+.
  2. Access the application via http://localhost:8080/BlogApp/listPosts.

 

Download code from  gitHub

https://github.com/acesoftech/javaservlet-crud-with-image-upload/upload

Leave a Reply

Your email address will not be published. Required fields are marked *