Compare commits

...

4 Commits

21 changed files with 289 additions and 178 deletions

View File

@@ -69,6 +69,11 @@
<artifactId>jakarta.validation-api</artifactId> <artifactId>jakarta.validation-api</artifactId>
<version>3.1.0</version> <version>3.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
@@ -79,16 +84,6 @@
<artifactId>reflections</artifactId> <artifactId>reflections</artifactId>
<version>0.10.2</version> <version>0.10.2</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.17.0</version>
</dependency>
<!-- JAX-RS (Jersey) --> <!-- JAX-RS (Jersey) -->
<dependency> <dependency>

View File

@@ -1,10 +1,12 @@
package com.humanbooster; package com.humanbooster;
import com.humanbooster.client.RestClient;
import com.humanbooster.config.HibernateConfig; import com.humanbooster.config.HibernateConfig;
import com.humanbooster.config.ServerConfig; import com.humanbooster.config.ServerConfig;
import com.humanbooster.dao.AdDao; import com.humanbooster.dao.AdDao;
import com.humanbooster.dao.ArticleDao; import com.humanbooster.dao.ArticleDao;
import com.humanbooster.dao.UserDao; import com.humanbooster.dao.UserDao;
import com.humanbooster.factory.DataFactory;
import com.humanbooster.model.Ad; import com.humanbooster.model.Ad;
import com.humanbooster.model.Article; import com.humanbooster.model.Article;
import com.humanbooster.model.User; import com.humanbooster.model.User;
@@ -12,19 +14,19 @@ import com.humanbooster.service.AdService;
import com.humanbooster.service.ArticleService; import com.humanbooster.service.ArticleService;
import com.humanbooster.service.UserService; import com.humanbooster.service.UserService;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List; import java.util.List;
public class App { public class App {
public static final boolean LOCAL_ENVIRONMENT = true;
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("Démarrage de l'application"); System.out.println("Démarrage de l'application");
RestClient client = new RestClient();
try { try {
ServerConfig serverConfig = new ServerConfig(); ServerConfig serverConfig = new ServerConfig();
serverConfig.startServer(); serverConfig.startServer();
@@ -32,58 +34,18 @@ public class App {
System.out.println("Erreur lors du démarrage du serveur : " + e.getMessage()); System.out.println("Erreur lors du démarrage du serveur : " + e.getMessage());
} }
SessionFactory sessionFactory; SessionFactory sessionFactory = new HibernateConfig().getSessionFactory();
if (HibernateConfig.isLocalEnvironment()) sessionFactory = HibernateConfig.getSessionFactory();
else {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure()
.build();
Metadata metadata = new MetadataSources(registry).buildMetadata();
sessionFactory = metadata.buildSessionFactory();
}
User user = new User("Bob", "bob@example.com", null);
user.setArticles(List.of(
new Article("Article 1", "Contenu de l'article 1", LocalDate.now(), user, 0),
new Article("Article 2", "Contenu de l'article 2", LocalDate.now(), user, 0)
));
List<Ad> ads = List.of(
(new Ad(
"Ad 1",
"Contenu de l'annonce 1",
LocalDate.now(),
LocalDate.now().plusDays(7),
"contact@example.com",
BigDecimal.valueOf(12))),
(new Ad(
"Ad 2",
"Contenu de l'annonce 2",
LocalDate.now(),
LocalDate.now().plusDays(10),
"contact@example.com",
BigDecimal.valueOf(6.7)))
);
UserService userService = new UserService(new UserDao(sessionFactory)); UserService userService = new UserService(new UserDao(sessionFactory));
ArticleService articleService = new ArticleService(new ArticleDao(sessionFactory)); ArticleService articleService = new ArticleService(new ArticleDao(sessionFactory));
AdService adService = new AdService(new AdDao(sessionFactory)); AdService adService = new AdService(new AdDao(sessionFactory));
DataFactory dataFactory = new DataFactory();
cleanDatabase(userService, articleService, adService); cleanDatabase(userService, articleService, adService);
userService.createUser(user); userService.createUser(dataFactory.createUser("Michel", "michel@test.fr"));
dataFactory.createAds().forEach(adService::createAd);
articleService.findArticlesByCriteria("test", 3L, 1, 1).forEach(article -> {
System.out.println("\nArticle trouvé :" + article.toString());
}
);
ads.forEach(adService::createAd);
sessionFactory.close(); sessionFactory.close();
System.out.print("Fin du programme"); System.out.print("Fin du programme");

View File

@@ -1,6 +0,0 @@
package com.humanbooster.annotation;
public @interface Pair {
String message() default "Le nombre doit être pair";
}

View File

@@ -1,12 +0,0 @@
package com.humanbooster.annotation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class PairValidator implements ConstraintValidator<Pair, Integer> {
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
return (integer != null) && (integer % 2 == 0);
}
}

View File

@@ -1,11 +0,0 @@
package com.humanbooster.api;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
public class ApiApplication extends ResourceConfig {
public ApiApplication() {
packages("com.humanbooster");
register(JacksonFeature.class);
}
}

View File

@@ -0,0 +1,63 @@
package com.humanbooster.client;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class RestClient {
private final HttpClient httpClient = HttpClient.newHttpClient();
public String sendGetRequest(String url, String method, String body) {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json");
switch (method.toUpperCase()) {
case "GET":
builder.GET();
break;
case "POST":
builder.POST(HttpRequest.BodyPublishers.ofString(body));
break;
case "PUT":
builder.PUT(HttpRequest.BodyPublishers.ofString(body));
break;
case "DELETE":
builder.DELETE();
break;
default:
throw new IllegalArgumentException("Invalid HTTP method: " + method);
}
HttpRequest request = builder.build();
HttpResponse<String> response;
try {
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return parseResponse(response.body());
} catch (Exception e) {
System.err.println("Error occurred while sending the request: " + e.getMessage());
}
return null;
}
private String parseResponse(String response) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode jsonNode = mapper.readTree(response);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
} catch (Exception e) {
System.err.println("Error occurred while parsing the response: " + e.getMessage());
}
return null;
}
}

