feat(DevWeb): Setup du Projet avec Servlet et JPA

This commit is contained in:
Lucàs
2024-03-13 20:17:41 +01:00
parent 9d59897ac4
commit a05ab6d2db
25 changed files with 289 additions and 257 deletions
+11
View File
@@ -0,0 +1,11 @@
# Projet Développent Web - 2024
## Installation
Pour pouvoir lancer le projet, il vous faut avoir docker et maven d'installé sur votre machine.
Lancez les commandes suivantes pour installer le projet :
````
docker-compose up -d
mvn install
````
+26 -25
View File
@@ -2,37 +2,38 @@ CREATE DATABASE IF NOT EXISTS db;
USE db;
-- Table: User
CREATE TABLE IF NOT EXISTS User
CREATE TABLE IF NOT EXISTS `user`
(
id_user INT NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
birth_date DATE NOT NULL,
sexe VARCHAR(255) NOT NULL,
PRIMARY KEY (id_user)
gender VARCHAR(255) NOT NULL,
birth DATE NOT NULL,
PRIMARY KEY (id)
);
-- Table: Game
CREATE TABLE IF NOT EXISTS Game
(
id_game INT NOT NULL AUTO_INCREMENT,
date DATE NOT NULL,
starting_time TIME NOT NULL,
PRIMARY KEY (id_game)
CREATE TABLE IF NOT EXISTS game
(
id INT NOT NULL AUTO_INCREMENT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS Player
CREATE TABLE IF NOT EXISTS player
(
id_player INT NOT NULL AUTO_INCREMENT,
id_game INT NOT NULL,
id_user INT NOT NULL,
score INT NOT NULL,
winner BOOLEAN NOT NULL,
nb_clicks INT NOT NULL,
nb_good_clicks INT NOT NULL,
nb_rapid_clicks INT NOT NULL,
PRIMARY KEY (id_player),
FOREIGN KEY (id_game) REFERENCES Game (id_game),
FOREIGN KEY (id_user) REFERENCES User (id_user)
)
id INT NOT NULL AUTO_INCREMENT,
game_id INT NOT NULL,
user_id INT NOT NULL,
score INT NOT NULL,
winner BOOLEAN NOT NULL,
click_count INT NOT NULL,
right_click_count INT NOT NULL,
rapid_click_count INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (game_id) REFERENCES game (id),
FOREIGN KEY (user_id) REFERENCES `user` (id)
);
+27 -19
View File
@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tp4</groupId>
<artifactId>Project</artifactId>
<groupId>uppa</groupId>
<artifactId>project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>TP4_mysql_2</name>
<name>Projet</name>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -17,35 +18,42 @@
</properties>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>3.0.2</version>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins></plugins>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin> </plugins>
</build>
</project>
</project>
@@ -1,51 +0,0 @@
package project;
import java.util.Calendar;
import project.dao.DAO;
import project.dao.DAOException;
import project.dao.jpa.Game_JPA_DAO_Factory;
import project.pojo.Game;
import project.pojo.Player;
import project.pojo.User;
public class Main {
public static void main(String[] args) {
try {
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
DAO<User> daoJpaUser = jpaDaoFactory.getDAOUser();
DAO<Game> daoJpaGame = jpaDaoFactory.getDAOGame();
DAO<Player> daoJpaPlayer = jpaDaoFactory.getDAOPlayer();
// Contenu de la BD au début
User[] users = daoJpaUser.findAll();
for (User u : users) {
System.out.println(u.toString());
}
System.out.println();
// Ajout d'un joueur :
Calendar calendarUser1 = Calendar.getInstance();
calendarUser1.set(1996,Calendar.FEBRUARY,20);
User user1 = new User("Kevin", "Mitresse", calendarUser1.getTime(), User.Sexe.HOMME);
Calendar calendarUser2 = Calendar.getInstance();
calendarUser2.set(2002,Calendar.JUNE,28);
User user2 = new User("Lucàs", "Vabre", calendarUser1.getTime(), User.Sexe.HOMME);
users = daoJpaUser.findAll();
for (User u : users) {
System.out.println(u.toString());
}
System.out.println();
EntityManagerProvider.close();
} catch (DAOException e) {
e.printStackTrace();
} catch (Exception e) {
System.out.println("Error : : : : ");
}
}
}
@@ -1,4 +1,4 @@
package project;
package uppa.project;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
@@ -8,7 +8,7 @@ public final class EntityManagerProvider {
private static EntityManager instance;
private static EntityManagerFactory factory;
private final static String PERSISTANCE_UNIT_NAME = "default";
private final static String PERSISTANCE_UNIT_NAME = "db";
public static EntityManager getInstance() {
if (factory == null) {
@@ -0,0 +1,50 @@
package uppa.project;
import java.util.Calendar;
import uppa.project.dao.DAO;
import uppa.project.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.pojo.Game;
import uppa.project.pojo.Player;
import uppa.project.pojo.User;
public class Main {
public static void main(String[] args) {
try {
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
DAO<User> daoJpaUser = jpaDaoFactory.getDAOUser();
// DAO<Game> daoJpaGame = jpaDaoFactory.getDAOGame();
// DAO<Player> daoJpaPlayer = jpaDaoFactory.getDAOPlayer();
// Contenu de la BD au début
User[] users = daoJpaUser.findAll();
for (User u : users) {
System.out.println(u.toString());
}
System.out.println();
// Ajout d'User :
Calendar cal1 = Calendar.getInstance();
cal1.set(1996, Calendar.FEBRUARY, 20);
User user1 = new User("Kevin", "Mitresse", cal1.getTime(), User.Gender.MALE);
Calendar cal2 = Calendar.getInstance();
cal2.set(2002, Calendar.JUNE, 28);
User user2 = new User("Lucàs", "Vabre", cal2.getTime(), User.Gender.MALE);
daoJpaUser.create(user1);
daoJpaUser.create(user2);
// Contenu de la BD après ajout
users = daoJpaUser.findAll();
for (User u : users) {
System.out.println(u.toString());
}
System.out.println();
EntityManagerProvider.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -4,9 +4,9 @@
* Pas de copyright, aucun droits
*/
package project.dao;
package uppa.project.dao;
import project.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.dao.jpa.Game_JPA_DAO_Factory;
/**
* Factory renvoyant une factory de DAO en fonction du support de persistance choisi
@@ -4,7 +4,7 @@
* Pas de copyright, aucun droits
*/
package project.dao;
package uppa.project.dao;
/**
* DAO abstrait et générique pour tout type de données
@@ -4,7 +4,7 @@
* Pas de copyright, aucun droits
*/
package project.dao;
package uppa.project.dao;
/**
* Exception spécifique aux problèmes d'accès aux données via un DAO
@@ -4,9 +4,9 @@
* Pas de copyright, aucun droits
*/
package project.dao;
package uppa.project.dao;
import project.pojo.*;
import uppa.project.pojo.*;
/**
* Fabrique abstraite de DAO pour le schéma sports
@@ -4,7 +4,7 @@
* Pas de copyright, aucun droits
*/
package project.dao;
package uppa.project.dao;
/**
* Type de support de persistance pour les données
@@ -1,13 +1,13 @@
package project.dao.jpa;
package uppa.project.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import project.EntityManagerProvider;
import project.dao.DAO;
import project.dao.DAOException;
import project.pojo.Game;
import uppa.project.EntityManagerProvider;
import uppa.project.dao.DAO;
import uppa.project.dao.DAOException;
import uppa.project.pojo.Game;
public class DAO_JPA_Game extends DAO<Game> {
@@ -1,13 +1,13 @@
package project.dao.jpa;
package uppa.project.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import project.EntityManagerProvider;
import project.dao.DAO;
import project.dao.DAOException;
import project.pojo.Player;
import uppa.project.EntityManagerProvider;
import uppa.project.dao.DAO;
import uppa.project.dao.DAOException;
import uppa.project.pojo.Player;
public class DAO_JPA_Player extends DAO<Player> {
@@ -1,13 +1,13 @@
package project.dao.jpa;
package uppa.project.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import project.dao.DAO;
import project.dao.DAOException;
import project.EntityManagerProvider;
import project.pojo.User;
import uppa.project.dao.DAO;
import uppa.project.dao.DAOException;
import uppa.project.EntityManagerProvider;
import uppa.project.pojo.User;
public class DAO_JPA_User extends DAO<User> {
@@ -4,12 +4,12 @@
* Pas de copyright, aucun droits
*/
package project.dao.jpa;
package uppa.project.dao.jpa;
import project.dao.DAO;
import project.pojo.*;
import project.dao.DAOException;
import project.dao.GameDAOFactory;
import uppa.project.dao.DAO;
import uppa.project.pojo.*;
import uppa.project.dao.DAOException;
import uppa.project.dao.GameDAOFactory;
/**
* Fabrique concrète de DAO pour le schéma relationnel sports avec une implémentation en JDBC.
@@ -1,13 +1,13 @@
package project.pojo;
package uppa.project.pojo;
public class Card {
public enum Color{coeur, carreau, pique, trèfle}
public enum Color{coeur, carreau, pique, trefle}
public enum Value{un, deux, trois, quatre, cinq, six, sept, huit, neuf, dix, valet, dame, roi}
private Color color;
private final Color color;
private Value value;
private final Value value;
public Card(Color color, Value value) {
this.color = color;
@@ -1,4 +1,4 @@
package project.pojo;
package uppa.project.pojo;
import java.util.ArrayList;
import java.util.Collections;
@@ -1,4 +1,4 @@
package project.pojo;
package uppa.project.pojo;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
@@ -23,52 +23,30 @@ import java.util.Set;
public class Game implements Serializable {
@Id
@Column(name = "id_game")
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@Temporal(TemporalType.DATE)
@Column(name="date")
private Date date;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="starting_time")
private Timestamp startTime;
@Column(name="created_at")
private Date createdAt;
@OneToMany(mappedBy = "game", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Player> players;
public Game() {
}
public Game(Date date, Timestamp startTime) {
this.date = date;
this.startTime = startTime;
}
@Override
public int hashCode() {
return Objects.hash(id, date);
return Objects.hash(id, createdAt, players);
}
public BigDecimal getId() {
return id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Timestamp getStartTime() {
return startTime;
}
public void setStartTime(Timestamp startTime) {
this.startTime = startTime;
public Date getCreatedAt() {
return createdAt;
}
public Set<Player> getPlayers() {
@@ -87,10 +65,6 @@ public class Game implements Serializable {
@Override
public String toString() {
return "Game{" +
"id=" + id +
", date=" + date +
", players=" + players +
'}';
return String.format("Game{id=%s, createdAt=%s, players=%s}", id.toString(), createdAt, players);
}
}
@@ -1,4 +1,4 @@
package project.pojo;
package uppa.project.pojo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -17,16 +17,16 @@ import java.util.Objects;
public class Player implements Serializable {
@Id
@Column(name = "id_player")
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@ManyToOne
@JoinColumn(name = "id_game", nullable = false)
@JoinColumn(name = "game_id", nullable = false)
private Game game;
@ManyToOne
@JoinColumn(name = "id_user", nullable = false)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(name = "score")
@@ -35,14 +35,14 @@ public class Player implements Serializable {
@Column(name = "winner")
private boolean winner;
@Column(name = "nb_clicks")
private int nbClicks;
@Column(name = "click_count")
private int clickCount;
@Column(name = "nb_right_clicks")
private int nbRightClicks;
@Column(name = "right_click_count")
private int rightClickCount;
@Column(name = "nb_rapid_clicks")
private int nbRapidClick;
@Column(name = "rapid_click_count")
private int rapidClickCount;
public Player() {
@@ -53,24 +53,24 @@ public class Player implements Serializable {
this.user = user;
this.score = 0;
this.winner = false;
this.nbClicks = 0;
this.nbRightClicks = 0;
this.nbRapidClick = 0;
this.clickCount = 0;
this.rightClickCount = 0;
this.rapidClickCount = 0;
}
public Player(Game game, User user, int score, boolean winner, int nbClicks, int nbRightClicks, int nbRapidClick) {
public Player(Game game, User user, int score, boolean winner, int clickCount, int rightClickCount, int rapidClickCount) {
this.game = game;
this.user = user;
this.score = score;
this.winner = winner;
this.nbClicks = nbClicks;
this.nbRightClicks = nbRightClicks;
this.nbRapidClick = nbRapidClick;
this.clickCount = clickCount;
this.rightClickCount = rightClickCount;
this.rapidClickCount = rapidClickCount;
}
@Override
public int hashCode() {
return Objects.hash(game, user, score, winner, nbClicks, nbRightClicks, nbRapidClick);
return Objects.hash(game, user, score, winner, clickCount, rightClickCount, rapidClickCount);
}
public Game getGame() {
@@ -107,51 +107,43 @@ public class Player implements Serializable {
this.winner = true;
}
public int getNbClicks() {
return nbClicks;
public int getClickCount() {
return clickCount;
}
public void setNbClicks(int nbClicks) {
this.nbClicks = nbClicks;
public void setClickCount(int clickCount) {
this.clickCount = clickCount;
}
public void addClick() {
this.nbClicks++;
public void incrementClickCount() {
clickCount++;
}
public int getNbRightClicks() {
return nbRightClicks;
public int getRightClickCount() {
return rightClickCount;
}
public void setNbRightClicks(int nbRightClicks) {
this.nbRightClicks = nbRightClicks;
public void setRightClickCount(int rightClickCount) {
this.rightClickCount = rightClickCount;
}
public void addRightClick() {
this.nbRapidClick++;
public void incrementRightClickCount() {
rightClickCount++;
}
public int getNbRapidClick() {
return nbRapidClick;
public int getRapidClickCount() {
return rapidClickCount;
}
public void setNbRapidClick(int nbRapidClick) {
this.nbRapidClick = nbRapidClick;
public void setRapidClickCount(int rapidClickCount) {
this.rapidClickCount = rapidClickCount;
}
public void addRapidClick() {
this.nbRapidClick++;
public void incrementRapidClickCount() {
rapidClickCount++;
}
@Override
public String toString() {
return "Player{" +
"game=" + game +
", user=" + user +
", score=" + score +
", winner=" + winner +
", nbClicks=" + nbClicks +
", nbRightClicks=" + nbRightClicks +
", nbRapidClick=" + nbRapidClick +
'}';
return String.format("Player{id=%s, game=%s, user=%s, score=%d, winner=%b, clickCount=%d, rightClickCount=%d, rapidClickCount=%d}", id.toString(), game.toString(), user.toString(), score, winner, clickCount, rightClickCount, rapidClickCount);
}
}
@@ -1,4 +1,4 @@
package project.pojo;
package uppa.project.pojo;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
@@ -15,45 +15,41 @@ import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import java.io.Serializable;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@Entity
@Table(name = "user")
public class User implements Serializable {
public enum Sexe {FEMME, HOMME, NONBINAIRE};
@Id
@Column(name = "id_user")
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Temporal(TemporalType.DATE)
@Column(name = "birth_date")
private Date bithDate;
@Column(name = "sexe")
@Enumerated( EnumType.STRING)
private Sexe sexe;
@Column(name = "birth")
private Date birth;
@Column(name = "gender")
@Enumerated(EnumType.STRING)
private Gender gender;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Player> playedGame;
public User() {}
public User(String username, String password, Date birthDate, Sexe sexe) {
this.username = username;
String hashedPassword = hashPassword(password);
this.password = hashedPassword;
this.bithDate = birthDate;
this.sexe = sexe;
public User() {
}
public User(String username, String password, Date birth, Gender gender) {
this.username = username;
this.password = hashPassword(password);
this.birth = birth;
this.gender = gender;
}
public User(BigDecimal id, String username, String password) {
@@ -64,11 +60,13 @@ public class User implements Serializable {
@Override
public int hashCode() {
return Objects.hash(id, username, password, bithDate, sexe);
return Objects.hash(id, username, password, birth, gender);
}
public BigDecimal getId(){
public BigDecimal getId() {
return id;
}
public String getUsername() {
return username;
}
@@ -82,29 +80,30 @@ public class User implements Serializable {
}
public void setPassword(String password) {
String hashedPassword = hashPassword(password);
this.password = hashedPassword;
this.password = hashPassword(password);
}
public Date getBithDate() {
return bithDate;
public Date getBirth() {
return birth;
}
public void setBithDate(Date bithDate) {
this.bithDate = bithDate;
public void setBirth(Date birth) {
this.birth = birth;
}
public Sexe getSexe() {
return sexe;
public Gender getGender() {
return gender;
}
public void setSexe(Sexe sexe) {
this.sexe = sexe;
public void setGender(Gender gender) {
this.gender = gender;
}
public int getAge(){
//TODO: Implement this function
return 1;
public int getAge() {
Date currentDate = new Date();
long diff = currentDate.getTime() - birth.getTime();
long diffDays = diff / (24 * 60 * 60 * 1000);
return (int) (diffDays / 365);
}
private String hashPassword(String password) {
@@ -134,11 +133,8 @@ public class User implements Serializable {
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", age=" + getAge() +
", sexe=" + sexe +
'}';
return String.format("User{id=%s, username='%s', birth=%s, gender=%s}", id.toString(), username, birth.toString(), gender.toString());
}
public enum Gender {MALE, FEMALE, OTHER}
}
@@ -0,0 +1,27 @@
package uppa.project.servlet;
import java.io.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;
public void init() {
message = "Hello World!";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
public void destroy() {
}
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
bean-discovery-mode="annotated">
</beans>
@@ -1,14 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://jakarta.ee/xml/ns/persistence"
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="default">
<persistence-unit name="db">
<class>project.pojo.User</class>
<class>project.pojo.Game</class>
<class>project.pojo.Player</class>
<exclude-unlisted-classes></exclude-unlisted-classes>
<class>uppa.project.pojo.User</class>
<class>uppa.project.pojo.Game</class>
<class>uppa.project.pojo.Player</class>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
</web-app>
@@ -0,0 +1,12 @@
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %></h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
</body>
</html>