Table of contents
- 1. Introduction to Maven 🚀
- 2. Maven Lifecycle and Its Stages 🔄
- 3. Maven Artifacts 📦
- 4. Introduction to pom.xml 📝
- 5. Standard Java Directory Structure & Files 📂
- 6. Installation Requirements: JDK, JRE, JVM ☕️
- 7. JDK Version Compatibility 🔄
- 8. The .m2 Directory 📁
- 9. Where is the Final Artifact Created? 🎁
- 10. Amazon Linux 2023 Environment: Setting Up Java and Maven 🖥️
- 1. Choosing Between OpenJDK and Oracle JDK ☕️
- 2. Downloading JDKs Using wget 📥
- 3. Using yum Package Manager vs. wget 🆚
- 4. Downloading the Latest Version of Maven Using wget 🌐
- 5. Why Use /opt for External Downloads? 📂
- 6. Verify Installation and Check Versions ✅
- 7. Configuring Environment Variables 🌐
- What is /etc/profile ? 🗒️
- What is echo $PATH ? 📢
- Adding Environment Variables to /etc/profile ⚙️
- Why Use JAVA_HOME and Not Other Parameters? 🧐
- Retaining Environment Settings After Reboot 🔄
- 8. What is an Archetype in Maven? 🧩
- 11. Sample Web Application in Amazon Linux 2023 Environment Deployed in Tomcat 🌐
- 1. What is Tomcat? 🐱💻
- 2. Maven Builds and Deployment in Tomcat 🛠️
- 3. Tomcat Folder Structure and Its Uses 📂
- 4. Amazon Linux 2023 Environment Setup 🐧
- 1. Install Oracle JDK 8 ☕️
- 2. Install Apache Maven 🚀
- 3. Install Apache Tomcat 🐱
- 4. Set Up Environment Variables 🌍
- 5. Install tree Utility 🌳
- 6. Verification of installed binaries 🛠️
- 7. Java Source Code and Application Analysis 💻
- Project Directory Structure 📂
- Detailed Explanation of Each File in ~/advanced-java-webapp/ directory
- 1. pom.xml
- Content Breakdown:
- Root Element
- Model Version
- Project Identification
- Properties
- Dependencies
- Build Configuration
- Summary
- 2. web.xml
- Content Breakdown:
- 3. HomeServlet.java
- Content Breakdown:
- Package and Imports
- Servlet Annotation and Class Declaration
- Member Variables and Initialization
- doGet Method
- doPost Method
- createOrUpdatePost Method
- deletePost Method
- findPostById Method
- prepareEditPost Method
- BlogPost Inner Class
- Integration and Dependencies Between Methods and Classes
- HomeServlet and BlogPost
- How Each Part Interacts:
- 4. BlogPost.java
- Content Breakdown:
- Private Fields
- Constructor
- Getter Methods
- Usage and Dependencies
- Integration and Interaction
- 5. index.jsp
- Content Breakdown:
- JSP Directives
- HTML Document Structure
- HTML Body and Main Content
- Modal for Nickname Input
- Scripts and JavaScript Logic
- Usage and Integration
- 6. home.jsp
- Content Breakdown:
- JSP Directives
- HTML Document Structure
- Body and Main Content
- JavaScript Logic
- Usage and Integration
- 7. HomeServletTest.java
- Content Breakdown:
- Package Declaration and Imports
- Class Declaration
- Mock Object Declarations
- @Before Setup Method
- Test Methods
- Usage and Integration
- 8. BlogPostTest.java
- Content Breakdown:
- Package Declaration and Imports
- Class Declaration
- Test Methods
- Usage and Integration
- 5. Maven Build Process for our application 🚀
- 6. Deploying to Tomcat 🌐
1. Introduction to Maven 🚀
What is Maven? 🤔
Maven is a powerful, widely-used project management and comprehension tool in the Java ecosystem. The name "Maven" means "accumulator of knowledge." Maven simplifies the entire build process by providing a standardized structure and a clear lifecycle for project development. It helps developers manage dependencies, execute tests, package code, and deploy applications with minimal configuration. While it’s primarily designed for Java, Maven can be used with other programming languages as well.
Summary of Maven 📚
Build Automation 🔄: Maven automates the build process, including compiling the code, running tests, packaging it into a distributable format like a JAR file, and deploying the code to a server or repository. Automation ensures consistency across environments and reduces the likelihood of human error.
Dependency Management 📦: One of Maven’s key strengths is its ability to manage project dependencies. Maven automatically downloads required libraries from a central repository (like Maven Central) and includes them in your project, resolving version conflicts and handling transitive dependencies (dependencies of dependencies).
Project Management 🛠️: Maven uses a Project Object Model (POM) file (
pom.xml
) to define the project structure, dependencies, plugins, and other configuration details. The POM file is the core of a Maven project, making it easier to manage projects consistently across different teams and environments.Convention Over Configuration 📐: Maven encourages a standardized project structure (e.g.,
src/main/java
for source code,src/test/java
for tests). This convention reduces the need for custom configuration, which speeds up the development process and ensures consistency across projects.
Use Cases of Maven 🛠️
Java Project Builds 🧱: Maven is primarily used for building Java applications. It compiles the source code, packages it into a JAR/WAR/EAR, and manages dependencies, all with simple commands.
Dependency Management 📦: In complex projects with multiple dependencies, Maven handles the inclusion of external libraries (like Spring, Hibernate) by automatically downloading them from repositories, ensuring your project has everything it needs.
Continuous Integration (CI) 🤖: Maven integrates seamlessly with CI/CD pipelines, allowing automated builds and deployments. Tools like Jenkins, GitLab CI, and CircleCI often use Maven to build and test Java projects.
Maven as a Build Tool for DevOps 🔧
Maven is an essential part of the DevOps toolkit, particularly in Java environments:
Automating Repetitive Tasks 🔁: aven scripts (
mvn install
,mvn deploy
) can be run automatically by CI/CD tools like Jenkins, Bamboo, or GitLab CI to build, test, and deploy code whenever changes are pushed to the repository.Integrating with CI/CD Pipelines ⚙️: Maven’s lifecycle and plugins can be easily integrated into CI/CD pipelines, enabling automated builds, testing, and deployment, which accelerates the software development lifecycle.
Supporting Multi-Module Projects 🗂️: Maven efficiently manages projects with multiple modules (e.g., a large enterprise application with separate modules for web, service, and persistence layers). Each module can have its own POM file, and Maven can build and manage these modules as part of a larger project.
Best Practices for Using Maven 🏅
Use a Consistent Directory Structure 📁: Stick to Maven’s standard directory layout (
src/main/java
,src/test/java
, etc.) to minimize configuration and make it easier for new team members to understand the project structure.Define Dependencies Clearly 📦: Only include necessary dependencies in your
pom.xml
to keep the project lightweight. Avoid unnecessary dependencies that could bloat the project and increase the build time.Keep the POM File Clean and Organized 📝: Comment your
pom.xml
where necessary, and group related sections together. For example, keep all dependency declarations in one section, and plugin configurations in another.Use a Repository Manager 🌐: Consider using a repository manager like Nexus or Artifactory to store and manage your build artifacts. This adds a layer of security and control over what dependencies are being used in your builds.
Regularly Update Dependencies 🔄: Stay up to date with the latest versions of your dependencies to benefit from security patches, new features, and performance improvements. Use tools like the Maven Versions plugin to manage this process.
Use Profiles for Environment-Specific Configurations 🌍: Profiles in Maven allow you to customize the build process for different environments (e.g., development, testing, production).
Leverage Plugins ⬆️: Use Maven plugins to extend functionality, such as
maven-compiler-plugin
for compiling code,maven-surefire-plugin
for running tests, andmaven-jar-plugin
for creating JAR files.
Advantages of Maven 🌟
- Standardization 🧩: Maven’s conventions provide a standardized way to build and manage projects, making it easier to work across different projects or teams.
- Ease of Use 🛠️: Once you’re familiar with Maven’s conventions, you can set up new projects and manage dependencies with minimal effort.
- Extensibility 🔌: Maven’s plugin system allows it to be extended with custom build logic. There are thousands of plugins available for various tasks, from code analysis to deployment.
- Comprehensive Documentation 📚: Maven has extensive documentation and a large community, making it easy to find help or guidance when needed.
Disadvantages of Maven ⚠️
- Steep Learning Curve 📈: Maven can be complex for beginners due to its vast array of features and the requirement to understand concepts like POM, lifecycle phases, and dependency scopes.
- Dependency Conflicts ⚠️: Managing transitive dependencies can be challenging, especially when different libraries require different versions of the same dependency.
- Slower Builds ⏳: Maven’s comprehensive build process can be slower compared to other tools, particularly when dealing with large projects or extensive dependencies.
2. Maven Lifecycle and Its Stages 🔄
Maven's lifecycle defines the steps that occur when building a project. Each phase in the lifecycle represents a stage in the build process, from validating the project configuration to deploying the final build.
Overview of the Maven Lifecycle 📜
Maven’s build lifecycle consists of three main lifecycles:
- Default Lifecycle 🛠️: Handles project deployment, including compile, test, package, and install phases.
- Clean Lifecycle 🧹: Handles project cleaning, including removing previous builds.
- Site Lifecycle 🌐: Handles the creation of the project's site documentation.
Within the Default Lifecycle, the most commonly used phases are:
validate 🛠️: Validates that the project is correct and all necessary information is available.
- Example Output:
[INFO] Scanning for projects... [INFO] ----------------------< com.example:my-app >----------------------- [INFO] Building my-app 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-validate-plugin:1.0.0:validate (default) @ my-app --- [INFO] [INFO] BUILD SUCCESS
- Example Output:
compile 🧩: Compiles the source code of the project.
- Example Output:
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 10 source files to /target/classes [INFO] [INFO] BUILD SUCCESS
- Example Output:
test 🧪: Runs tests using a testing framework like JUnit.
- Example Output:
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ my-app --- [INFO] Surefire report directory: /target/surefire-reports [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.example.MyAppTest [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.123 s [INFO] [INFO] BUILD SUCCESS
- Example Output:
package 📦: Packages the compiled code into a distributable format, such as a JAR file.
- Example Output:
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ my-app --- [INFO] Building jar: /target/my-app-1.0-SNAPSHOT.jar [INFO] [INFO] BUILD SUCCESS
- Example Output:
verify ✔️: Runs checks to ensure the package is valid and meets quality standards.
- Example Output:
[INFO] --- maven-verifier-plugin:1.1:verify (default-verify) @ my-app --- [INFO] Verifying the project artifacts... [INFO] [INFO] BUILD SUCCESS
- Example Output:
install 💾: Installs the package into the local repository, making it available for other projects on the same machine.
- Example Output:
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ my-app --- [INFO] Installing /target/my-app-1.0-SNAPSHOT.jar to ~/.m2/repository/com/example/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar [INFO] [INFO] BUILD SUCCESS
- Example Output:
deploy 🌐: Copies the final package to a remote repository for sharing with other developers or projects.
- Example Output:
[INFO] --- maven-deploy-plugin:2.8.2:deploy (default-deploy) @ my-app --- [INFO] Uploading: https://repository.example.com/releases/com/example/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar [INFO] [INFO] BUILD SUCCESS
- Example Output:
Dependency Between Lifecycle Stages 🔗
Certain lifecycle stages inherently include the execution of previous stages:
- package 📦: When you run
mvn package
, Maven first runsvalidate
,compile
, andtest
stages before packaging the code. - install 💾: The
mvn install
command runs all prior stages (validate
,compile
,test
,package
, andverify
) before installing the artifact to the local repository. - deploy 🌐: Running
mvn deploy
executes all the preceding phases (validate
,compile
,test
,package
,verify
,install
) to ensure the artifact is correctly built and tested before being deployed.
Example Maven Command Execution ⚙️
Let’s run through a simple example of the mvn package
command and see what happens.
mvn package
Expected Output 🖥️
- validate: Maven checks that the project structure is correct.
[INFO] --- maven-enforcer-plugin:1.4.1:enforce (enforce-maven) @ my-app --- [INFO] Skipping Rule Enforcement.
- compile: The source code is compiled.
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 5 source files to /path/to/project/target/classes
- test: The tests are run.
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ my-app --- [INFO] Surefire report directory: /path/to/project/target/surefire-reports [INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.345 s - in TestSuite
- package: The compiled code is packaged into a JAR file.
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ my-app --- [INFO] Building jar: /path/to/project/target/my-app-1.0-SNAPSHOT.jar
3. Maven Artifacts 📦
Maven builds artifacts as the output of its build lifecycle. An artifact is a file, usually a JAR (Java ARchive), WAR (Web Application Archive), or EAR (Enterprise Archive), that is produced by Maven after executing its lifecycle stages. These artifacts can be shared with other developers, deployed to servers, or published to a repository for other projects to use.
How Maven Creates Artifacts 🛠️
Compilation 🧩: Maven first compiles the source code into bytecode that can be run on the Java Virtual Machine (JVM). This happens during the compile phase.
Packaging 📦: In the package phase, Maven takes the compiled code, along with any resources like configuration files or libraries, and packages them into a JAR, WAR, or EAR file. This file is the final product of the build process.
Installation and Deployment 💾🌐: After packaging, Maven can install the artifact into the local repository (
~/.m2/repository
) using the install phase or deploy it to a remote repository using the deploy phase. This makes the artifact available for use by other projects or for deployment to a server.
Types of Artifacts Maven Creates 🗂️
JAR (Java ARchive) 📁:
- Definition: A JAR file is the most common type of artifact. It contains compiled Java classes, metadata, and resources like images and text files. It's used for Java applications or libraries.
- Usage: JAR files are used when you want to distribute a library or a standalone application.
- Example Output:
[INFO] Building jar: /target/my-app-1.0-SNAPSHOT.jar
WAR (Web Application Archive) 🌐:
- Definition: A WAR file is used for web applications. It contains the web components like JSP files, servlets, HTML pages, JavaScript, and other resources necessary for a web application.
- Usage: WAR files are deployed to web servers like Apache Tomcat, JBoss, or GlassFish.
- Example Output:
[INFO] Building war: /target/my-web-app-1.0-SNAPSHOT.war
EAR (Enterprise Archive) 🏢:
- Definition: An EAR file is used for large, enterprise-level applications. It can contain multiple JAR and WAR files along with other resources like XML configuration files.
- Usage: EAR files are deployed to enterprise servers like IBM WebSphere or Oracle WebLogic.
- Example Output:
[INFO] Building ear: /target/my-enterprise-app-1.0-SNAPSHOT.ear
Why Multiple Lines of Code Are Packaged into Single Artifacts 🧳
Packaging multiple lines of code and resources into a single artifact has several benefits:
- Simplicity 🎯: Simplifies deployment by bundling all necessary files into a single archive.
- Versioning 🗓️: Ensures a consistent version of the application or library is distributed and deployed.
- Dependency Management 📦: Makes it easier to manage dependencies by packaging all required libraries and resources into one artifact.
- Security 🔒: Protects the code by compiling it into bytecode, which is more challenging to reverse-engineer than raw source code.
Advantages and Disadvantages of Packaging as a Single Artifact ⚖️
Advantages:
- Easier Deployment 🚀: A single file is easier to move, copy, and deploy across environments.
- Consistency 🛡️: Ensures all code, resources, and dependencies are consistent across different deployments.
- Security 🔐: Protects the source code from being directly viewed or modified, as the code is compiled into bytecode and packaged.
Disadvantages:
- Size 📏: Artifacts can become large, particularly EAR files that contain multiple modules, increasing storage and transfer times.
- Lack of Modularity 🧩: A single artifact means that all components are deployed together, even if only a small part of the application has changed, potentially slowing down the deployment process.
Example: Compiling Source Code and Required Plugins into an Artifact 🛠️
Let’s say you have a Maven project for a simple Java application. Here’s a step-by-step process on how Maven compiles and packages the code into a JAR file.
Source Code Structure 📂:
src/main/java/com/example/MyApp.java
: The main application file.src/main/resources/config.properties
: A configuration file.
Maven POM (
pom.xml
) Configuration 📑:- The POM file includes dependencies and plugins required to build and package the application.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>my-app</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- Example dependency --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- Compiler plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
- The POM file includes dependencies and plugins required to build and package the application.
Running Maven Commands 🏃♂️:
Compile: Run
mvn compile
to compile the Java source files.mvn compile
Output:
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /target/classes [INFO] [INFO] BUILD SUCCESS
Package: Run
mvn package
to create a JAR file containing the compiled code and resources.mvn package
Output:
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ my-app --- [INFO] Copying 1 resource [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /target/classes [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ my-app --- [INFO] Building jar: /target/my-app-1.0-SNAPSHOT.jar [INFO] [INFO] BUILD SUCCESS
The final artifact, my-app-1.0-SNAPSHOT.jar
, includes compiled Java classes and the config.properties
file, packaged into a single JAR file in the target
directory ready for deployment or sharing.
4. Introduction to pom.xml
📝
The pom.xml
file (Project Object Model) is the heart of any Maven project. It is an XML file that contains information about the project and configuration details used by Maven to build the project.
Why pom.xml
is Needed for Maven 🔍
- Central Configuration 🔧:
pom.xml
is the central place for managing all the configurations required to build a project. It defines project dependencies, plugins, goals, and other settings in a structured manner. - Plugins / Dependency Management 📦: Specifies all dependencies needed to build, test, and run the project. Maven uses this file to download the necessary libraries from the central or local repository.
- Build Customization 🛠️: Allows customization of the build process through plugins and profiles, which can be defined directly in
pom.xml
. - Versioning and Compatibility 📜: Helps maintain consistency and compatibility between different project modules or dependencies by specifying explicit versions.
Structure of pom.xml
📋
The structure of a pom.xml
file is hierarchical and contains several sections, each serving a specific purpose:
Model Version 🧩: Specifies the version of the POM model. Always set to
4.0.0
for compatibility with Maven 2 and later.<modelVersion>4.0.0</modelVersion>
Group ID 🏷️: Defines the group or organization that the project belongs to. This is usually a reversed domain name (e.g.,
com.example
).<groupId>com.example</groupId>
Artifact ID 🆔: Specifies the unique identifier for the project or module within the group.
<artifactId>my-app</artifactId>
Version 📅: Indicates the version of the artifact. Typically includes a version number and can include labels like
SNAPSHOT
for development versions.<version>1.0-SNAPSHOT</version>
Dependencies 📦: Lists all external libraries that the project depends on. Maven will download these from the specified repositories.
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency> </dependencies>
Build Configuration 🛠️: Configures the build process, including specifying plugins and their configurations.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
Repositories 🌐: Defines remote repositories where Maven can find artifacts. Maven Central is the default, but you can add others if needed.
<repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> </repositories>
Plugins 🔌: Configures plugins that extend Maven’s capabilities, such as compiling code, running tests, and packaging artifacts.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifestEntries> <Built-By>${user.name}</Built-By> <Built-Date>${maven.build.timestamp}</Built-Date> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
Maven Central and Maven Repository 🌐
Maven Central: The primary repository where most public Maven artifacts are stored. When a dependency is declared in the
pom.xml
, Maven first checks the local repository, then Maven Central. It is a large collection of build artifacts available for public use.- URL:
https://repo.maven.apache.org/maven2
- URL:
Maven Repository: Can be local (on your machine), remote (on a server), or central (like Maven Central). Maven searches these repositories in sequence to resolve dependencies.
- Local Repository: Stores artifacts downloaded from remote repositories or built locally. Typically located at
~/.m2/repository
. - Remote Repository: A remote server where artifacts can be stored and shared, often used in team environments or for distributing software.
- Local Repository: Stores artifacts downloaded from remote repositories or built locally. Typically located at
Adding Dependencies from Maven Central 📥
To add a dependency from Maven Central:
Find the Dependency 🔍: Search for the required dependency on Maven Central or a similar repository to get its
groupId
,artifactId
, andversion
.Add to
pom.xml
📑: Include the dependency information in the<dependencies>
section of yourpom.xml
file.<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.5.4</version> </dependency> </dependencies>
Maven Resolves the Dependency 🛠️: When you build your project, Maven will download the specified dependency and its transitive dependencies from Maven Central and add them to your project’s classpath.
mvn compile
- Example Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-dependency-plugin:3.1.2:resolve (default-cli) @ my-app --- [INFO] Resolving dependencies... [INFO] Resolving org.springframework.boot:spring-boot-starter-web:jar:2.5.4 [INFO] Resolving org.springframework.boot:spring-boot-starter-tomcat:jar:2.5.4 [INFO] [INFO] BUILD SUCCESS
- Example Output:
5. Standard Java Directory Structure & Files 📂
The Java directory structure is a standardized format that developers follow to organize their Java projects. This structure helps maintain a clean and predictable organization of files, which is crucial for building and deploying Java applications using tools like Maven.
A typical Java project follows a standard directory structure to keep the source code, resources, and configurations organized. This structure is essential for the project to be correctly processed by build tools like Maven.
Here's a typical directory structure for a Maven-based Java project:
my-java-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── MyApp.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── MyAppTest.java
│ └── resources/
├── target/
├── pom.xml
├── README.md
Root Directory 📁
- The root directory of your project typically contains the
pom.xml
file and other configuration files like.gitignore
. - Example:
my-java-project/ ├── pom.xml ├── src/ ├── target/ └── README.md
- The root directory of your project typically contains the
src
Directory 🗂️- This is the main directory where all the source code and resources are placed.
It typically has two subdirectories:
main
andtest
.src/main/
Directory 📦Purpose: Contains the application’s main code and resources.
Structure:
src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── MyApp.java │ └── resources/ │ └── application.properties
Subfolders:
src/main/java/
☕:- Purpose: The directory where all Java source code resides. This is where your
.java
files (classes, interfaces, enums, etc.) are stored. - Structure: Organized by package names (e.g.,
com/ example
). Each package typically represents a logical grouping of related classes. - Example:
com/example/MyApp.java
is where the main application code resides.
- Purpose: The directory where all Java source code resides. This is where your
src/main/resources/
📜:- Purpose: This folder contains non-Java files, such as configuration files, property files, XML files, or any other resources needed by the application.
- Structure: Files are usually placed directly under the resources directory or within subfolders for better organization.
- Example:
application.properties
is a common configuration file for Java applications, particularly when using frameworks like Spring Boot.
src/main/webapp/
🌐: (For web applications) Contains web-related files like JSP files, HTML, CSS, JavaScript, and other web resources.
src/test/
Directory 🧪- Purpose: Contains the test code and resources.
- Structure:
src/ ├── test/ ├ ├── java/ ├ │ └── com/ ├ │ └── example/ ├ │ └── MyAppTest.java ├ └── resources/
Subfolders:
src/test/java/
☕:- Purpose: Contains the Java source code for test cases. These test cases are used to validate the functionality of the application.
- Structure: Follows the same package structure as
src/main/java
to ensure that tests are easily linked to the corresponding source files. - Example:
com/example/MyAppTest.java
might contain unit tests forMyApp.java
.
src/test/resources/
📜:- Purpose: Stores resources required for testing, such as test configuration files, mock data, or SQL scripts.
- Structure: Similar to
src/main/resources
, files can be organized directly under the directory or in subfolders. - Example: A
test.properties
file used for configuring test-specific settings.
target
Directory 🎯Purpose: This directory is generated by Maven during the build process. It contains all the compiled classes, packaged artifacts (e.g., JAR, WAR), and any other output generated by Maven.
Structure:
target/ ├── classes/ ├── my-app-1.0-SNAPSHOT.jar └── test-classes/
- Subfolders:
target/classes/
📚: Contains compiled.class
file for the main application.target/test-classes/
📚: Contains compiled `.class files for test cases.target/[artifact-name].jar
📦: The packaged JAR file or other build artifacts.
- Subfolders:
pom.xml
📜: The Maven configuration file that describes the project, its dependencies, plugins, and build instructions.README.md
📄: A markdown file explaining the MyApp application & its related data.
Directories Needed for Apache Maven or Its Plugins 🚀
For Maven to work correctly, it expects the source files to be in the correct directories:
src/main/java/
☕: Maven looks here for all the Java source files to compile to generate the bytecode in thetarget/classes/
directory.src/main/resources/
📜: Maven includes all files in this directory in the final artifact. This is crucial for configuration files likeapplication.properties
.src/test/java/
☕: Maven looks here for test code to execute during thetest
phase.src/test/resources/
📜: Any test-specific resources are expected to be here, and Maven will include them in the test classpath.target
📦: Created by Maven during the build process to store compiled classes and packaged artifacts.pom.xml
📜: Mandatory for defining the Maven build configuration, dependencies, and plugins.
These directories are crucial because Maven's default conventions depend on this structure. If the structure is not followed, Maven will require additional configuration to locate and compile the files.
application.properties
File 📑
The application.properties
file is typically located in the src/main/resources/
directory. It’s a key configuration file in Java applications, especially those using frameworks like Spring Boot.
Purpose: This file contains application-specific properties such as database configurations, server ports, and other settings. It allows externalizing the configuration from the code, making the application more flexible and easier to manage in different environments.
Structure: The file consists of key-value pairs, each representing a specific configuration setting. The format is straightforward and easy to read.
Example Content:
# Server configuration server.port=8080 # Database configuration spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=password # Logging configuration logging.level.org.springframework=INFO
Usage:
- Configuring Application Behavior: Developers use
application.properties
to customize the behavior of their application based on different environments (development, testing, production). - Externalizing Configuration: By keeping settings in an external file, changes can be made without modifying the source code, allowing for more flexible deployments.
- Configuring Application Behavior: Developers use
6. Installation Requirements: JDK, JRE, JVM ☕️
Before installing Maven, you need to ensure that the Java Development Kit (JDK), Java Runtime Environment (JRE), and Java Virtual Machine (JVM) are properly installed. These components are essential for running Java applications and building Java projects using Maven.
JDK, JRE, and JVM: What Are They? 🤔
JDK (Java Development Kit) 🧰
- Purpose: The JDK is a software development environment used for developing Java applications. It includes tools for compiling, debugging, and running Java programs.
- Why Install: Developers need the JDK to write and compile Java programs. It provides all the necessary tools and libraries required for Java development.
- Components:
- Java Compiler (
javac
): Converts Java source code into bytecode. - JRE: Included within the JDK for running Java programs.
- Development Tools: Includes tools like
javadoc
,javap
, etc.
- Java Compiler (
JRE (Java Runtime Environment) 🏃♂️
- Purpose: The JRE is a software package that provides the libraries and other components necessary to run Java applications. It does not include development tools like compilers or debuggers.
- Why Install: The JRE is essential for running Java applications on end-user systems. It allows users to execute Java programs without needing the full JDK.
- Components:
- JVM: The core part of the JRE that executes the Java bytecode.
- Libraries: A set of class libraries that Java applications rely on.
JVM (Java Virtual Machine) 💻
- Purpose: The JVM is the virtual machine that runs Java bytecode. It is platform-independent, meaning the same Java code can run on any device with a compatible JVM.
- Why Install: Integral to both the JDK and JRE, the JVM allows Java applications to be platform-independent. Developers rely on the JVM to ensure that Java applications can run anywhere.
- Components:
- Class Loader: Loads Java classes into memory.
- Bytecode Verifier: Ensures the bytecode is valid and safe to execute.
- Interpreter/Just-In-Time Compiler: Executes the bytecode, translating it into machine code for the host system.
Software Structure for JDK, JRE, JVM in Tree Format 🌳
Here’s a simplified tree structure that outlines how these components are organized:
JDK (Java Development Kit)
│
├── bin/ (Binaries)
│ ├── javac (Java compiler)
│ ├── java (Java interpreter)
│ └── other tools (javadoc, jdb, etc.)
│
├── jre/ (Java Runtime Environment)
│ ├── bin/
│ │ └── java (JVM executable)
│ └── lib/
│ ├── rt.jar (Runtime libraries)
│ └── other runtime libraries
│
└── lib/ (Development Libraries)
├── tools.jar (Tools libraries)
└── other development libraries
- JDK: Contains everything needed for Java development, including the JRE, compiler, and other tools.
- JRE: A subset of the JDK that includes just the JVM and libraries needed to run Java applications.
- JVM: Part of the JRE, responsible for executing Java bytecode.
7. JDK Version Compatibility 🔄
When using Maven for building Java projects, selecting the correct version of the JDK is crucial. Maven relies on the JDK to compile and package Java applications, and not all JDK versions are compatible with every project or environment.
Why Only Selected Versions of JDK Work for Maven Packaging 🧐
Java Version Compatibility 📋: Maven projects are configured to use a specific version of Java. This is set in the
pom.xml
file using themaven-compiler-plugin
. If the installed JDK does not match the version specified in thepom.xml
, the build may fail.Compiler Differences 🧮: Different JDK versions have different compilers that might produce incompatible bytecode or have different performance characteristics. For example, Java 8 introduced significant changes in the language and compiler, which might not be compatible with earlier versions.
Library Dependencies 📚: Some libraries or frameworks used in the project might require a specific JDK version. Using an incompatible version could lead to
ClassNotFoundException
orNoSuchMethodError
.API Changes ⚙️: Different versions of the JDK can introduce or remove APIs, leading to compatibility issues with existing code. For instance, certain deprecated APIs might be removed in newer versions, causing compilation errors.
Bytecode Compatibility 📉: The bytecode generated by newer versions of the JDK might not be compatible with older JVMs. This is controlled by the
-source
and-target
options in themaven-compiler-plugin
.Language Features 📚: New language features (e.g., lambda expressions in JDK 8, modules in JDK 9) require a specific JDK version. Maven needs to compile your code with the appropriate version that supports these features.
Example of JDK Version Compatibility 🚦
Let’s say your project uses a library that is compatible only with JDK 11. If you try to build this project using JDK 8, you might encounter issues due to changes in the Java language or removed APIs.
Maven Compiler Plugin Configuration in Project’s
pom.xml
:<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> </plugins> </build>
Output When Building with JDK 8:
- Command:
mvn clean install
- Output:
[INFO] ------------------------------------------------------------- [ERROR] COMPILATION ERROR : [INFO] ------------------------------------------------------------- [ERROR] Source option 11 is not supported. Use 8 or lower. [ERROR] Target option 11 is not supported. Use 8 or lower. [INFO] 2 errors [INFO] -------------------------------------------------------------
- Command:
Output When Building with JDK 11:
- Command:
mvn clean install
- Output:
[INFO] ------------------------------------------------------------- [INFO] BUILD SUCCESS [INFO] -------------------------------------------------------------
- Command:
Solution: In this example, the project fails to build with JDK 8 because it’s configured for JDK 11. However, it builds successfully when the correct JDK version is used. Ensure that the correct JDK version is installed and configured for the project to avoid such compatibility issues.
Difference Between OpenJDK and Oracle JDK ⚖️
- OpenJDK 🆓: An open-source implementation of the Java Platform, Standard Edition under the GNU General Public License (GPL) with a linking exception. This makes it free to use, modify, and distribute. It’s free to use and has the same codebase as Oracle JDK.
- Oracle JDK 💼: Oracle’s proprietary implementation of the Java Platform, Standard Edition, built from the OpenJDK project but with additional commercial features.
- Differences:
- Licensing: Oracle JDK comes with a commercial license for enterprises, whereas OpenJDK is free under an open-source license.
- Performance: Oracle JDK might have slight performance optimizations and additional monitoring tools compared to OpenJDK.
- Differences:
8. The .m2
Directory 📁
The .m2
directory is a hidden folder located in the user’s home directory (~/.m2
) that Maven uses to store its repository of downloaded dependencies, plugin files, and other build-related information.
What is the .m2
Directory? 🗂️
- Purpose: The
.m2
directory is the default location for Maven’s local repository. It stores all downloaded dependencies, plugins, and cached build information. - Location: By default, this directory is located in the user's home directory (
~/.m2
on Unix-based systems orC:\Users\<username>\.m2
on Windows).
When is the .m2
Directory Created? 📅
- The
.m2
directory is created automatically the first time Maven is run. Maven will create the necessary subdirectories and configuration files, such assettings.xml
and therepository
folder. When Maven downloads dependencies or plugins, it caches them in this directory for future use, eliminating the need to re-download them for every build.
Contents of the .m2
Folder 🗄️
repository
📦: This is the most crucial subdirectory within.m2
. It contains all the downloaded JAR files, libraries, plugins, and other artifacts that Maven retrieves from remote repositories.- Structure:
~/.m2/ ├── repository/ │ ├── com/ │ │ └── example/ │ │ └── my-library/ │ │ └── 1.0/ │ │ └── my-library-1.0.jar │ └── org/ │ └── apache/ │ └── commons/ │ └── commons-lang3/ │ └── 3.10/ │ ├── commons-lang3-3.10.jar │ └── commons-lang3-3.10.pom └── settings.xml
- Significance 📥: The
repository
folder allows Maven to quickly access dependencies that have already been downloaded, significantly speeding up the build process by avoiding repeated downloads.
- Structure:
settings.xml
⚙️: A configuration file that allows users to customize Maven's behavior, such as specifying proxy settings, mirror repositories, or different local repository locations.
Where Does Maven Store Its Dependencies? 📦
Dependency Storage: Maven stores all dependencies in the
~/.m2/repository
folder. Each dependency is stored in a specific path based on its group ID, artifact ID, and version.Example:
- Dependency:
org.apache.commons:commons-lang3:3.12.0
- Stored At:
~/.m2/repository/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar
- Dependency:
Significance of the .m2
Folder for Build Performance 🚀
Performance Benefits: By caching all dependencies and plugins locally, the
.m2
folder prevents Maven from repeatedly downloading the same files for every build, drastically reducing build times, especially in environments with slow or limited internet access.- Example: If a project requires
junit:junit:4.13.1
, Maven will first check~/.m2/repository/junit/junit/4.13.1
for the JAR file before attempting to download it from a remote repository.
- Example: If a project requires
Reduced Build Time: If Maven has already downloaded and stored a dependency in the
.m2
directory, it can retrieve it directly from the local repository, speeding up subsequent builds.
9. Where is the Final Artifact Created? 🎁
Final Artifact Location: When Maven completes the build process, it places the final artifact (e.g., a JAR or WAR file) in the
target
directory of the project.Example:
my-java-project/ ├── pom.xml ├── src/ ├── target/ │ ├── my-java-project-1.0-SNAPSHOT.jar │ └── ...
Project Directory:
/my-java-project/
- Artifact:
my-java-project-1.0-SNAPSHOT.jar
- Location:
/my-java-project/target/my-java-project-1.0-SNAPSHOT.jar
This target/
directory is where Maven places all output generated during the build process, including compiled classes, packaged archives, and temporary files.
This structure ensures a clean separation between source files, compiled classes, and packaged artifacts, making the Maven build process efficient and organized.
10. Amazon Linux 2023 Environment: Setting Up Java and Maven 🖥️
Setting up a development environment on Amazon Linux 2023 requires careful attention to detail, especially when installing Java and Maven. When setting up Java and Maven in an Amazon Linux 2023 environment, you have two main options for Java Development Kits (JDK): OpenJDK and Oracle JDK.
1. Choosing Between OpenJDK and Oracle JDK ☕️
Java developers can choose between OpenJDK (an open-source implementation of the Java Platform) and Oracle JDK (a commercially supported, proprietary implementation by Oracle) depending on your project's requirements. It's essential to decide which JDK to use based on licensing, support, and specific features required.
Important Note: You should not install both OpenJDK and Oracle JDK simultaneously on the same machine. Doing so can lead to conflicts in the Java runtime environment, causing unexpected behavior in Java applications.
2. Downloading JDKs Using wget
📥
Connect to Your AWS Instance: Log in to your Amazon Linux 2023 instance as the root user
or a user with sudo
privileges.
Downloading OpenJDK 8 🆓
Open a Terminal Session as Root User:
- It’s essential to have root privileges to install software in
/opt
or other system directories.
- It’s essential to have root privileges to install software in
Navigate to the
/opt
Directory:- The
/opt
directory is used for installing software packages that are not managed by the system’s package manager. This keeps them isolated from system software and avoids potential conflicts.cd /opt
- The
Download OpenJDK 8 Using
wget
:- Use the
wget
command to download the OpenJDK 8 tarball. - Use
-P /opt
: Saves the downloaded file in the/opt
directory (optional, if you are in another directory).wget https://download.java.net/openjdk/jdk8u44/ri/openjdk-8u44-linux-x64.tar.gz -P /opt
- The above URL is an example; you may need to check for the latest versions or mirrors for OpenJDK 8.
- Use the
Extract the Downloaded Tarball:
- Use the
tar
command to extract the downloaded.tar.gz
file.tar -xvzf /opt/openjdk-8u44-linux-x64.tar.gz -C /opt
- Use
-C /opt
: Specifies the directory to extract to (optional, if you are in another directory).
- Use the
Downloading Oracle JDK 8 💼
Navigate to the
/opt
Directory:cd /opt
Download Oracle JDK 8 Using
wget
:- Oracle requires users to accept their license agreement before downloading the JDK. For this, you might need to manually download the file from Oracle's website or use a script with cookies enabled. You can bypass this by using a pre-signed link (only for demonstration purposes).
wget --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz -P /opt
- Oracle requires users to accept their license agreement before downloading the JDK. For this, you might need to manually download the file from Oracle's website or use a script with cookies enabled. You can bypass this by using a pre-signed link (only for demonstration purposes).
Explanation:
--no-cookies
and--no-check-certificate
: Bypasses restrictions on the Oracle website.--header "Cookie: oraclelicense=accept-securebackup-cookie"
: Accepts the Oracle license automatically.
Extract the Oracle JDK Tarball:
tar -xvzf /opt/jdk-8u131-linux-x64.tar.gz -C /opt
3. Using yum
Package Manager vs. wget
🆚
wget
for Manual Downloads:- Downloads a specific version of JDK directly from the web.
- Gives you full control over the installation and version management.
- Suitable when you need a specific version or when managing dependencies manually.
yum
Package Manager:- Uses the default package manager for Red Hat-based systems.
- Automatically handles dependencies.
- Downloads the latest available version in the repository, which might not be the version you need.
4. Downloading the Latest Version of Maven Using wget
🌐
Navigate to the
/opt
Directory:cd /opt
Download the Latest Maven Version:
- First, check Maven’s official website for the latest version and download it using
wget
.wget https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz -P /opt
- First, check Maven’s official website for the latest version and download it using
Extract the Maven Tarball:
tar -xvzf /opt/apache-maven-3.8.8-bin.tar.gz -C /opt
5. Why Use /opt
for External Downloads? 📂
- Isolation: The
/opt
directory is designated for installing optional software packages that are not part of the default operating system installation. It’s an ideal location for external software. This keeps them separate from system-managed files in directories like/usr
. - Control: By installing in
/opt
, administrators have more control over software versions and configurations, preventing package managers from overwriting custom installations.
6. Verify Installation and Check Versions ✅
Check Java Version:
- After extracting the JDK, check the installed Java version.
/opt/openjdk-8u44-linux-x64/bin/java -version #For OpenJDK /opt/jdk1.8.0_131/bin/java -version #For OracleJDK
- Example Output (For OracleJDK):
java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
Check Maven Version:
- Verify Maven installation by checking its version
(Do this step after configuring the environment variables as mentioned below)
/opt/apache-maven-3.8.8/bin/mvn -version
- Example Output:
Apache Maven 3.8.8 (4c87b05d9aedce574290d1acc98575ed5eb6cd39) Maven home: /opt/apache-maven-3.8.8 Java version: 1.8.0_131, vendor: Oracle Corporation, runtime: /opt/jdk1.8.0_131/jre Default locale: en, platform encoding: UTF-8 OS name: "linux", version: "6.1.102-111.182.amzn2023.x86_64", arch: "amd64", family: "unix"
- Verify Maven installation by checking its version
7. Configuring Environment Variables 🌐
What is /etc/profile
? 🗒️
/etc/profile
is a system-wide configuration file used to set environment variables for all users. It’s executed by the shell at login and is ideal for setting up environment variables likePATH
,JAVA_HOME
, andMAVEN_HOME
.- This file is ideal for setting up Java and Maven paths because it ensures that all users and processes have access to these settings without needing individual configurations.
What is echo $PATH
? 📢
- The
echo $PATH
command displays the current value of thePATH
environment variable. ThePATH
variable tells the shell where to look for executable files when a command is issued.
Adding Environment Variables to /etc/profile
⚙️
Open
/etc/profile
:sudo vi /etc/profile
Add the following lines (use any one JDK only) at the end of the file:
export JAVA_HOME=/opt/openjdk-8u44-linux-x64 #For OpenJDK export JAVA_HOME=/opt/jdk1.8.0_131 #For OracleJDK export MAVEN_HOME=/opt/apache-maven-3.8.8 export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
Explanation:
JAVA_HOME
andMAVEN_HOME
: Specifies the installation directories.M2_HOME
: TheM2_HOME
environment variable points to the Maven installation directory. By adding Maven’sbin
directory toPATH
, you ensure that Maven commands (mvn
) can be run from anywhere on the command line.PATH
: Updates the PATH variable to include the Java and Maven bin directories.
Why Use JAVA_HOME
and Not Other Parameters? 🧐
JAVA_HOME
is a standard environment variable used by various Java applications and tools to locate the Java installation directory. Most build tools (like Maven) and IDEs (like Eclipse or IntelliJ) useJAVA_HOME
to know where to find the JDK.- Alternative Parameters: Other parameters like
JRE_HOME
orCLASSPATH
are less commonly used and might not be recognized by all tools or might not serve the same purpose.JAVA_HOME
is the universally recognized standard for pointing to a JDK installation. - M2_HOME We can use parameter
M2_HOME
instead ofMAVEN_HOME
while exporting the maven path.
Retaining Environment Settings After Reboot 🔄
To ensure that environment settings persist after a session ends or the system restarts, adding them to /etc/profile
is effective because this file is executed whenever a login shell starts.
Persisting Settings Across Reboots:
- Global Changes: Modifications to
/etc/profile
apply globally to all users and persist across reboots. - User-Specific Changes: If you want changes to be user-specific, you can add them to the
~/.bash_profile
or~/.bashrc
files in the user's home directory.
To ensure the environment variables are set for all future sessions:
Reload the Profile: Exit the current session & re-login.
Verify the Variables:
echo $JAVA_HOME echo $MAVEN_HOME
You can also verify by entering the Java & Maven commands at any path apart from its bin location,
java -version #For JDK mvn -version #For Maven
8. What is an Archetype in Maven? 🧩
Archetype: A Maven archetype is a template project provided by Maven to help developers quickly set up a new project with a standard directory structure, a basic
pom.xml
, and other necessary files. This ensures consistency and saves time when starting new projects.Generating a Simple Web App with
archetype:generate
command 🌐The
archetype:generate
goal generates a new Maven project based on an archetype.Example Command:
mvn archetype:generate -DgroupId=com.example -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
Explanation:
archetype:generate
: Command to generate a new project from an archetype.-DgroupId
,-DartifactId
: Specifies the project’s group and artifact IDs.-DarchetypeArtifactId
: Specifies the archetype to use (e.g.,maven-archetype-webapp
for a web application).-DinteractiveMode=false
: Runs the command without prompting for input.
Linux and Windows: The command is the same for both operating systems when using Maven.
This command initializes a new project in the my-webapp
directory, using the maven-archetype-webapp
archetype to set up a basic web application.
11. Sample Web Application in Amazon Linux 2023 Environment Deployed in Tomcat 🌐
1. What is Tomcat? 🐱💻
Tomcat, also known as Apache Tomcat, is an open-source web server and servlet container that serves as a crucial component in the Java web development ecosystem. It allows developers to deploy and run Java-based web applications, such as Java Servlets and JavaServer Pages (JSPs). Essentially, Tomcat provides an environment for executing Java code in response to web requests, making it a vital tool for hosting and managing Java web applications. 🌐
Why is Tomcat Important? 🤔
- Open Source: It is freely available and has a strong community supporting it.
- Java Web Application Hosting: Tomcat is popular for its stability and wide adoption, making it the go-to choice for hosting Java web applications. 💻
- Integration with Java Frameworks: It integrates seamlessly with Java frameworks like Spring and Hibernate, enabling powerful, scalable web applications. ⚙️
- Scalability: Tomcat can scale from simple web applications to large enterprise-level applications. 📈
- Customization and Extensibility: Tomcat is highly customizable, allowing developers to tweak it according to their project needs. 🛠️
- Lightweight: Compared to full-fledged Java EE application servers like JBoss or WebSphere, Tomcat is lightweight and has a smaller footprint.
In summary, Tomcat acts as a middle layer (middleware) between the web client (browser) and the Java-based server application, handling requests and responses efficiently. 🌟
How it Works:
- Client Requests: Receives HTTP / HTTPS requests from clients.
- Servlets/JSPs: Processes these requests using servlets and JSPs.
- Response: Sends the processed response back to the client.
2. Maven Builds and Deployment in Tomcat 🛠️
Maven is a build automation tool used primarily for Java projects. It manages project builds, dependencies, and documentation. When deploying to Tomcat, Maven can automate the build and deployment process using plugins. 🚀
Maven Build Process:
- Project Setup: Maven uses a
pom.xml
file to manage project dependencies, configurations, and plugins. - Compile Code: Maven compiles Java code using the dependencies listed in
pom.xml
. - Run Tests: Maven runs any tests to ensure code quality and functionality.
- Package Application: Maven packages the compiled code and resources into a WAR (Web Application Archive) file. This WAR file is what gets deployed to Tomcat.
Using Maven to Deploy to Tomcat:
- Project Setup: Define your project and dependencies in the
pom.xml
file. - Build Lifecycle: Maven follows a defined lifecycle to build your project, which includes compiling, testing, packaging, and deploying.
- WAR File: For web applications, Maven builds a
.war
(Web Application Archive) file which contains all the necessary files to deploy a web application. - Deployment Plugin: Use the Maven Tomcat plugin (
tomcat-maven-plugin
) to deploy the.war
file to the Tomcat server.
Example pom.xml
Configuration:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>TomcatServer</server>
<path>/my-webapp</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
<url>
: The URL of the Tomcat manager.<server>
: The ID of the server credentials defined insettings.xml
in the tomcat configuration directory.<path>
: The context path where the application will be deployed.
Build the Project: Use Maven to build your project into a WAR (Web Application Archive) file.
mvn clean package
This command cleans the previous builds and packages the application into a WAR file located in the target
directory. 📦
Deploy the WAR: Deploy the WAR file to Tomcat using Maven.
mvn tomcat7:deploy
Note:
- We can run the clean, package & deploy command simultaneously like
mvn clean package tomcat7:deploy
& it is suggested to package the application before deploying. Before running the above command we need to configure
settings.xml
for accessing manager access. In our actual deployment mentioned below we will manually do it, so this process is optional.This command uploads the WAR file to Tomcat’s webapps directory and deploys it. 🚀
3. Tomcat Folder Structure and Its Uses 📂
Understanding Tomcat's folder structure is essential for effectively managing and configuring the server. Let's break down the key directories and their purposes. 📁
apache-tomcat-x.x.x/
│
├── bin/ # Contains startup scripts and utility programs.
│ ├── catalina.sh # Script to start/stop Tomcat (Unix/Linux)
│ ├── catalina.bat # Script to start/stop Tomcat (Windows)
│ └── tomcat-juli.jar# Utility JAR for logging.
│
├── conf/ # Configuration files for Tomcat.
│ ├── server.xml # Main configuration file where you define connectors, engines, etc.
│ ├── web.xml # Global web application configuration.
│ ├── tomcat-users.xml # User roles and permissions.
│ └── context.xml # Configuration specific to individual applications.
│
├── lib/ # Libraries required by Tomcat itself.
│ ├── catalina.jar # Core Tomcat classes.
│ ├── tomcat-api.jar # API classes.
│ └── servlet-api.jar # Servlet API.
│
├── logs/ # Log files generated by Tomcat.
│ ├── catalina.out # Main log file.
│ ├── localhost.log # Logs specific to the localhost.
│ └── manager.log # Logs related to the Tomcat Manager.
│
├── webapps/ # Default web applications and where your deployed apps go.
│ ├── ROOT/ # Default web application served at the root URL.
│ └── examples/ # Example applications (useful for testing).
│
├── work/ # Temporary files and compiled JSPs.
│ ├── Catalina/ # Compiled classes for individual web applications.
│ └── localhost/ # Temporary files for the localhost.
│
└── temp/ # Temporary files created by Tomcat.
└── work/ # Temporary files created by Tomcat for internal use.
Explanation of Key Directories: 📁
/bin
: 📁- Purpose: Contains scripts for starting and stopping Tomcat.
- Key Files:
startup.sh
/startup.bat
: Starts the Tomcat server.shutdown.sh
/shutdown.bat
: Stops the Tomcat server.
/conf
: 📁- Purpose: Houses all the configuration files for Tomcat.
- Key Files:
server.xml
: Main configuration file for the server.web.xml
: Default configuration for web applications.tomcat-users.xml
: Manages user roles and access controls.
/lib
: 📁- Purpose: Contains Java libraries (JAR files) needed by Tomcat and web applications.
- Usage: Place any additional JAR files here to make them available to all web applications.
/logs
: 📁- Purpose: Stores log files for monitoring server activity.
- Key Logs:
catalina.out
: Primary log file for Tomcat.localhost_access_log.*
: Access logs that record incoming requests.
/temp
: 📁- Purpose: Temporary storage used by Tomcat during operations.
/webapps
: 📁- Purpose: Default deployment directory for web applications.
- Usage: Deploy WAR files here for automatic deployment by Tomcat.
ROOT/
: The default web application that is served when accessing the root URL.myapp/
: An example directory where your custom web applications are deployed.
/work
: 📁- Purpose: Contains temporary files and compiled JSPs. This directory is used for runtime storage and is usually cleared out automatically.
4. Amazon Linux 2023 Environment Setup 🐧
To deploy a Java web application on Tomcat, we need to set up the environment on Amazon Linux 2023. Here's how you do it step by step:
We will be using,
- Oracle JDK 8
- Maven available latest version
- Tomcat version 8
1. Install Oracle JDK 8 ☕️
The Java Development Kit (JDK) is necessary for compiling and running Java applications.
Command:
wget --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz -P /opt
- Purpose: Download Oracle JDK 8 Update 131.
- Options:
--no-cookies
and--no-check-certificate
: Bypass certificate checks and cookie requirements.--header "Cookie: oraclelicense=accept-securebackup-cookie"
: Accept Oracle's licensing terms.-P /opt
: Save the file in the/opt
directory.
Command:
tar -xvzf /opt/jdk-8u131-linux-x64.tar.gz -C /opt
- Purpose: Extract the downloaded JDK tarball into
/opt
. - Options:
-xvzf
: Extract (x
), verbose (v
), gzip (z
), file (f
).-C /opt
: Change to/opt
directory before extracting.
2. Install Apache Maven 🚀
Maven is used to build and manage Java projects.
Command:
wget https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz -P /opt
- Purpose: Download Apache Maven 3.8.8.
- Options:
-P /opt
: Save the file in the/opt
directory.
Command:
tar -xvzf /opt/apache-maven-3.8.8-bin.tar.gz -C /opt
- Purpose: Extract the Maven tarball into
/opt
. - Options:
-xvzf
: Extract (x
), verbose (v
), gzip (z
), file (f
).-C /opt
: Change to/opt
directory before extracting.
3. Install Apache Tomcat 🐱
Tomcat will serve as our servlet container.
wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.1/bin/apache-tomcat-8.0.1.tar.gz -P /opt
- Purpose: Download Apache Tomcat 8.0.1.
Options:
-P /opt
: Save the file in the/opt
directory.
tar -xvzf /opt/apache-tomcat-8.0.1.tar.gz -C /opt
- Purpose: Extract the Tomcat tarball into
/opt
. - Options:
-xvzf
: Extract (x
), verbose (v
), gzip (z
), file (f
).-C /opt
: Change to/opt
directory before extracting.
4. Set Up Environment Variables 🌍
To make Java, Maven, and Tomcat accessible system-wide, we set up environment variables.
echo "export JAVA_HOME=/opt/jdk1.8.0_131 #For OracleJDK" >> /etc/profile
echo "export MAVEN_HOME=/opt/apache-maven-3.8.8" >> /etc/profile
echo 'export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin' >> /etc/profile
echo
: Adds environment variable settings to/etc/profile
.JAVA_HOME
: Points to the JDK installation directory.MAVEN_HOME
: Points to the Maven installation directory.PATH
: Updates the systemPATH
to include Java and Maven binaries.echo 'export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin'
: Add the JDK and Maven bin directories to thePATH
, ensuring their executables can be run from anywhere.
5. Install tree
Utility 🌳
The tree
command is useful for displaying directory structures.
yum install tree -y
yum install tree -y
: Installs thetree
utility on Amazon Linux.
6. Verification of installed binaries 🛠️
Once the above binaries are installed, logout of the session or user & login in Terminal again for changes to get effected & check the versions,
1. For Java
,
Command:
java -version
Output:
Oracle Java:
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
2. For Maven
Command:
mvn -version
Output:
Apache Maven 3.8.8 (4c87b05d9aedce574290d1acc98575ed5eb6cd39)
Maven home: /opt/apache-maven-3.8.8
Java version: 1.8.0_131, vendor: Oracle Corporation, runtime: /opt/jdk1.8.0_131/jre
Default locale: en, platform encoding: UTF-8
OS name: "linux", version: "6.1.102-111.182.amzn2023.x86_64", arch: "amd64", family: "unix"
3. For Tomcat
,
Command:
/opt/apache-tomcat-8.0.1/bin/version.sh
Output:
Using CATALINA_BASE: /opt/apache-tomcat-8.0.1
Using CATALINA_HOME: /opt/apache-tomcat-8.0.1
Using CATALINA_TMPDIR: /opt/apache-tomcat-8.0.1/temp
Using JRE_HOME: /opt/jdk1.8.0_131
Using CLASSPATH: /opt/apache-tomcat-8.0.1/bin/bootstrap.jar:/opt/apache-tomcat-8.0.1/bin/tomcat-juli.jar
Server version: Apache Tomcat/8.0.1
Server built: Jan 29 2014 11:13:21
Server number: 8.0.1.0
OS Name: Linux
OS Version: 6.1.102-111.182.amzn2023.x86_64
Architecture: amd64
JVM Version: 1.8.0_131-b11
JVM Vendor: Oracle Corporation
7. Java Source Code and Application Analysis 💻
Now, let's dive into the actual Java code, directory structure, and how the application is organized and works. 🚀
This Java web application showcases a basic blog management system using Servlets and JSP. It includes setup instructions, Maven configurations, Java code, and JSP pages. The application structure and files are designed to facilitate both development and testing, ensuring that the web app functions as intended.
Project Directory Structure 📂
Create Project directories
mkdir -p ~/advanced-java-webapp/{src/main/{java/com/example/webapp/{servlet,views,model},resources,webapp/WEB-INF/views},src/test/java}
mkdir -p ~/advanced-java-webapp/src/test/java/com/example/webapp/{servlet,model}
Here's how the project is organized:
~/advanced-java-webapp
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── webapp
│ │ ├── model
│ │ │ └── BlogPost.java
│ │ ├── servlet
│ │ │ └── HomeServlet.java
│ │ └── views
│ ├── resources
│ └── webapp
│ ├── WEB-INF
│ │ ├── views
│ │ │ └── home.jsp
│ │ └── web.xml
│ └── index.jsp
└── test
└── java
└── com
└── example
└── webapp
├── model
│ └── BlogPostTest.java
└── servlet
└── HomeServletTest.java
Directory Structure Overview
The directory structure of your web application project is carefully organized to follow the Maven Standard Directory Layout, which simplifies project management and builds processes.
Here's a breakdown of your project's directory structure:
~/advanced-java-webapp/
: Root directory for the project.src/main/java
: Contains the Java source code for your application.com/example/webapp/servlet
: Holds the servlets that handle client requests and generate responses.com/example/webapp/views
: Would typically hold Java classes for view-related logic (if needed).com/example/webapp/model
: Contains Java classes representing the application's data model (e.g.,BlogPost
).
src/main/resources
: Contains configuration files and resources such as property files or XML configurations needed at runtime.src/main/webapp
: The web application root directory, containing all web-related resources.WEB-INF
: Contains theweb.xml
deployment descriptor and JSP files underWEB-INF/views
directory to restrict direct access.
src/test/java
: Contains Java test classes for unit and integration testing.com/example/webapp/servlet
: Tests for servlets.com/example/webapp/model
: Tests for model classes.
Detailed Explanation of Each File in ~/advanced-java-webapp/
directory
1. pom.xml
This file is crucial for Maven builds. It specifies the project structure, dependencies, plugins, and configuration settings. The dependencies are essential for developing and running a web application using Servlets and JSP. The plugins manage the build lifecycle and deployment to Tomcat.
Command:
vi ~/advanced-java-webapp/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>advanced-java-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<!-- Servlet API dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- JSP API dependency -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!-- JSTL dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Mockito dependency for testing -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<!-- JUnit dependency for testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>advanced-java-webapp</finalName>
<plugins>
<!-- Maven WAR Plugin for packaging the application -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warName>advanced-java-webapp</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- Tomcat Maven Plugin for deploying to Tomcat -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/advanced-java-webapp</path>
</configuration>
</plugin>
<!-- Maven Surefire Plugin for running tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
</project>
Explanation:
Content Breakdown:
Certainly! Here’s a more detailed breakdown of the pom.xml
file located at ~/advanced-java-webapp/pom.xml
:
Root Element
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project>
: This is the root element of the POM file, defining the project model.xmlns
: XML namespace for the POM schema, specifying the default namespace for elements in the POM.xsi:schemaLocation
: Provides the location of the XML Schema Definition (XSD) for validation. This tells XML parsers where to find the schema that defines the structure and constraints of the POM file.
Model Version
<modelVersion>4.0.0</modelVersion>
<modelVersion>
: Specifies the version of the POM model to use.4.0.0
is the current version and is required for all POM files.
Project Identification
<groupId>com.example</groupId>
<artifactId>advanced-java-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<groupId>
: Defines the group or organization that the project belongs to. Typically a reversed domain name to ensure uniqueness (e.g.,com.example
).<artifactId>
: The name of the project artifact. This is the name of the JAR or WAR file without the version number (e.g.,advanced-java-webapp
).<version>
: The version of the project.1.0-SNAPSHOT
indicates that this is a snapshot version, meaning it is a work-in-progress and not a final release.<packaging>
: Specifies the type of artifact to produce.war
stands for Web Application Archive, which is used for web applications.
Properties
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<properties>
: Defines project-wide properties that can be referenced elsewhere in the POM.<project.build.sourceEncoding>
: Sets the character encoding for source files to UTF-8, ensuring proper handling of text.<maven.compiler.source>
: Specifies the version of the Java source code to use (Java 1.8).<maven.compiler.target>
: Specifies the version of the Java bytecode to generate (Java 1.8).<failOnMissingWebXml>
: Determines whether to fail the build if theweb.xml
file is missing. Set tofalse
to allow the build to proceed without this file.
Dependencies
<dependencies>
<!-- Servlet API dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- JSP API dependency -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!-- JSTL dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Mockito dependency for testing -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<!-- JUnit dependency for testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencies>
: Lists all the dependencies required for the project.- Servlet API:
<dependency>
:<groupId>
:javax.servlet
<artifactId>
:javax.servlet-api
<version>
:3.1.0
<scope>
:provided
– This means the servlet API is expected to be provided by the runtime environment (e.g., Tomcat) and is not included in the WAR file.
- JSP API:
<dependency>
:<groupId>
:javax.servlet.jsp
<artifactId>
:javax.servlet.jsp-api
<version>
:2.3.1
<scope>
:provided
– Similar to the Servlet API, the JSP API is provided by the server.
- JSTL:
<dependency>
:<groupId>
:javax.servlet
<artifactId>
:jstl
<version>
:1.2
– Provides the JavaServer Pages Standard Tag Library (JSTL).
- Mockito:
<dependency>
:<groupId>
:org.mockito
<artifactId>
:mockito-core
<version>
:3.12.4
<scope>
:test
– This dependency is used for writing unit tests and is included only in the test classpath.
- JUnit:
<dependency>
:<groupId>
:junit
<artifactId>
:junit
<version>
:4.13.2
<scope>
:test
– This dependency is used for writing and running unit tests.
- Servlet API:
Build Configuration
<build>
<finalName>advanced-java-webapp</finalName>
<plugins>
<!-- Maven WAR Plugin for packaging the application -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warName>advanced-java-webapp</warName>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- Tomcat Maven Plugin for deploying to Tomcat -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/advanced-java-webapp</path>
</configuration>
</plugin>
<!-- Maven Surefire Plugin for running tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
<build>
: Configures how the project is built and packaged.<finalName>
: Specifies the name of the final WAR file produced by the build. It will be namedadvanced-java-webapp.war
.<plugins>
: Lists the plugins used in the build process.- Maven WAR Plugin:
<plugin>
:<groupId>
:org.apache.maven.plugins
<artifactId>
:maven-war-plugin
<version>
:3.3.1
– Manages the creation of WAR files.<configuration>
:<warName>
: Sets the name of the WAR file.<failOnMissingWebXml>
: Allows the build to succeed even if theweb.xml
is missing, which is useful for servlet 3.0+ applications that might not require aweb.xml
.
- Tomcat Maven Plugin:
<plugin>
:<groupId>
:org.apache.tomcat.maven
<artifactId>
:tomcat7-maven-plugin
<version>
:2.2
– Facilitates deploying the application to Tomcat.<configuration>
:<path>
: Sets
- Maven WAR Plugin:
the context path for deployment in Tomcat. The application will be accessible at
/advanced-java-webapp
.- Maven Surefire Plugin:
<plugin>
:<groupId>
:org.apache.maven.plugins
<artifactId>
:maven-surefire-plugin
<version>
:3.0.0-M5
– Used for running unit tests during the build process.
Summary
The pom.xml
file for the advanced-java-webapp
project defines:
- Project Metadata: Group ID, artifact ID, version, and packaging type (WAR).
- Build Properties: Source and target Java versions, character encoding, and handling of missing
web.xml
. - Dependencies: Includes Servlet API, JSP API, JSTL, Mockito (for testing), and JUnit (for testing).
- Build Configuration: Specifies the final name of the WAR file, and includes plugins for packaging (Maven WAR Plugin), deployment (Tomcat Maven Plugin), and testing (Maven Surefire Plugin).
This setup ensures the project can be properly built, tested, and deployed as a web application.
2. web.xml
This is the deployment descriptor for your web application. It configures your web application and defines servlets, filters, and listeners. The welcome-file-list
element is used to define the default page when a user accesses the application.
Command:
vi ~/advanced-java-webapp/src/main/webapp/WEB-INF/web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Advanced Java Web Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Explanation:
Content Breakdown:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Advanced Java Web Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
XML Namespaces and Schema: The
web-app
defines the XML schema and namespaces used, ensuring the file conforms to the specifications for a Java EE 7 (Servlet 3.1) application.Display Name: The
<display-name>
element provides a human-readable name for the application.Welcome File List: The
<welcome-file-list>
defines the default resource to be loaded (i.e.,index.jsp
) when the root URL is accessed.
3. HomeServlet.java
The HomeServlet
class is a key component of the application, responsible for handling HTTP requests and managing blog posts to /home
. It demonstrates a basic CRUD (Create, Read, Update, Delete) operation pattern using Java Servlets. It extends HttpServlet
, which is part of the Java Servlet API, and overrides doGet
and doPost
methods to handle HTTP GET and POST requests, respectively.
Command:
vi ~/advanced-java-webapp/src/main/java/com/example/webapp/servlet/HomeServlet.java
package com.example.webapp.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
private List<BlogPost> blogPosts;
@Override
public void init() throws ServletException {
super.init();
blogPosts = new ArrayList<>();
blogPosts.add(new BlogPost(1, "The Art of Java Programming", "Discover the beauty of Java and its vast ecosystem.", "John Doe"));
blogPosts.add(new BlogPost(2, "Web Development with Servlets and JSP", "Learn how to create dynamic web applications using Java EE technologies.", "Jane Smith"));
blogPosts.add(new BlogPost(3, "Mastering Design Patterns in Java", "Explore common design patterns and their implementation in Java.", "Bob Johnson"));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if (action != null) {
switch (action) {
case "delete":
deletePost(request);
break;
case "edit":
prepareEditPost(request);
break;
}
}
request.setAttribute("blogPosts", blogPosts);
request.getRequestDispatcher("/WEB-INF/views/home.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if ("submit".equals(action)) {
createOrUpdatePost(request);
} else if ("delete".equals(action)) {
deletePost(request);
}
doGet(request, response);
}
private void createOrUpdatePost(HttpServletRequest request) {
String idStr = request.getParameter("id");
String title = request.getParameter("title");
String excerpt = request.getParameter("excerpt");
String author = request.getParameter("author");
int id = idStr.isEmpty() ? -1 : Integer.parseInt(idStr);
BlogPost post = findPostById(id);
if (post == null) {
blogPosts.add(new BlogPost(blogPosts.size() + 1, title, excerpt, author));
} else {
post.setTitle(title);
post.setExcerpt(excerpt);
post.setAuthor(author);
}
}
private void deletePost(HttpServletRequest request) {
int id = Integer.parseInt(request.getParameter("id"));
BlogPost post = findPostById(id);
if (post != null) {
blogPosts.remove(post);
}
}
private BlogPost findPostById(int id) {
for (BlogPost post : blogPosts) {
if (post.getId() == id) {
return post;
}
}
return null;
}
private void prepareEditPost(HttpServletRequest request) {
int id = Integer.parseInt(request.getParameter("id"));
BlogPost post = findPostById(id);
if (post != null) {
request.setAttribute("editPost", post);
}
}
public static class BlogPost {
private int id;
private String title;
private String excerpt;
private String author;
public BlogPost(int id, String title, String excerpt, String author) {
this.id = id;
this.title = title;
this.excerpt = excerpt;
this.author = author;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getExcerpt() {
return excerpt;
}
public void setExcerpt(String excerpt) {
this.excerpt = excerpt;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
}
Explanation:
Content Breakdown:
Package and Imports
package com.example.webapp.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Package Declaration: The
package com.example.webapp.servlet;
line defines the package to which this servlet belongs. Packages are used to organize classes and interfaces in a namespace, which helps to avoid naming conflicts and to control access.Imports:
java.io.IOException
andjavax.servlet.ServletException
are imported for handling exceptions that can occur during the input/output operations and servlet operations.java.util.ArrayList
andjava.util.List
are used to manage collections ofBlogPost
objects.javax.servlet.annotation.WebServlet
is an annotation used to declare a servlet and map it to a specific URL (/home
in this case).javax.servlet.http.HttpServlet
,javax.servlet.http.HttpServletRequest
, andjavax.servlet.http.HttpServletResponse
are part of the Servlet API, allowing the servlet to handle HTTP requests and responses.
Servlet Annotation and Class Declaration
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
@WebServlet("/home")
: This annotation is used to declare the servlet and specify the URL pattern that this servlet will handle. In this case, the servlet will handle requests sent to the/home
URL.Class Declaration:
public class HomeServlet extends HttpServlet
declares a public classHomeServlet
that extendsHttpServlet
. This meansHomeServlet
is a servlet that inherits capabilities from theHttpServlet
class, such as handling HTTP requests (GET
,POST
, etc.).
Member Variables and Initialization
private List<BlogPost> blogPosts;
@Override
public void init() throws ServletException {
super.init();
blogPosts = new ArrayList<>();
blogPosts.add(new BlogPost(1, "The Art of Java Programming", "Discover the beauty of Java and its vast ecosystem.", "John Doe"));
blogPosts.add(new BlogPost(2, "Web Development with Servlets and JSP", "Learn how to create dynamic web applications using Java EE technologies.", "Jane Smith"));
blogPosts.add(new BlogPost(3, "Mastering Design Patterns in Java", "Explore common design patterns and their implementation in Java.", "Bob Johnson"));
}
private List<BlogPost> blogPosts;
: This is a private member variable of typeList<BlogPost>
that stores a list ofBlogPost
objects. It will be used to manage the collection of blog posts.init()
Method:- This method is called by the servlet container to initialize the servlet when it is first loaded into memory.
- It initializes the
blogPosts
list and populates it with threeBlogPost
objects, each representing a different blog post. - The
super.init()
call ensures that the parent class (HttpServlet
) initialization logic is executed.
doGet
Method
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if (action != null) {
switch (action) {
case "delete":
deletePost(request);
break;
case "edit":
prepareEditPost(request);
break;
}
}
request.setAttribute("blogPosts", blogPosts);
request.getRequestDispatcher("/WEB-INF/views/home.jsp").forward(request, response);
}
doGet
Method:- Handles
GET
requests to the servlet. It is triggered when a user navigates to the/home
URL. - Retrieves the
action
parameter from the request to determine what action to take (delete
oredit
). - Depending on the
action
value, it calls eitherdeletePost
orprepareEditPost
. - Sets the
blogPosts
list as an attribute on the request object so it can be accessed in the JSP (home.jsp
). - Forwards the request to the
home.jsp
page to display the current state ofblogPosts
.
- Handles
doPost
Method
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
if ("submit".equals(action)) {
createOrUpdatePost(request);
} else if ("delete".equals(action)) {
deletePost(request);
}
doGet(request, response);
}
doPost
Method:- Handles
POST
requests to the servlet, typically used when a form is submitted. - Checks the
action
parameter to determine what action to perform. If the action is"submit"
, it callscreateOrUpdatePost
to handle the creation or update of a blog post. If the action is"delete"
, it callsdeletePost
. - Calls
doGet
to refresh the page after performing the post action to ensure the user sees the updated list of blog posts.
- Handles
createOrUpdatePost
Method
private void createOrUpdatePost(HttpServletRequest request) {
String idStr = request.getParameter("id");
String title = request.getParameter("title");
String excerpt = request.getParameter("excerpt");
String author = request.getParameter("author");
int id = idStr.isEmpty() ? -1 : Integer.parseInt(idStr);
BlogPost post = findPostById(id);
if (post == null) {
blogPosts.add(new BlogPost(blogPosts.size() + 1, title, excerpt, author));
} else {
post.setTitle(title);
post.setExcerpt(excerpt);
post.setAuthor(author);
}
}
createOrUpdatePost
Method:- Responsible for creating a new blog post or updating an existing one based on the form data submitted.
- Retrieves parameters from the request (
id
,title
,excerpt
,author
). - If
id
is empty, it's set to-1
, indicating a new post creation. - Calls
findPostById
to see if a post with the givenid
exists. - If the post is
null
(not found), a newBlogPost
is created and added to theblogPosts
list. Otherwise, the existing post is updated with the new data (title
,excerpt
,author
).
deletePost
Method
private void deletePost(HttpServletRequest request) {
int id = Integer.parseInt(request.getParameter("id"));
BlogPost post = findPostById(id);
if (post != null) {
blogPosts.remove(post);
}
}
deletePost
Method:- Handles the deletion of a blog post.
- Retrieves the
id
of the post to be deleted from the request parameters. - Uses
findPostById
to locate the post by itsid
. - If the post is found, it is removed from the
blogPosts
list.
findPostById
Method
private BlogPost findPostById(int id) {
for (BlogPost post : blogPosts) {
if (post.getId() == id) {
return post;
}
}
return null;
}
findPostById
Method:- Searches for a
BlogPost
in theblogPosts
list by itsid
. - Iterates through each
BlogPost
inblogPosts
and returns the post if theid
matches. - Returns
null
if no post with the givenid
is found.
- Searches for a
prepareEditPost
Method
private void prepareEditPost(HttpServletRequest request) {
int id = Integer.parseInt(request.getParameter("id"));
BlogPost post = findPostById(id);
if (post != null) {
request.setAttribute("editPost", post);
}
}
prepareEditPost
Method:- Prepares a blog post for editing.
- Retrieves the
id
of the post to be edited from the request parameters. - Uses
findPostById
to find the post by itsid
. - If the post is found, it sets the post as an attribute (
editPost
) on the request object so it can be accessed in the JSP (home.jsp
).
BlogPost
Inner Class
public static class BlogPost {
private int id;
private String title;
private String excerpt;
private String author;
public BlogPost(int id, String title, String excerpt, String author) {
this.id = id;
this.title = title;
this.excerpt = excerpt;
this.author = author;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getExcerpt() {
return excerpt;
}
public void setExcerpt(String excerpt) {
this.excerpt = excerpt;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
Fields:
private int id
: Represents the unique identifier of each blog post.private String title
: Stores the title of the blog post.private String excerpt
: Contains a brief summary or excerpt of the blog post's content.private String author
: Holds the name of the author of the blog post.
Constructor:
public BlogPost(int id, String title, String excerpt, String author)
: This constructor initializes a new instance ofBlogPost
with the providedid
,title
,excerpt
, andauthor
.
Getter and Setter Methods:
getId()
: Returns theid
of the blog post.getTitle()
: Returns thetitle
of the blog post.setTitle(String title)
: Sets a newtitle
for the blog post.getExcerpt()
: Returns theexcerpt
of the blog post.setExcerpt(String excerpt)
: Sets a newexcerpt
for the blog post.getAuthor()
: Returns theauthor
of the blog post.setAuthor(String author)
: Sets a newauthor
for the blog post.
Integration and Dependencies Between Methods and Classes
HomeServlet
and BlogPost
HomeServlet
Class:- Purpose: Serves as a controller in the MVC (Model-View-Controller) pattern, handling HTTP requests and manipulating data before sending it to the view (
home.jsp
). - Main Responsibilities:
- Initialization (
init()
): Loads initial data (blog posts). - Request Handling (
doGet()
,doPost()
): Manages bothGET
andPOST
requests, controlling what happens based on user actions. - Data Operations:
- Creating/Updating Posts (
createOrUpdatePost()
): Adds new posts or updates existing ones based on user input. - Deleting Posts (
deletePost()
): Removes a blog post based on itsid
. - Editing Preparation (
prepareEditPost()
): Prepares a blog post for editing by placing it in the request scope.
- Creating/Updating Posts (
- Initialization (
- Purpose: Serves as a controller in the MVC (Model-View-Controller) pattern, handling HTTP requests and manipulating data before sending it to the view (
BlogPost
Class:- Purpose: Represents a single blog post entity within the application.
- Main Responsibilities:
- Data Encapsulation: Holds blog post properties (
id
,title
,excerpt
,author
) and provides methods to access and modify them.
- Data Encapsulation: Holds blog post properties (
How Each Part Interacts:
Data Initialization:
- The
init()
method initializes theblogPosts
list with sampleBlogPost
objects. This setup is crucial for testing and demonstrating the functionality of the servlet without needing an external database.
- The
Handling HTTP Requests:
doGet()
Method:- Processes
GET
requests to display the blog posts. - Depending on the
action
parameter (e.g.,delete
oredit
), it will call methods (deletePost
orprepareEditPost
) to modify theblogPosts
list or set attributes for the view. - The
blogPosts
list is set as a request attribute to be displayed inhome.jsp
.
- Processes
doPost()
Method:- Processes
POST
requests, typically from form submissions. - Based on the
action
parameter (submit
ordelete
), it either callscreateOrUpdatePost
to modify the blog posts ordeletePost
to remove a post. - After handling a
POST
request, it delegates todoGet()
to refresh the view with the updated data.
- Processes
Modifying Data:
createOrUpdatePost()
:- Checks if a blog post already exists using
findPostById()
. If it does, it updates the post's properties using the setter methods (setTitle()
,setExcerpt()
,setAuthor()
). - If the post does not exist (
id
is-1
or not found), it creates a newBlogPost
and adds it to the list.
- Checks if a blog post already exists using
deletePost()
:- Finds the post by
id
and removes it from theblogPosts
list.
- Finds the post by
prepareEditPost()
:- Finds the post by
id
and sets it as a request attribute (editPost
) to be accessed in the JSP page (home.jsp
).
- Finds the post by
View Rendering (
home.jsp
):- The JSP file (
home.jsp
) renders theblogPosts
list to the user. It relies on the request attributes set by thedoGet()
method to display data dynamically based on the current state ofblogPosts
.
- The JSP file (
4. BlogPost.java
The BlogPost
class in the com.example.webapp.model
package is a simple data model class (also known as a POJO—Plain Old Java Object). It is used to represent a blog post entity within the application. The class encapsulates the properties of a blog post, including the title, excerpt, and author, and provides getter methods to access these properties.
Command:
vi ~/advanced-java-webapp/src/main/java/com/example/webapp/model/BlogPost.java
package com.example.webapp.model;
public class BlogPost {
private String title;
private String excerpt;
private String author;
public BlogPost(String title, String excerpt, String author) {
this.title = title;
this.excerpt = excerpt;
this.author = author;
}
// Getters
public String getTitle() { return title; }
public String getExcerpt() { return excerpt; }
public String getAuthor() { return author; }
}
Explanation:
Content Breakdown:
package com.example.webapp.model;
- Package Declaration:
- The
package
statement declares that this class is part of thecom.example.webapp.model
package. This helps organize related classes together and avoid naming conflicts.
- The
public class BlogPost {
- Class Declaration:
- The
BlogPost
class is declared aspublic
, meaning it can be accessed by any other class in the application. This is important for its usage across different parts of the application, especially in servlets and JSPs.
- The
Private Fields
private String title;
private String excerpt;
private String author;
- Fields:
private String title;
: This field holds the title of the blog post. It is marked asprivate
to restrict direct access from outside the class, following the principle of encapsulation.private String excerpt;
: This field stores a brief excerpt or summary of the blog post's content. It is alsoprivate
to ensure that it can only be accessed through the class's methods.private String author;
: This field contains the name of the author of the blog post. It is private for the same reasons as the other fields.
Constructor
public BlogPost(String title, String excerpt, String author) {
this.title = title;
this.excerpt = excerpt;
this.author = author;
}
- Constructor:
- The constructor is
public
, allowing any other class to create instances ofBlogPost
. - Parameters:
String title
: The title of the blog post.String excerpt
: A brief summary or excerpt of the blog post.String author
: The author's name.
this
Keyword:this.title = title;
assigns the value of thetitle
parameter to thetitle
field of theBlogPost
instance being created. This pattern is repeated for theexcerpt
andauthor
fields. Thethis
keyword is necessary here to differentiate between the class fields and the parameters with the same name.
- The constructor is
Getter Methods
// Getters
public String getTitle() { return title; }
public String getExcerpt() { return excerpt; }
public String getAuthor() { return author; }
- Getter Methods:
- These methods provide public access to the private fields of the class. They follow a standard naming convention (
getFieldName
) which is widely recognized in Java for accessing private data. public String getTitle()
:- Returns the
title
of the blog post. This allows other classes (such as servlets or JSPs) to retrieve the title without directly accessing the private field.
- Returns the
public String getExcerpt()
:- Returns the
excerpt
of the blog post. Similar togetTitle()
, it provides controlled access to the privateexcerpt
field.
- Returns the
public String getAuthor()
:- Returns the
author
of the blog post, allowing external classes to access the author's name.
- Returns the
- These methods provide public access to the private fields of the class. They follow a standard naming convention (
Usage and Dependencies
Usage in the Web Application:
- The
BlogPost
class is primarily used as a data model within the web application. For example, instances ofBlogPost
might be created, modified, and stored in a collection (like aList
) in servlets such asHomeServlet
. The servlets would then use these objects to dynamically generate content for the web pages (likehome.jsp
).
- The
Dependencies:
- The
BlogPost
class has no direct dependencies on other classes or libraries. It is a self-contained data model class. - However, other classes depend on
BlogPost
for storing and manipulating blog post data. For instance, in the servlet (HomeServlet
), a list ofBlogPost
objects is created and managed to display blog posts on the homepage.
- The
Integration and Interaction
Interaction with Servlets:
- In the
HomeServlet
class, theBlogPost
model is used to represent the data for blog posts. The servlet creates and manipulates instances ofBlogPost
using the constructor and getter methods. - For example, when initializing the list of blog posts, the servlet creates several
BlogPost
objects using the constructor:blogPosts.add(new BlogPost("The Art of Java Programming", "Discover the beauty of Java...", "John Doe"));
- When displaying the blog posts on a webpage, the servlet accesses each blog post's details using the getter methods:
request.setAttribute("blogPosts", blogPosts);
- In the
Interaction with JSP (JavaServer Pages):
- When the servlet forwards the request to a JSP file (like
home.jsp
), the JSP can use Expression Language (EL) or JSTL to access the properties of theBlogPost
objects provided by the servlet. For example:<c:forEach var="post" items="${blogPosts}"> <h2>${post.title}</h2> <p>${post.excerpt}</p> <p><em>by ${post.author}</em></p> </c:forEach>
- This snippet shows how the
title
,excerpt
, andauthor
fields are accessed through the getter methods indirectly via EL expressions (${post.title}
,${post.excerpt}
,${post.author}
).
- When the servlet forwards the request to a JSP file (like
5. index.jsp
The index.jsp
file is a well-structured JavaServer Page (JSP) that serves as the entry point for the web application. It is designed to provide a welcoming landing page for users visiting the blog. The page includes a button to navigate to the home page and a modal dialog for users to enter a nickname. It leverages Bootstrap for a modern, responsive design and uses JavaScript for interactive elements, such as the nickname modal and client-side storage. By combining HTML, CSS, and JavaScript with JSP capabilities, the page creates a dynamic and engaging user experience while preparing the user for further navigation within the application.
Command:
vi ~/advanced-java-webapp/src/main/webapp/index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Asthik Blog</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📰</text></svg>">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #004643;
color: white;
}
.btn-primary {
border-radius: 25px; /* Increased corner radius */
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center">Welcome to Asthik's Blog</h1>
<p class="text-center mt-3">
<button id="goToHomeBtn" class="btn btn-primary">Go to Home Page</button>
</p>
</div>
<!-- Nickname Modal -->
<div class="modal fade" id="nicknameModal" tabindex="-1" aria-labelledby="nicknameModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="nicknameModalLabel">Enter Your Nickname</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="text" class="form-control" id="nicknameInput" placeholder="Enter your nickname">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="saveNickname">Save</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
var nicknameModal = new bootstrap.Modal(document.getElementById('nicknameModal'));
document.getElementById('goToHomeBtn').addEventListener('click', function(e) {
e.preventDefault();
nicknameModal.show();
});
document.getElementById('saveNickname').addEventListener('click', function() {
var nickname = document.getElementById('nicknameInput').value || 'Friend';
nicknameModal.hide();
// Store the nickname in localStorage
localStorage.setItem('userNickname', nickname);
// Redirect to the home page
window.location.href = '${pageContext.request.contextPath}/home';
});
</script>
</body>
</html>
Explanation:
Content Breakdown:
JSP Directives
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- Page Directive:
- The JSP page directive provides configuration settings for the JSP page.
language="java"
: Specifies that the scripting language used in this JSP is Java.contentType="text/html; charset=UTF-8"
: Sets the MIME type of the response totext/html
with a character encoding of UTF-8. This is essential for correctly displaying the text and special characters on the webpage.pageEncoding="UTF-8"
: Specifies the encoding used for the JSP page itself, ensuring it is read and interpreted as UTF-8.
HTML Document Structure
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Asthik Blog</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📰</text></svg>">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #004643;
color: white;
}
.btn-primary {
border-radius: 25px; /* Increased corner radius */
}
</style>
</head>
<body>
...
</body>
</html>
HTML5 Doctype:
- The
<!DOCTYPE html>
declaration defines the document type and version of HTML being used (HTML5 in this case).
- The
<html>
Element:- The root element of the HTML document.
<head>
Section:<meta charset="UTF-8">
: Specifies the character set for the HTML document as UTF-8, ensuring proper handling of text and special characters.<title>Asthik Blog</title>
: Sets the title of the web page, which appears in the browser tab.- Favicon Link:
<link rel="icon" ...>
: Embeds a small newspaper emoji as the favicon using an SVG image data URI. This favicon will be displayed in the browser tab or address bar.
- Bootstrap CSS:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
: Includes Bootstrap 5 CSS from a CDN for responsive design and pre-styled components.
- Internal CSS Styles:
- The
<style>
block includes internal CSS to customize the page's appearance:body { background-color: #004643; color: white; }
: Sets the background color to a dark green (#004643
) and text color to white..btn-primary { border-radius: 25px; }
: Modifies Bootstrap’s default primary button style to have a larger border radius for rounded corners.
- The
HTML Body and Main Content
<body>
<div class="container mt-5">
<h1 class="text-center">Welcome to Asthik's Blog</h1>
<p class="text-center mt-3">
<button id="goToHomeBtn" class="btn btn-primary">Go to Home Page</button>
</p>
</div>
...
</body>
<body>
Element:- Contains the visible content of the webpage.
Main Container:
<div class="container mt-5">
: A Bootstrap container element centered with a top margin (mt-5
). This provides a responsive and aligned structure for the page content.- Welcome Header:
<h1 class="text-center">Welcome to Asthik's Blog</h1>
: Displays a centered heading welcoming users to the blog.
- Home Button:
<p class="text-center mt-3">
: A paragraph element with additional top margin (mt-3
) to separate it from the header.<button id="goToHomeBtn" class="btn btn-primary">Go to Home Page</button>
: A Bootstrap-styled primary button with an ID ofgoToHomeBtn
. Clicking this button triggers the display of the nickname modal.
Modal for Nickname Input
<!-- Nickname Modal -->
<div class="modal fade" id="nicknameModal" tabindex="-1" aria-labelledby="nicknameModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="nicknameModalLabel">Enter Your Nickname</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="text" class="form-control" id="nicknameInput" placeholder="Enter your nickname">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="saveNickname">Save</button>
</div>
</div>
</div>
</div>
- Modal Component:
- This section creates a Bootstrap modal component, which is a dialog box/popup window that is displayed on top of the current page.
<div class="modal fade" id="nicknameModal" ...>
: The outer container for the modal, with Bootstrap classesmodal
andfade
for transition effects.- Modal Dialog and Content:
<div class="modal-dialog">
: Defines the modal's dialog box.<div class="modal-content">
: Contains the actual content of the modal.
- Modal Header:
<div class="modal-header">
: Header section of the modal, containing the title and a close button.<h5 class="modal-title" id="nicknameModalLabel">Enter Your Nickname</h5>
: Displays the title of the modal.- Close Button:
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
: A Bootstrap-styled close button to dismiss the modal.
- Modal Body:
<div class="modal-body">
: Contains the body of the modal.- Nickname Input:
<input type="text" class="form-control" id="nicknameInput" placeholder="Enter your nickname">
: An input field for the user to enter their nickname. It uses Bootstrap’sform-control
class for styling.
- Modal Footer:
<div class="modal-footer">
: Footer of the modal with action buttons.- Close and Save Buttons:
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
: A secondary button to close the modal.<button type="button" class="btn btn-primary" id="saveNickname">Save</button>
: A primary button to save the nickname input by the user. This button is associated with the IDsaveNickname
for JavaScript event handling.
Scripts and JavaScript Logic
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
var nicknameModal = new bootstrap.Modal(document.getElementById('nicknameModal'));
document.getElementById('goToHomeBtn').addEventListener('click', function(e) {
e.preventDefault();
nicknameModal.show();
});
document.getElementById('saveNickname').addEventListener('click', function() {
var nickname = document.getElementById('nicknameInput').value || 'Friend';
nicknameModal.hide();
// Store the nickname in localStorage
localStorage.setItem('userNickname', nickname);
// Redirect to the home page
window.location.href = '${pageContext.request.contextPath}/home';
});
</script>
- Bootstrap JS:
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
: Loads Bootstrap's JavaScript library from a CDN. This library includes all Bootstrap components and functionality, such as mod
als and buttons.
- JavaScript for Modal and User Interaction:
- JavaScript Variable Initialization:
var nicknameModal = new bootstrap.Modal(document.getElementById('nicknameModal'));
: Initializes a new Bootstrap modal instance for the nickname modal element.
- Button Event Listeners:
- Go to Home Button:
document.getElementById('goToHomeBtn').addEventListener('click', function(e) {...}
: Adds a click event listener to the "Go to Home Page" button. When clicked, it prevents the default button behavior and displays the nickname modal by callingnicknameModal.show()
.
- Save Nickname Button:
document.getElementById('saveNickname').addEventListener('click', function() {...}
: Adds a click event listener to the "Save" button in the modal. When clicked:var nickname = document.getElementById('nicknameInput').value || 'Friend';
: Retrieves the user-inputted nickname from the input field. If no nickname is entered, it defaults to 'Friend'.nicknameModal.hide();
: Closes the modal after the nickname is saved.localStorage.setItem('userNickname', nickname);
: Stores the nickname in the browser'slocalStorage
so it can be retrieved later across page loads or sessions.window.location.href = '${pageContext.request.contextPath}/home';
: Redirects the user to the home page using JSP'spageContext
to construct the correct URL path.
- Go to Home Button:
- JavaScript Variable Initialization:
Usage and Integration
Client-Side Interactions:
- This JSP serves as a dynamic front-end page that interacts directly with users. It uses Bootstrap for styling and JavaScript to handle user interactions such as opening the modal and saving user input.
Server-Side Context:
- While this JSP does not interact with server-side Java code directly (e.g., through scriptlets or JSP expressions), it does utilize the JSP
pageContext
to correctly handle URL paths. This is particularly useful when deploying the web application in different environments where the context path may change.
- While this JSP does not interact with server-side Java code directly (e.g., through scriptlets or JSP expressions), it does utilize the JSP
Session Management and User Personalization:
- The nickname modal provides a simple mechanism for personalizing the user experience. By saving the user's nickname in
localStorage
, the application can remember the user's choice across different sessions or page loads without the need for server-side state management.
- The nickname modal provides a simple mechanism for personalizing the user experience. By saving the user's nickname in
6. home.jsp
The home.jsp
file is a key component of the blog application, combining dynamic server-side rendering with interactive client-side features. It displays a list of blog posts and provides options to create, edit, or delete a post. By leveraging JSTL for server-side logic, Bootstrap for styling, and JavaScript for interactivity, the page provides a seamless and engaging user experience. The integration with backend services through forms and dynamic links ensures that users can manage blog content effectively.
Command:
vi ~/advanced-java-webapp/src/main/webapp/WEB-INF/views/home.jsp
<%@ 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>Asthik Home</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏠︎</text></svg>">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
background-color: #2c2a4a;
color: white;
}
.card {
background-color: #4f518c;
color: white;
transition: transform 0.3s;
border-radius: 15px; /* Increased corner radius */
}
.card-body {
border-radius: 15px; /* Increased corner radius */
}
.card:hover {
transform: translateY(-5px);
}
.btn {
border-radius: 20px;
transition: all 0.3s ease;
}
.btn:hover {
transform: scale(1.05);
}
.btn-warning {
background-color: #dabfff;
border-color: #dabfff;
margin-right: 10px;
}
.btn-danger {
background-color: #907ad6;
border-color: #907ad6;
}
.btn-home {
background-color: #dd2d4a;
border-color: #dd2d4a;
color: white;
}
#redirectMessage {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0,0,0,0.7);
padding: 10px 20px;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">Welcome to Asthik's Blog</h1>
<c:if test="${not empty message}">
<div class="alert alert-success" role="alert">
${message}
</div>
</c:if>
<div class="row mb-5">
<c:forEach items="${blogPosts}" var="post">
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">${post.title}</h5>
<p class="card-text">${post.excerpt}</p>
<p class="card-text"><small>By ${post.author}</small></p>
<a href="${pageContext.request.contextPath}/home?action=edit&id=${post.id}" class="btn btn-warning btn-sm">Edit</a>
<a href="${pageContext.request.contextPath}/home?action=delete&id=${post.id}" class="btn btn-danger btn-sm">Delete</a>
</div>
</div>
</div>
</c:forEach>
</div>
<!-- Form to create or edit blog post -->
<div class="row">
<div class="col-md-6 mx-auto">
<h2>Create or Edit Post</h2>
<form action="${pageContext.request.contextPath}/home" method="post">
<input type="hidden" name="id" value="${editPost != null ? editPost.id : ''}">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" value="${editPost != null ? editPost.title : ''}" required>
</div>
<div class="mb-3">
<label for="excerpt" class="form-label">Excerpt</label>
<textarea class="form-control" id="excerpt" name="excerpt" rows="3" required>${editPost != null ? editPost.excerpt : ''}</textarea>
</div>
<div class="mb-3">
<label for="author" class="form-label">Author</label>
<input type="text" class="form-control" id="author" name="author" value="${editPost != null ? editPost.author : ''}" required>
</div>
<button type="submit" class="btn btn-primary" name="action" value="submit">Save Post</button>
<a href="${pageContext.request.contextPath}" class="btn btn-home" id="backHome">Back Home</a>
</form>
</div>
</div>
</div>
<div id="redirectMessage" style="display: none;">
<p>Thank you, <span id="nicknamePlaceholder"></span>! Redirecting in <span id="countdown">5</span> seconds.</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.getElementById('backHome').addEventListener('click', function(e) {
e.preventDefault();
var nickname = localStorage.getItem('userNickname') || 'Friend';
document.getElementById('nicknamePlaceholder').textContent = nickname;
document.getElementById('redirectMessage').style.display = 'block';
var countdown = 5;
var countdownElement = document.getElementById('countdown');
var countdownInterval = setInterval(function() {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(countdownInterval);
window.location.href = '${pageContext.request.contextPath}';
}
}, 1000);
});
</script>
</body>
</html>
Explanation:
Content Breakdown:
JSP Directives
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Page Directive:
language="java"
: Specifies that the scripting language used is Java.contentType="text/html; charset=UTF-8"
: Sets the MIME type for the page totext/html
with UTF-8 encoding.pageEncoding="UTF-8"
: Ensures the JSP page is read and interpreted as UTF-8.
Taglib Directive:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
: Imports the core JSTL tag library, which provides standard tags like<c:if>
and<c:forEach>
for adding conditional logic and loops within the JSP page.
HTML Document Structure
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Asthik Home</title>
<link rel="icon" href="data:image/svg+xml,...">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
...
</style>
</head>
<body>
...
</body>
</html>
HTML5 Doctype:
- Defines the document type as HTML5, ensuring modern standards and browser compatibility.
<html>
Element:- The root element for the HTML document.
<head>
Section:- Meta Tag: Specifies the character encoding for the document as UTF-8.
- Title Tag: Sets the title of the webpage to "Asthik Home".
- Favicon: Embeds a small house emoji as the favicon using an SVG image data URI.
- Bootstrap CSS: Includes Bootstrap 5 CSS from a CDN to provide a responsive layout and pre-styled components.
- Internal CSS Styles: Contains internal CSS rules that customize the appearance of the page, such as background colors, card styling, button effects, and hover transitions.
Body and Main Content
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">Welcome to Asthik's Blog</h1>
<c:if test="${not empty message}">
<div class="alert alert-success" role="alert">
${message}
</div>
</c:if>
<div class="row mb-5">
<c:forEach items="${blogPosts}" var="post">
...
</c:forEach>
</div>
<div class="row">
<div class="col-md-6 mx-auto">
<h2>Create or Edit Post</h2>
<form action="${pageContext.request.contextPath}/home" method="post">
...
</form>
</div>
</div>
</div>
<div id="redirectMessage" style="display: none;">
<p>Thank you, <span id="nicknamePlaceholder"></span>! Redirecting in <span id="countdown">5</span> seconds.</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
...
</script>
</body>
Main Container:
- Bootstrap Container: A
div
with thecontainer
class is used to center content and add a top margin (mt-5
). - Welcome Message: A centered heading welcoming users to the blog.
- Bootstrap Container: A
Conditional Alert:
<c:if test="${not empty message}">
: JSTLif
tag that checks if themessage
attribute is not empty.- Alert Box: Displays a Bootstrap-styled alert box containing a message when a blog post is successfully saved, edited, or deleted.
Blog Post Listing:
<c:forEach items="${blogPosts}" var="post">
: JSTL loop that iterates over a collection ofblogPosts
.- Post Cards: For each blog post, a Bootstrap card is displayed with the post's title, excerpt, author, and buttons for editing or deleting the post.
- Edit and Delete Buttons: Use dynamic URLs constructed with JSP expressions and query parameters based on the post ID.
Form for Creating or Editing Posts:
- Form Container: A Bootstrap row containing a form for creating or editing blog posts.
- Form Fields: Includes input fields for the post ID (hidden), title, excerpt, and author, pre-filled with values if
editPost
is not null (indicating an edit operation). - Form Buttons: Includes buttons to save the post and return to the home page.
Redirect Message:
<div id="redirectMessage">
: A hidden div that shows a countdown and a thank-you message when a user navigates back home.
JavaScript Logic
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.getElementById('backHome').addEventListener('click', function(e) {
e.preventDefault();
var nickname = localStorage.getItem('userNickname') || 'Friend';
document.getElementById('nicknamePlaceholder').textContent = nickname;
document.getElementById('redirectMessage').style.display = 'block';
var countdown = 5;
var countdownElement = document.getElementById('countdown');
var countdownInterval = setInterval(function() {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(countdownInterval);
window.location.href = '${pageContext.request.contextPath}';
}
}, 1000);
});
</script>
Bootstrap JS:
- Loads Bootstrap's JavaScript library to support dynamic components like modals and buttons.
JavaScript for Redirect Message and Countdown:
- Back Home Button Event Listener: Listens for clicks on the "Back Home" button. When clicked:
- Prevent Default Action: Prevents the default hyperlink behavior.
- Retrieve Nickname: Gets the user’s nickname from
localStorage
or defaults to 'Friend'. - Show Redirect Message: Displays a message thanking the user and begins a countdown.
- Countdown Logic: Updates a countdown every second and redirects the user to the home page when the countdown reaches zero.
- Back Home Button Event Listener: Listens for clicks on the "Back Home" button. When clicked:
Usage and Integration
Dynamic Content with JSTL:
- The use of JSTL allows the JSP to dynamically display content based on the server-side state. For example, it can loop through blog posts or conditionally display a success message.
Responsive Design with Bootstrap:
- Bootstrap is used extensively to create a responsive and modern UI, including forms, buttons, alerts, and cards.
User Interaction and Personalization:
- JavaScript enhances the user experience by adding interactive elements, such as showing a redirect message with a countdown. It also allows for some level of personalization, such as greeting users by their saved nickname.
Server-Side Integration:
- The form submissions and dynamic links (
Edit
andDelete
) are constructed to interact with server-side logic. Actions like creating, editing, and deleting posts are handled via HTTP requests to the backend.
- The form submissions and dynamic links (
7. HomeServletTest.java
The HomeServletTest.java
file effectively tests the core functionalities of the HomeServlet
class using JUnit and Mockito. By mocking servlet components and simulating different request scenarios, these tests ensure that the servlet correctly handles user interactions and maintains the intended behavior of the web application. This approach is crucial for maintaining code quality and reliability in a Java web application environment. It uses the Mockito framework to mock the HTTP request and response objects, as well as the RequestDispatcher
to simulate the servlet environment. The tests verify the servlet's ability to handle various HTTP methods (GET
and POST
) and actions (submit
, delete
, and edit
) correctly.
Command:
vi ~/advanced-java-webapp/src/test/java/com/example/webapp/servlet/HomeServletTest.java
package com.example.webapp.servlet;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import static org.mockito.Mockito.*;
public class HomeServletTest {
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private RequestDispatcher requestDispatcher;
private HomeServlet homeServlet;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
homeServlet = new HomeServlet();
homeServlet.init(); // Initialize the servlet
when(request.getRequestDispatcher("/WEB-INF/views/home.jsp")).thenReturn(requestDispatcher);
}
@Test
public void testDoGet() throws ServletException, IOException {
homeServlet.doGet(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
@Test
public void testDoPost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("submit");
when(request.getParameter("id")).thenReturn("");
when(request.getParameter("title")).thenReturn("Test Title");
when(request.getParameter("excerpt")).thenReturn("Test Excerpt");
when(request.getParameter("author")).thenReturn("Test Author");
homeServlet.doPost(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
@Test
public void testDeletePost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("delete");
when(request.getParameter("id")).thenReturn("1");
homeServlet.doPost(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
@Test
public void testEditPost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("edit");
when(request.getParameter("id")).thenReturn("1");
homeServlet.doGet(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
}
Explanation:
Content Breakdown:
Package Declaration and Imports
package com.example.webapp.servlet;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import static org.mockito.Mockito.*;
- Package Declaration: Declares that this class is part of the
com.example.webapp.servlet
package. - JUnit Imports:
org.junit.Before
: Annotation to specify a method that should run before each test case.org.junit.Test
: Annotation to define test methods.
- Mockito Imports:
org.mockito.Mock
: Annotation to declare mock objects.org.mockito.MockitoAnnotations
: Utility class to initialize annotated mock objects.
- Servlet Imports:
javax.servlet.*
: Includes necessary classes for handling servlet requests, responses, and exceptions.
- Mockito Static Imports:
static org.mockito.Mockito.*
: Provides access to Mockito methods likewhen
,verify
, andany
.
Class Declaration
public class HomeServletTest {
- The
HomeServletTest
class is a public test class designed to test the functionality of theHomeServlet
.
Mock Object Declarations
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private RequestDispatcher requestDispatcher;
private HomeServlet homeServlet;
- Mock Annotations:
@Mock
: Annotations are used to declare mock objects forHttpServletRequest
,HttpServletResponse
, andRequestDispatcher
.- These mocks are initialized in the
setUp()
method and are used to simulate the behavior of servlet components.
HomeServlet
Instance:private HomeServlet homeServlet;
: The servlet under test, which will be instantiated and initialized in thesetUp()
method.
@Before
Setup Method
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
homeServlet = new HomeServlet();
homeServlet.init(); // Initialize the servlet
when(request.getRequestDispatcher("/WEB-INF/views/home.jsp")).thenReturn(requestDispatcher);
}
@Before
Annotation:- Specifies that the
setUp()
method should be executed before each test case to initialize the test environment.
- Specifies that the
- Mockito Initialization:
MockitoAnnotations.initMocks(this);
: Initializes the mock objects annotated with@Mock
.
- Servlet Initialization:
homeServlet = new HomeServlet();
: Instantiates the servlet object to be tested.homeServlet.init();
: Calls theinit()
method to initialize the servlet (if necessary for your servlet setup).
- RequestDispatcher Mock Setup:
when(request.getRequestDispatcher("/WEB-INF/views/home.jsp")).thenReturn(requestDispatcher);
: Configures the mockHttpServletRequest
to return a mockRequestDispatcher
whengetRequestDispatcher()
is called with the specified path.
Test Methods
Each test method is annotated with @Test
and verifies a different aspect of the servlet's behavior.
testDoGet()
Method
@Test
public void testDoGet() throws ServletException, IOException {
homeServlet.doGet(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
- Purpose: Tests the
doGet()
method ofHomeServlet
. - Method Call: Invokes the
doGet()
method on thehomeServlet
object. Verification:
verify(request).setAttribute(eq("blogPosts"), any(List.class));
: Ensures that the servlet sets theblogPosts
attribute on the request object.verify(requestDispatcher).forward(request, response);
: Ensures that the request is forwarded to the correct JSP view (home.jsp
).
testDoPost()
Method
@Test
public void testDoPost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("submit");
when(request.getParameter("id")).thenReturn("");
when(request.getParameter("title")).thenReturn("Test Title");
when(request.getParameter("excerpt")).thenReturn("Test Excerpt");
when(request.getParameter("author")).thenReturn("Test Author");
homeServlet.doPost(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
- Purpose: Tests the
doPost()
method when creating or submitting a blog post. - Mock Setup: Configures the request parameters to simulate a form submission with a "submit" action and input values for title, excerpt, and author.
- Method Call: Invokes the
doPost()
method on thehomeServlet
object. Verification:
- Checks if the servlet properly sets attributes and forwards the request as expected after handling a post submission.
testDeletePost()
Method
@Test
public void testDeletePost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("delete");
when(request.getParameter("id")).thenReturn("1");
homeServlet.doPost(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
- Purpose: Tests the
doPost()
method for the "delete" action. - Mock Setup: Mocks request parameters to simulate deleting a blog post with ID "1".
- Method Call: Invokes the
doPost()
method on thehomeServlet
. Verification:
- Ensures that the appropriate request attributes are set and the request is forwarded correctly.
testEditPost()
Method
@Test
public void testEditPost() throws ServletException, IOException {
when(request.getParameter("action")).thenReturn("edit");
when(request.getParameter("id")).thenReturn("1");
homeServlet.doGet(request, response);
verify(request).setAttribute(eq("blogPosts"), any(List.class));
verify(requestDispatcher).forward(request, response);
}
- Purpose: Tests the
doGet()
method for the "edit" action. - Mock Setup: Mocks request parameters to simulate an edit action for a blog post with ID "1".
- Method Call: Invokes the
doGet()
method on thehomeServlet
. - Verification:
- Checks that the servlet handles the edit action correctly by setting the necessary attributes and forwarding the request.
Usage and Integration
- Mocking with Mockito:
- The use of Mockito enables isolation of the servlet's logic from its dependencies (such as the HTTP request and response), allowing the tests to focus solely on the servlet's behavior.
- JUnit Annotations:
@Before
and@Test
annotations organize the test lifecycle, ensuring that the servlet and its dependencies are properly initialized before each test and that each method is correctly identified as a test case.
- Verifying Servlet Behavior:
verify()
methods are used to ensure that the servlet interacts with the request and response objects as expected, such as setting attributes and forwarding requests.
- Testing Different Actions:
- The test cases cover multiple scenarios (
GET
requests,POST
requests with different actions), ensuring comprehensive coverage of the servlet's functionality.
- The test cases cover multiple scenarios (
8. BlogPostTest.java
The BlogPostTest.java
file provides thorough testing of the BlogPost
class nested within the HomeServlet
. The tests validate the constructor's ability to initialize fields correctly and the setters' ability to modify fields appropriately. By ensuring that both construction and modification behaviors are tested, this class helps maintain the integrity and reliability of the BlogPost
data model within the Java web application.
Command:
vi ~/advanced-java-webapp/src/test/java/com/example/webapp/model/BlogPostTest.java
package com.example.webapp.model;
import org.junit.Test;
import static org.junit.Assert.*;
import com.example.webapp.servlet.HomeServlet;
public class BlogPostTest {
@Test
public void testBlogPostCreation() {
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Test Title", "Test Excerpt", "Test Author");
assertEquals(1, post.getId());
assertEquals("Test Title", post.getTitle());
assertEquals("Test Excerpt", post.getExcerpt());
assertEquals("Test Author", post.getAuthor());
}
@Test
public void testBlogPostSetters() {
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Initial Title", "Initial Excerpt", "Initial Author");
post.setTitle("Updated Title");
post.setExcerpt("Updated Excerpt");
post.setAuthor("Updated Author");
assertEquals("Updated Title", post.getTitle());
assertEquals("Updated Excerpt", post.getExcerpt());
assertEquals("Updated Author", post.getAuthor());
}
}
Explanation:
Content Breakdown:
Package Declaration and Imports
package com.example.webapp.model;
import org.junit.Test;
import static org.junit.Assert.*;
import com.example.webapp.servlet.HomeServlet;
- Package Declaration: Declares that this class is part of the
com.example.webapp.model
package. - JUnit Imports:
org.junit.Test
: This annotation is used to indicate that a method is a JUnit test case.
- JUnit Assertion Imports:
static org.junit.Assert.*
: Provides access to assertion methods such asassertEquals
to validate test outcomes.
- HomeServlet Import:
com.example.webapp.servlet.HomeServlet
: Imports theHomeServlet
class to access the nestedBlogPost
class that resides withinHomeServlet
.
Class Declaration
public class BlogPostTest {
- The
BlogPostTest
class is a public test class designed to test theBlogPost
data model nested within theHomeServlet
class.
Test Methods
Each test method is annotated with @Test
and is responsible for verifying different functionalities of the BlogPost
class.
testBlogPostCreation()
Method
@Test
public void testBlogPostCreation() {
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Test Title", "Test Excerpt", "Test Author");
assertEquals(1, post.getId());
assertEquals("Test Title", post.getTitle());
assertEquals("Test Excerpt", post.getExcerpt());
assertEquals("Test Author", post.getAuthor());
}
- Purpose: Tests the creation of a
BlogPost
object and verifies that all fields are correctly initialized. - Object Instantiation:
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Test Title", "Test Excerpt", "Test Author");
: Creates a new instance ofBlogPost
with an ID, title, excerpt, and author.
- Assertions:
assertEquals(1, post.getId());
: Verifies that the ID of theBlogPost
object is correctly set to1
.assertEquals("Test Title", post.getTitle());
: Ensures the title is "Test Title".assertEquals("Test Excerpt", post.getExcerpt());
: Ensures the excerpt is "Test Excerpt".assertEquals("Test Author", post.getAuthor());
: Ensures the author is "Test Author".
Outcome: Confirms that the constructor of
BlogPost
properly initializes its fields.testBlogPostSetters()
Method
@Test
public void testBlogPostSetters() {
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Initial Title", "Initial Excerpt", "Initial Author");
post.setTitle("Updated Title");
post.setExcerpt("Updated Excerpt");
post.setAuthor("Updated Author");
assertEquals("Updated Title", post.getTitle());
assertEquals("Updated Excerpt", post.getExcerpt());
assertEquals("Updated Author", post.getAuthor());
}
- Purpose: Tests the setter methods of the
BlogPost
class to ensure they correctly update the fields. - Object Instantiation:
HomeServlet.BlogPost post = new HomeServlet.BlogPost(1, "Initial Title", "Initial Excerpt", "Initial Author");
: Creates a newBlogPost
object with initial values for each field.
- Method Calls:
post.setTitle("Updated Title");
: Updates the title of theBlogPost
to "Updated Title".post.setExcerpt("Updated Excerpt");
: Updates the excerpt to "Updated Excerpt".post.setAuthor("Updated Author");
: Updates the author to "Updated Author".
- Assertions:
assertEquals("Updated Title", post.getTitle());
: Verifies that the title has been correctly updated.assertEquals("Updated Excerpt", post.getExcerpt());
: Verifies that the excerpt has been correctly updated.assertEquals("Updated Author", post.getAuthor());
: Verifies that the author has been correctly updated.
- Outcome: Confirms that the setter methods (
setTitle
,setExcerpt
,setAuthor
) correctly modify the fields of theBlogPost
object.
Usage and Integration
- JUnit Annotations:
@Test
: Indicates that the methods are test cases, allowing JUnit to execute them as part of the test suite.
- Assertions:
assertEquals
: Used extensively to check if the actual value matches the expected value. This is critical for verifying the correctness of object initialization and modification.
- Testing Object State:
- The test cases ensure that both the creation (constructor) and modification (setters) of a
BlogPost
object maintain consistent and expected state.
- The test cases ensure that both the creation (constructor) and modification (setters) of a
- Verification of Behavior:
- By testing both the getters and setters, these tests provide comprehensive coverage of the
BlogPost
model's behavior, ensuring that any changes to these methods in the future will be immediately detected if they deviate from the expected functionality.
- By testing both the getters and setters, these tests provide comprehensive coverage of the
5. Maven Build Process for our application 🚀
First let's dive into the individual Maven build process and how it integrates with Tomcat for your Java application! 😊
mvn clean
🧹- Purpose: Cleans up the
target
directory, removing all files generated by the previous build. - Sample Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ my-app --- [INFO] Deleting /root/advanced-java-webapp/target [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 0.5 s [INFO] Finished at: 2024-08-31T14:00:00+00:00 [INFO] ------------------------------------------------------------------------
- Purpose: Cleans up the
mvn compile
🔄- Purpose: Compiles the source code of the project.
- Sample Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Compiling 5 source files to /root/advanced-java-webapp/target/classes [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 1.2 s [INFO] Finished at: 2024-08-31T14:05:00+00:00 [INFO] ------------------------------------------------------------------------
mvn validate
✅- Purpose: Validates the project and checks if all necessary information is available.
- Sample Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-validation-plugin:2.0:validate (default-validate) @ my-app --- [INFO] Validation successful [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 0.3 s [INFO] Finished at: 2024-08-31T14:10:00+00:00 [INFO] ------------------------------------------------------------------------
mvn package
📦- Purpose: Packages the compiled code into a distributable format, like a
.jar
or.war
file. - Sample Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ my-app --- [INFO] Building jar: /root/advanced-java-webapp/target/advanced-java-webapp.war [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 2.0 s [INFO] Finished at: 2024-08-31T14:15:00+00:00 [INFO] ------------------------------------------------------------------------
- Purpose: Packages the compiled code into a distributable format, like a
mvn test
🧪- Purpose: Runs the unit tests using a suitable testing framework.
- Sample Output:
[INFO] Scanning for projects... [INFO] [INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ my-app --- [INFO] Surefire report directory: /root/advanced-java-webapp/target/surefire-reports [INFO] [INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.5 s [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 1.5 s [INFO] Finished at: 2024-08-31T14:20:00+00:00 [INFO] ------------------------------------------------------------------------
mvn clean install
🔄🛠️- Purpose: Cleans the project and then builds it. It also installs the package into the local repository.
- Sample Output:
In our case, since the application is built first time, we can use[INFO] Scanning for projects... [INFO] [INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ my-app --- [INFO] Deleting /root/advanced-java-webapp/target [INFO] [INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ my-app --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 2 resources [INFO] [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ my-app --- [INFO] Compiling 5 source files to /root/advanced-java-webapp/target/classes [INFO] [INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ my-app --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ my-app --- [INFO] Compiling 2 test sources to /root/advanced-java-webapp/target/test-classes [INFO] [INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ my-app --- [INFO] Surefire report directory: /root/advanced-java-webapp/target/surefire-reports [INFO] [INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.7 s [INFO] [INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ my-app --- [INFO] Building jar: /root/advanced-java-webapp/target/advanced-java-webapp.war [INFO] [INFO] --- maven-install-plugin:2.5.0:install (default-install) @ my-app --- [INFO] Installing /root/advanced-java-webapp/target/advanced-java-webapp.war to /root/.m2/repository/com/example/advanced-java-webapp/1.0-SNAPSHOT/advanced-java-webapp-1.0-SNAPSHOT.war [INFO] [INFO] BUILD SUCCESS [INFO] [INFO] Total time: 5.0 s [INFO] Finished at: 2024-08-31T14:30:00+00:00 [INFO] ------------------------------------------------------------------------
mvn package
ormvn install
ormvn clean package(OR)install
Using Maven Build Process with mvn clean install
as per our case
Command:
mvn clean install
Explanation: This command performs a series of steps:
clean
: Deletes thetarget
directory to ensure a fresh build.validate
: Validates the project’s configuration.compile
: Compiles the source code.test
: Runs unit tests.package
: Packages the code into a JAR/WAR file.install
: Installs the packaged artifact into the local Maven repository (.m2
directory).
Artifact Locations
target
Directory:- This is where Maven places the final WAR file. The default location is
advanced-java-webapp/target/advanced-java-webapp.war
. - Configuration in
pom.xml
: The<build>
section inpom.xml
defines the output directory for artifacts. - Example configuration:
<build> <finalName>advanced-java-webapp</finalName> </build>
- This is where Maven places the final WAR file. The default location is
Local Maven Repository (.m2 directory): The artifact & pom is also copied to the local Maven repository for use in other Maven projects.
- Path:
~/.m2/repository/com ├── example │ └── advanced-java-webapp │ ├── 1.0-SNAPSHOT │ │ ├── _remote.repositories │ │ ├── advanced-java-webapp-1.0-SNAPSHOT.pom │ │ ├── advanced-java-webapp-1.0-SNAPSHOT.war │ │ └── maven-metadata-local.xml │ └── maven-metadata-local.xml
Configuration in
pom.xml
by which this path in .m2 is created<groupId>com.example</groupId> <artifactId>advanced-java-webapp</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
- Path:
Final Project Directory Structure with Artifacts 📂
~/advanced-java-webapp
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── webapp
│ │ │ ├── model
│ │ │ │ └── BlogPost.java
│ │ │ ├── servlet
│ │ │ │ └── HomeServlet.java
│ │ │ └── views
│ │ ├── resources
│ │ └── webapp
│ │ ├── WEB-INF
│ │ │ ├── views
│ │ │ │ └── home.jsp
│ │ │ └── web.xml
│ │ └── index.jsp
│ └── test
│ └── java
│ └── com
│ └── example
│ └── webapp
│ ├── model
│ │ └── BlogPostTest.java
│ └── servlet
│ └── HomeServletTest.java
└── target
├── advanced-java-webapp
│ ├── META-INF
│ ├── WEB-INF
│ │ ├── classes
│ │ │ └── com
│ │ │ └── example
│ │ │ └── webapp
│ │ │ ├── model
│ │ │ │ └── BlogPost.class
│ │ │ └── servlet
│ │ │ ├── HomeServlet$BlogPost.class
│ │ │ └── HomeServlet.class
│ │ ├── lib
│ │ │ └── jstl-1.2.jar
│ │ ├── views
│ │ │ └── home.jsp
│ │ └── web.xml
│ └── index.jsp
├── advanced-java-webapp.war
├── classes
│ └── com
│ └── example
│ └── webapp
│ ├── model
│ │ └── BlogPost.class
│ └── servlet
│ ├── HomeServlet$BlogPost.class
│ └── HomeServlet.class
├── generated-sources
│ └── annotations
├── generated-test-sources
│ └── test-annotations
├── maven-archiver
│ └── pom.properties
├── maven-status
│ └── maven-compiler-plugin
│ ├── compile
│ │ └── default-compile
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── testCompile
│ └── default-testCompile
│ ├── createdFiles.lst
│ └── inputFiles.lst
├── surefire-reports
│ ├── TEST-com.example.webapp.model.BlogPostTest.xml
│ ├── TEST-com.example.webapp.servlet.HomeServletTest.xml
│ ├── com.example.webapp.model.BlogPostTest.txt
│ └── com.example.webapp.servlet.HomeServletTest.txt
└── test-classes
└── com
└── example
└── webapp
├── model
│ └── BlogPostTest.class
└── servlet
└── HomeServletTest.class
Detailed explanation of the final directory structure and files after running the Maven build for advanced-java-webapp
project:
Root Directory
~/advanced-java-webapp
├── pom.xml
pom.xml
: This is the Maven Project Object Model (POM) file. It contains configuration information about the project, including dependencies, plugins, and build settings.
Source Code Directory
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── webapp
│ │ │ ├── model
│ │ │ │ └── BlogPost.java
│ │ │ ├── servlet
│ │ │ │ └── HomeServlet.java
│ │ │ └── views
│ │ ├── resources
│ │ └── webapp
│ │ ├── WEB-INF
│ │ │ ├── views
│ │ │ │ └── home.jsp
│ │ │ └── web.xml
│ │ └── index.jsp
│ └── test
│ └── java
│ └── com
│ └── example
│ └── webapp
│ ├── model
│ │ └── BlogPostTest.java
│ └── servlet
│ └── HomeServletTest.java
src/main/java
: Contains the main application source code.com/example/webapp/model/BlogPost.java
: Defines theBlogPost
class.com/example/webapp/servlet/HomeServlet.java
: Contains theHomeServlet
class.com/example/webapp/views
: Contains view-related files (though it’s empty in this structure).
src/main/resources
: Used for non-Java resources (empty in this case).src/main/webapp
: Contains web application resources.WEB-INF
: Contains configuration and internal files.views/home.jsp
: JSP file for rendering the home page.web.xml
: Deployment descriptor for configuring servlets and other web components.
index.jsp
: The default JSP file served when accessing the web application.
src/test/java
: Contains test source code.com/example/webapp/model/BlogPostTest.java
: Unit tests for theBlogPost
class.com/example/webapp/servlet/HomeServletTest.java
: Unit tests for theHomeServlet
class.
Target Directory
└── target
├── advanced-java-webapp
│ ├── META-INF
│ ├── WEB-INF
│ │ ├── classes
│ │ │ └── com
│ │ │ └── example
│ │ │ └── webapp
│ │ │ ├── model
│ │ │ │ └── BlogPost.class
│ │ │ └── servlet
│ │ │ ├── HomeServlet$BlogPost.class
│ │ │ └── HomeServlet.class
│ │ ├── lib
│ │ │ └── jstl-1.2.jar
│ │ ├── views
│ │ │ └── home.jsp
│ │ └── web.xml
│ └── index.jsp
├── advanced-java-webapp.war
├── classes
│ └── com
│ └── example
│ └── webapp
│ ├── model
│ │ └── BlogPost.class
│ └── servlet
│ ├── HomeServlet$BlogPost.class
│ └── HomeServlet.class
├── generated-sources
│ └── annotations
├── generated-test-sources
│ └── test-annotations
├── maven-archiver
│ └── pom.properties
├── maven-status
│ └── maven-compiler-plugin
│ ├── compile
│ │ └── default-compile
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── testCompile
│ └── default-testCompile
│ ├── createdFiles.lst
│ └── inputFiles.lst
├── surefire-reports
│ ├── TEST-com.example.webapp.model.BlogPostTest.xml
│ ├── TEST-com.example.webapp.servlet.HomeServletTest.xml
│ ├── com.example.webapp.model.BlogPostTest.txt
│ └── com.example.webapp.servlet.HomeServletTest.txt
└── test-classes
└── com
└── example
└── webapp
├── model
│ └── BlogPostTest.class
└── servlet
└── HomeServletTest.class
target/advanced-java-webapp
: The directory structure for the packaged WAR file.META-INF
: Contains metadata files.WEB-INF
: Contains the compiled classes and other resources.classes
: Contains compiled.class
files.com/example/webapp/model/BlogPost.class
: Compiled class forBlogPost
.com/example/webapp/servlet/HomeServlet.class
: Compiled class forHomeServlet
.com/example/webapp/servlet/HomeServlet$BlogPost.class
: Compiled class for the innerBlogPost
class withinHomeServlet
.
lib
: Contains libraries used by the application (e.g., JSTL).jstl-1.2.jar
: The JSTL library.
views/home.jsp
: JSP file copied from thesrc/main/webapp
directory.web.xml
: Deployment descriptor copied from thesrc/main/webapp/WEB-INF
directory.
index.jsp
: JSP file copied from thesrc/main/webapp
directory.
target/advanced-java-webapp.war
: The packaged WAR file. This is the final deployable artifact.target/classes
: Contains compiled classes for the main source code.com/example/webapp/model/BlogPost.class
: Compiled class forBlogPost
.com/example/webapp/servlet/HomeServlet.class
: Compiled class forHomeServlet
.com/example/webapp/servlet/HomeServlet$BlogPost.class
: Compiled class for the innerBlogPost
class withinHomeServlet
.
target/generated-sources
: Contains sources generated during the build (e.g., annotation processing).annotations
: Directory for annotation-generated sources.
target/generated-test-sources
: Contains sources generated for testing.test-annotations
: Directory for test-related annotations.
target/maven-archiver
: Contains metadata about the build.pom.properties
: Properties file with information about the POM and project.
target/maven-status
: Contains status files for Maven plugins.maven-compiler-plugin
:compile/default-compile
: Contains lists of files created or used during compilation.testCompile/default-testCompile
: Contains lists of files created or used during test compilation.
target/surefire-reports
: Contains reports from test execution.TEST-com.example.webapp.model.BlogPostTest.xml
: Test results in XML format forBlogPostTest
.TEST-com.example.webapp.servlet.HomeServletTest.xml
: Test results in XML format forHomeServletTest
.com.example.webapp.model.BlogPostTest.txt
: Test results in text format forBlogPostTest
.com.example.webapp.servlet.HomeServletTest.txt
: Test results in text format forHomeServletTest
.
target/test-classes
: Contains compiled classes for the test source code.com/example/webapp/model/BlogPostTest.class
: Compiled class forBlogPostTest
.com/example/webapp/servlet/HomeServletTest.class
: Compiled class forHomeServletTest
.
6. Deploying to Tomcat 🌐
Tomcat Service Management
Stopping Tomcat 🚫
- Before deploying your
.war
file, ensure Tomcat is not running. Commands:
/opt/apache-tomcat-8.0.1/bin/catalina.sh stop
(OR)
/opt/apache-tomcat-8.0.1/bin/shutdown.sh
- Sample Output:
Using CATALINA_BASE: /opt/apache-tomcat-8.0.1 Using CATALINA_HOME: /opt/apache-tomcat-8.0.1 Using CATALINA_TMPDIR: /opt/apache-tomcat-8.0.1/temp Using JRE_HOME: /usr/lib/jvm/java-8-openjdk Using CLASSPATH: /opt/apache-tomcat-8.0.1/bin/bootstrap.jar:/opt/apache-tomcat-8.0.1/bin/tomcat-juli.jar Stopping Tomcat server from /opt/apache-tomcat-8.0.1
- Note: If the Tomcat service is not started & when you run stop command, before its started, you might see this error,
Using CATALINA_BASE: /opt/apache-tomcat-8.0.1 Using CATALINA_HOME: /opt/apache-tomcat-8.0.1 Using CATALINA_TMPDIR: /opt/apache-tomcat-8.0.1/temp Using JRE_HOME: /opt/jdk1.8.0_131 Using CLASSPATH: /opt/apache-tomcat-8.0.1/bin/bootstrap.jar:/opt/apache-tomcat-8.0.1/bin/tomcat-juli.jar Sep 01, 2024 1:31:20 PM org.apache.catalina.startup.Catalina stopServer SEVERE: Could not contact localhost:8005. Tomcat may not be running. Sep 01, 2024 1:31:20 PM org.apache.catalina.startup.Catalina stopServer SEVERE: Catalina.stop: java.net.ConnectException: Connection refused (Connection refused)
- Before deploying your
Deploy the WAR file:
- Copy the WAR file to the Tomcat
webapps
directory. - Command:
cp ~/advanced-java-webapp/target/advanced-java-webapp.war /opt/apache-tomcat-8.0.1/webapps/
- Tomcat automatically deploys the WAR file once copied & the service is started.
- Copy the WAR file to the Tomcat
Starting Tomcat 🚀
Commands:
/opt/apache-tomcat-8.0.1/bin/catalina.sh start
(OR)
/opt/apache-tomcat-8.0.1/bin/startup.sh
- Sample Output:
Using CATALINA_BASE: /opt/apache-tomcat-8.0.1 Using CATALINA_HOME: /opt/apache-tomcat-8.0.1 Using CATALINA_TMPDIR: /opt/apache-tomcat-8.0.1/temp Using JRE_HOME: /usr/lib/jvm/java-8-openjdk Using CLASSPATH: /opt/apache-tomcat-8.0.1/bin/bootstrap.jar:/opt/apache-tomcat-8.0.1/bin/tomcat-juli.jar Starting Tomcat server from /opt/apache-tomcat-8.0.1
Accessing Your Web Application
- Once Tomcat starts, it will deploy your
.war
file. A folder with the name of your artifact (e.g.,my-app
) will be created in/opt/apache-tomcat-8.0.1/webapps
. - Website will be accessible at:
http://<hostname>:8080/<artifactname>
(e.g.,http://localhost:8080/advanced-java-webapp
).
Environment Variables
$CATALINA_HOME
: Points to the Tomcat installation directory (/opt/apache-tomcat-8.0.1
). It helps Tomcat locate its configuration, libraries, and scripts.- Web Application Folder: Your web application is placed in
$CATALINA_HOME/webapps/advanced-java-webapp
.
Tomcat Configuration
Access Manager Home URL 🔑
- Modify
/opt/apache-tomcat-8.0.1/conf/tomcat-users.xml
to add users and roles for the Tomcat Manager. - Example Configuration:
<tomcat-users> <role rolename="manager-gui"/> <user username="admin" password="admin" roles="manager-gui"/> </tomcat-users>
- Modify
Configuration Changes 🛠️
- Modify
/opt/apache-tomcat-8.0.1/conf/catalina.properties
to adjust various properties such as classpath settings, logging levels, etc. - Example Configuration:
# Customize the classpath for additional libraries common.loader=${catalina.base}/lib,/path/to/extra/libs/*.jar
- Modify
Access Logs 📜
- Logs are stored in
/opt/apache-tomcat-8.0.1/logs
. Check files likecatalina.out
for application logs, andlocalhost_access_log.*.txt
for access logs.
- Logs are stored in
Summary of build process 🌟
Maven Build:
- Use commands like
mvn clean
,mvn compile
,mvn validate
,mvn package
,mvn test
, andmvn clean install
to manage the build process. mvn clean install
builds and installs the artifact into your local Maven repository.
- Use commands like
Deployment to Tomcat:
- Ensure Tomcat is stopped before deploying.
- Copy the WAR file to the
webapps
directory. - Start Tomcat to deploy your
.war
file. - Access your application at
http://<hostname>:8080/<artifactname>
. - Manage Tomcat using scripts and configuration files found in
$CATALINA_HOME
.
Configuration and Logs:
$CATALINA_HOME
defines the Tomcat directory.- Manage Tomcat using
shutdown.sh
andstartup.sh
. - Configure Tomcat Manager access and other settings in
tomcat-users.xml
andcatalina.properties
. - Check logs in the
logs
directory.