View File

@@ -1,6 +1,11 @@
package com.humanbooster.config; package com.humanbooster.config;
import com.humanbooster.App;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.reflections.Reflections; import org.reflections.Reflections;
@@ -8,28 +13,16 @@ import jakarta.persistence.Entity;
public class HibernateConfig { public class HibernateConfig {
private static final SessionFactory sessionFactory; public SessionFactory getSessionFactory() {
private static final boolean LOCAL = true;
private static String url;
private static String username;
private static String password;
static { SessionFactory sessionFactory;
if (LOCAL) { if (App.LOCAL_ENVIRONMENT) {
url = "jdbc:mysql://127.0.0.1:3306/testdb";
username = "admin";
password = "admin";
} else {
url = "jdbc:mysql://mysql:3306/testdb?useSSL=false&amp;allowPublicKeyRetrieval=true";
username = "root";
password = "root";
}
Configuration config = new Configuration() Configuration config = new Configuration()
.setProperty("hibernate.connection.url", url) .setProperty("hibernate.connection.url", "jdbc:mysql://127.0.0.1:3306/testdb")
.setProperty("hibernate.connection.username", username) .setProperty("hibernate.connection.username", "admin")
.setProperty("hibernate.connection.password", password) .setProperty("hibernate.connection.password", "admin")
.setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver") .setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver")
.setProperty("hibernate.hbm2ddl.auto", "update") .setProperty("hibernate.hbm2ddl.auto", "update")
.setProperty("hibernate.show_sql", "false") .setProperty("hibernate.show_sql", "false")
@@ -40,15 +33,16 @@ public class HibernateConfig {
config.addAnnotatedClass(clazz); config.addAnnotatedClass(clazz);
} }
sessionFactory = config.buildSessionFactory(); return sessionFactory = config.buildSessionFactory();
}
public static SessionFactory getSessionFactory() { } else {
return sessionFactory; StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
} .configure()
.build();
public static boolean isLocalEnvironment() { Metadata metadata = new MetadataSources(registry).buildMetadata();
return LOCAL; return sessionFactory = metadata.buildSessionFactory();
}
} }
} }

View File

@@ -1,18 +1,23 @@
package com.humanbooster.config; package com.humanbooster.config;
import com.humanbooster.api.ApiApplication;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletContainer;
public class ServerConfig { public class ServerConfig extends ResourceConfig {
public ServerConfig() {
packages("com.humanbooster");
register(JacksonFeature.class);
}
public void startServer() throws Exception { public void startServer() throws Exception {
System.out.println("Starting server..."); System.out.println("Lancement du serveur...");
ResourceConfig config = new ApiApplication(); ResourceConfig config = this;
ServletHolder servlet = new ServletHolder(new ServletContainer(config)); ServletHolder servlet = new ServletHolder(new ServletContainer(config));
Server server = new Server(80); Server server = new Server(80);
@@ -23,10 +28,10 @@ public class ServerConfig {
try { try {
server.start(); server.start();
System.out.println("Server started on port 80"); System.out.println("Serveur démarré sur le port 80");
server.join(); server.join();
} catch (Exception e) { } catch (Exception e) {
System.out.println("Failed to start server: " + e.getMessage()); System.out.println("Echec lors du lancement du serveur: " + e.getMessage());
} }
} }
} }

View File

@@ -0,0 +1,20 @@
package com.humanbooster.controller;
import com.humanbooster.config.HibernateConfig;
import com.humanbooster.dao.ArticleDao;
import com.humanbooster.dao.GenericDao;
import com.humanbooster.model.Article;
import jakarta.ws.rs.Path;
import org.hibernate.SessionFactory;
@Path("/articles")
public class ArticleController extends GenericControllerImpl<Article, Long> {
public ArticleController() {
this(new HibernateConfig().getSessionFactory(), new ArticleDao(new HibernateConfig().getSessionFactory()));
}
public ArticleController(SessionFactory sessionFactory, GenericDao<Article, Long> dao) {
super(sessionFactory, dao);
}
}

View File

@@ -0,0 +1,11 @@
package com.humanbooster.controller;
import java.util.List;
public interface GenericController<T, ID> {
void create(T entity);
T read(ID id);
void update(ID id);
void delete(ID id);
List<T> getAll();
}

View File

@@ -0,0 +1,55 @@
package com.humanbooster.controller;
import com.humanbooster.config.HibernateConfig;
import com.humanbooster.dao.GenericDao;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import org.hibernate.SessionFactory;
import java.util.List;
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public abstract class GenericControllerImpl<T, ID> implements GenericController<T, ID>, GenericDao<T, ID> {
protected final SessionFactory sessionFactory;
private final GenericDao<T, ID> dao;
public GenericControllerImpl(SessionFactory sessionFactory, GenericDao<T, ID> dao) {
this.sessionFactory = sessionFactory;
this.dao = dao;
}
@POST
@Override
public void create(T entity) {
dao.create(entity);
}
@GET
@Path("/{id}")
@Override
public T read(@PathParam("id") ID id) {
return dao.read(id);
}
@PUT
@Path("/{id}")
@Override
public void update(@PathParam("id") ID id) {
dao.update(id);
}
@DELETE
@Path("/{id}")
@Override
public void delete(@PathParam("id") ID id) {
dao.delete(id);
}
@GET
@Override
public List<T> getAll() {
return dao.getAll();
}
}

View File

@@ -7,44 +7,17 @@ import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import java.util.List;
@Path("/users") @Path("/users")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public class UserController { public class UserController extends GenericControllerImpl<User, Long> {
SessionFactory sessionFactory = HibernateConfig.getSessionFactory(); public UserController() {
this(new HibernateConfig().getSessionFactory(), new UserDao(new HibernateConfig().getSessionFactory()));
private final UserDao dao = new UserDao(sessionFactory);
@GET
public List<User> getAll() {
return dao.findAll();
} }
@GET public UserController(SessionFactory sessionFactory, UserDao userDao) {
@Path("/{id}") super(sessionFactory, userDao);
public User getById(@PathParam("id") Long id) {
return dao.read(id);
}
@POST
public void create(User person) {
dao.create(person);
}
@PUT
@Path("/{id}")
public void update(@PathParam("id") Long id, User user) {
user.setId(id);
dao.update(user);
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") Long id) {
System.out.println();
dao.delete(id);
} }
} }

View File

@@ -5,7 +5,7 @@ import java.util.List;
public interface GenericDao<T, ID> { public interface GenericDao<T, ID> {
void create(T entity); void create(T entity);
T read(ID id); T read(ID id);
void update(T entity); void update(ID id);
void delete(ID id); void delete(ID id);
List<T> findAll(); List<T> getAll();
} }

View File

@@ -35,9 +35,10 @@ public abstract class GenericDaoImpl<T, ID> implements GenericDao<T, ID> {
} }
@Override @Override
public void update(T entity) { public void update(ID id) {
try (Session session = sessionFactory.openSession()) { try (Session session = sessionFactory.openSession()) {
session.beginTransaction(); session.beginTransaction();
T entity = session.get(entityClass, id);
session.merge(entity); session.merge(entity);
session.getTransaction().commit(); session.getTransaction().commit();
} }
@@ -54,7 +55,7 @@ public abstract class GenericDaoImpl<T, ID> implements GenericDao<T, ID> {
} }
@Override @Override
public List<T> findAll() { public List<T> getAll() {
try (Session session = sessionFactory.openSession()) { try (Session session = sessionFactory.openSession()) {
session.beginTransaction(); session.beginTransaction();
List<T> entities = session.createQuery("from " + entityClass.getName(), entityClass).list(); List<T> entities = session.createQuery("from " + entityClass.getName(), entityClass).list();

View File

@@ -0,0 +1,43 @@
package com.humanbooster.factory;
import com.humanbooster.model.Ad;
import com.humanbooster.model.Article;
import com.humanbooster.model.User;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public class DataFactory {
public User createUser(String name, String email) {
User user = new User(name, email, null);
user.setArticles(List.of(
new Article("Article 1", "Contenu de l'article 1", LocalDate.now(), user, 0),
new Article("Article 2", "Contenu de l'article 2", LocalDate.now(), user, 0)
));
return user;
}
public List<Ad> createAds() {
return List.of(
(new Ad(
"Ad 1",
"Contenu de l'annonce 1",
LocalDate.now(),
LocalDate.now().plusDays(7),
"contact@example.com",
BigDecimal.valueOf(12))),
(new Ad(
"Ad 2",
"Contenu de l'annonce 2",
LocalDate.now(),
LocalDate.now().plusDays(10),
"contact@example.com",
BigDecimal.valueOf(6.7)))
);
}
}

View File

@@ -1,5 +1,6 @@
package com.humanbooster.model; package com.humanbooster.model;
import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.LocalDate; import java.time.LocalDate;
@@ -9,6 +10,7 @@ public class Article extends Publication {
@ManyToOne @ManyToOne
@JoinColumn(name="author_id", nullable = false) @JoinColumn(name="author_id", nullable = false)
@JsonBackReference
private User author; private User author;
private int views = 0; private int views = 0;

View File

@@ -1,5 +1,6 @@
package com.humanbooster.model; package com.humanbooster.model;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@@ -19,6 +20,7 @@ public class User {
private String email; private String email;
@OneToMany(mappedBy="author", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) @OneToMany(mappedBy="author", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JsonManagedReference
private List<Article> articles; private List<Article> articles;
public User() {} public User() {}

View File

@@ -15,8 +15,8 @@ public record AdService (AdDao adDao) {
return adDao.read(id); return adDao.read(id);
} }
public void updateAd(Ad ad) { public void updateAd(Long id) {
adDao.update(ad); adDao.update(id);
} }
public void deleteAd(Long id) { public void deleteAd(Long id) {
@@ -24,6 +24,6 @@ public record AdService (AdDao adDao) {
} }
public List<Ad> getAllAds() { public List<Ad> getAllAds() {
return adDao.findAll(); return adDao.getAll();
} }
} }

View File

@@ -15,8 +15,8 @@ public record ArticleService(ArticleDao articleDao) {
articleDao.read(id); articleDao.read(id);
} }
public void updateArticle(Article article) { public void updateArticle(Long id) {
articleDao.update(article); articleDao.update(id);
} }
public void deleteArticle(Long id) { public void deleteArticle(Long id) {
@@ -24,7 +24,7 @@ public record ArticleService(ArticleDao articleDao) {
} }
public List<Article> getAllArticles() { public List<Article> getAllArticles() {
return articleDao.findAll(); return articleDao.getAll();
} }
public Article findArticleByAuthor(String author) { public Article findArticleByAuthor(String author) {

View File

@@ -15,8 +15,8 @@ public record UserService (UserDao userDao) {
userDao.read(id); userDao.read(id);
} }
public void updateUser(User user) { public void updateUser(Long id) {
userDao.update(user); userDao.update(id);
} }
public void deleteUser(Long id) { public void deleteUser(Long id) {
@@ -24,7 +24,7 @@ public record UserService (UserDao userDao) {
} }
public List<User> getAllUsers() { public List<User> getAllUsers() {
return userDao.findAll(); return userDao.getAll();
} }
public User findUserByEmail(String email) { public User findUserByEmail(String email) {

View File

@@ -0,0 +1,14 @@
### GET request to example server
GET http://localhost/users
###
POST http://localhost/users/
Content-Type: application/json
{
"name": "John Doe",
"email": "john.doe@example.com"
}
###
DELETE http://localhost/articles/13