feat : Add ExceptionHandler, Image and User Controller

TommyVersion
tomivt 3 weeks ago
parent 236378e0cb
commit 53f9a0b8aa

@ -6,7 +6,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>wtf</artifactId>
@ -51,7 +51,8 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

@ -0,0 +1,101 @@
package com.example.wtf.controller;
import com.example.wtf.exception.ResourceNotFound;
import com.example.wtf.model.Image;
import com.example.wtf.repository.ImageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController
@RequestMapping("/images")
public class ImageController {
@Autowired
private ImageRepository repository;
@GetMapping("/get")
public @ResponseBody CollectionModel<EntityModel<Image>> getImages() {
List<EntityModel<Image>> images = new ArrayList<>();
for (Image image : repository.findAll()) {
EntityModel<Image> imageResource = EntityModel.of(
image,
linkTo(methodOn(ImageController.class).getImage(image.getId())).withSelfRel(),
linkTo(methodOn(ImageController.class).updateImage(image.getId(), new Image())).withRel("Update Image"),
linkTo(methodOn(ImageController.class).deleteImage(image.getId())).withRel("Delete Image")
);
images.add(imageResource);
}
return CollectionModel.of(
images,
linkTo(methodOn(ImageController.class).addImage(new Image())).withRel("Add Image")
);
}
@GetMapping("/get/{id}")
public @ResponseBody EntityModel<Image> getImage(@PathVariable Long id) {
Image image = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Image not found"));
return EntityModel.of(
image,
linkTo(methodOn(ImageController.class).updateImage(image.getId(), new Image())).withRel("Update Image"),
linkTo(methodOn(ImageController.class).deleteImage(image.getId())).withRel("Delete Image"),
linkTo(methodOn(ImageController.class).getImages()).withRel("Images")
);
}
@PostMapping("/add")
public @ResponseBody EntityModel<Image> addImage(@RequestBody Image image) {
repository.save(image);
return EntityModel.of(
image,
linkTo(methodOn(ImageController.class).getImage(image.getId())).withSelfRel(),
linkTo(methodOn(ImageController.class).updateImage(image.getId(), new Image())).withRel("Update Image"),
linkTo(methodOn(ImageController.class).deleteImage(image.getId())).withRel("Delete Image"),
linkTo(methodOn(ImageController.class).getImages()).withRel("Images")
);
}
@PutMapping("/update/{id}")
public @ResponseBody EntityModel<Image> updateImage(@PathVariable Long id,
@RequestBody Image update) {
Image image = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Image not found"));
if (update.getPath() != null && !update.getPath().isEmpty()) {
image.setPath(update.getPath());
}
repository.save(image);
return EntityModel.of(
image,
linkTo(methodOn(ImageController.class).getImage(id)).withSelfRel(),
linkTo(methodOn(ImageController.class).deleteImage(id)).withRel("Delete Image"),
linkTo(methodOn(ImageController.class).getImages()).withRel("Images")
);
}
@DeleteMapping("delete/{id}")
public @ResponseBody EntityModel<Image> deleteImage(@PathVariable Long id) {
Image image = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Image not found"));
repository.delete(image);
return EntityModel.of(
image,
linkTo(methodOn(ImageController.class).getImages()).withRel("Images")
);
}
}

@ -0,0 +1,115 @@
package com.example.wtf.controller;
import com.example.wtf.exception.ResourceNotFound;
import com.example.wtf.model.Question;
import com.example.wtf.repository.QuestionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController
@RequestMapping("/questions")
public class QuestionController {
@Autowired
private QuestionRepository repository;
@GetMapping("/get")
public @ResponseBody CollectionModel<EntityModel<Question>> getQuestions() {
List<EntityModel<Question>> questions = new ArrayList<>();
for (Question question : repository.findAll()) {
EntityModel<Question> questionResource = EntityModel.of(
question,
linkTo(methodOn(QuestionController.class).getQuestion(question.getId())).withSelfRel(),
linkTo(methodOn(QuestionController.class).updateQuestion(question.getId(), new Question())).withRel("Update Question"),
linkTo(methodOn(QuestionController.class).deleteQuestion(question.getId())).withRel("Delete Question")
);
questions.add(questionResource);
}
return CollectionModel.of(
questions,
linkTo(methodOn(QuestionController.class).addQuestion(new Question())).withRel("Add Question")
);
}
@GetMapping("/get/{id}")
public @ResponseBody EntityModel<Question> getQuestion(@PathVariable Long id) {
Question question = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Question not found"));
return EntityModel.of(
question,
linkTo(methodOn(QuestionController.class).updateQuestion(question.getId(), new Question())).withRel("Update Question"),
linkTo(methodOn(QuestionController.class).deleteQuestion(question.getId())).withRel("Delete Question"),
linkTo(methodOn(QuestionController.class).getQuestions()).withRel("Questions")
);
}
@PostMapping("/add")
public @ResponseBody EntityModel<Question> addQuestion(@RequestBody Question question) {
repository.save(question);
return EntityModel.of(
question,
linkTo(methodOn(QuestionController.class).getQuestion(question.getId())).withSelfRel(),
linkTo(methodOn(QuestionController.class).updateQuestion(question.getId(), new Question())).withRel("Update Question"),
linkTo(methodOn(QuestionController.class).deleteQuestion(question.getId())).withRel("Delete Question"),
linkTo(methodOn(QuestionController.class).getQuestions()).withRel("Questions")
);
}
@PutMapping("/update/{id}")
public @ResponseBody EntityModel<Question> updateQuestion(@PathVariable Long id,
@RequestBody Question update) {
Question question = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Question not found"));
if (update.getContent() != null && !update.getContent().isEmpty()) {
question.setContent(update.getContent());
}
if (update.getAnswerA() != null && !update.getAnswerA().isEmpty()) {
question.setAnswerA(update.getAnswerA());
}
if (update.getAnswerB() != null && !update.getAnswerB().isEmpty()) {
question.setAnswerB(update.getAnswerB());
}
if (update.getAnswerC() != null && !update.getAnswerC().isEmpty()) {
question.setAnswerC(update.getAnswerC());
}
if (update.getAnswerD() != null && !update.getAnswerD().isEmpty()) {
question.setAnswerD(update.getAnswerD());
}
if (update.getcAnswer() != null && !update.getcAnswer().isEmpty()) {
question.setcAnswer(update.getcAnswer());
}
repository.save(question);
return EntityModel.of(
question,
linkTo(methodOn(QuestionController.class).getQuestion(id)).withSelfRel(),
linkTo(methodOn(QuestionController.class).deleteQuestion(id)).withRel("Delete Question"),
linkTo(methodOn(QuestionController.class).getQuestions()).withRel("Questions")
);
}
@DeleteMapping("delete/{id}")
public @ResponseBody EntityModel<Question> deleteQuestion(@PathVariable Long id) {
Question question = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("Question not found"));
repository.delete(question);
return EntityModel.of(
question,
linkTo(methodOn(QuestionController.class).getQuestions()).withRel("Questions")
);
}
}

@ -0,0 +1,137 @@
package com.example.wtf.controller;
import com.example.wtf.exception.ResourceForbidden;
import com.example.wtf.exception.ResourceNotFound;
import com.example.wtf.model.Image;
import com.example.wtf.model.User;
import com.example.wtf.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository repository;
@GetMapping("/get")
public @ResponseBody CollectionModel<EntityModel<User>> getUsers() {
List<EntityModel<User>> users = new ArrayList<>();
for (User user : repository.findAll()) {
EntityModel<User> userResource = EntityModel.of(
user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel(),
linkTo(methodOn(UserController.class).updateUser(user.getId(), new User())).withRel("Update user"),
linkTo(methodOn(UserController.class).deleteUser(user.getId())).withRel("Delete user")
);
users.add(userResource);
}
return CollectionModel.of(
users,
linkTo(methodOn(UserController.class).addUser(new User())).withRel("Add User")
);
}
@GetMapping("/get/{id}")
public @ResponseBody EntityModel<User> getUser(@PathVariable Long id) {
User user = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("User not found"));
return EntityModel.of(
user,
linkTo(methodOn(UserController.class).updateUser(user.getId(), new User())).withRel("Update user"),
linkTo(methodOn(UserController.class).deleteUser(user.getId())).withRel("Delete user"),
linkTo(methodOn(UserController.class).getUsers()).withRel("Users")
);
}
@PostMapping("/add")
public @ResponseBody EntityModel<User> addUser(@RequestBody User user) {
if (repository.existsByUsername(user.getUsername())) {
throw new ResourceForbidden("Username forbidden");
}
if (repository.existsByEmail(user.getEmail())) {
throw new ResourceForbidden("Email forbidden");
}
if (user.getImage() == null) {
user.setImage(new Image("/default/path"));
}
if (user.getCreation() == null) {
user.setCreation(LocalDate.now());
}
repository.save(user);
return EntityModel.of(
user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel(),
linkTo(methodOn(UserController.class).updateUser(user.getId(), new User())).withRel("Update user"),
linkTo(methodOn(UserController.class).deleteUser(user.getId())).withRel("Delete user"),
linkTo(methodOn(UserController.class).getUsers()).withRel("Users")
);
}
@PutMapping("/update/{id}")
public @ResponseBody EntityModel<User> updateUser(@PathVariable Long id,
@RequestBody User update) {
User user = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("User not found"));
if (update.getUsername() != null && !update.getUsername().isEmpty()) {
if (repository.existsByUsername(user.getUsername())) {
throw new ResourceForbidden("Username forbidden");
}
user.setUsername(update.getUsername());
}
if (update.getEmail() != null && !update.getEmail().isEmpty()) {
if (repository.existsByEmail(user.getEmail())) {
throw new ResourceForbidden("Email forbidden");
}
user.setEmail(update.getEmail());
}
if (update.getPassword() != null && !update.getPassword().isEmpty()) {
user.setPassword(update.getPassword());
}
if (update.getImage() != null) {
user.setImage(update.getImage());
}
if (update.getCreation() != null) {
user.setCreation(update.getCreation());
}
repository.save(user);
return EntityModel.of(
user,
linkTo(methodOn(UserController.class).getUser(id)).withSelfRel(),
linkTo(methodOn(UserController.class).deleteUser(id)).withRel("Delete user"),
linkTo(methodOn(UserController.class).getUsers()).withRel("Users")
);
}
@DeleteMapping("delete/{id}")
public @ResponseBody EntityModel<User> deleteUser(@PathVariable Long id) {
User user = repository.findById(id)
.orElseThrow(() -> new ResourceNotFound("User not found"));
repository.delete(user);
return EntityModel.of(
user,
linkTo(methodOn(UserController.class).getUsers()).withRel("Users")
);
}
}

@ -1,114 +0,0 @@
package com.example.wtf.controller;
import com.example.wtf.exception.ResourceNotFound;
import com.example.wtf.model.Question;
import com.example.wtf.repository.questionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController
@RequestMapping("/questions")
public class questionController {
@Autowired
private questionRepository repo;
@GetMapping("/get")
public @ResponseBody CollectionModel<EntityModel<Question>> getQuestions() {
List<EntityModel<Question>> questions = new ArrayList<>();
for (Question question : repo.findAll()) {
EntityModel<Question> questionResource = EntityModel.of(
question,
linkTo(methodOn(questionController.class).getQuestion(question.getId())).withSelfRel(),
linkTo(methodOn(questionController.class).updateQuestion(question.getId(), null)).withRel("Update question"),
linkTo(methodOn(questionController.class).deleteQuestion(question.getId())).withRel("Delete question")
);
questions.add(questionResource);
}
return CollectionModel.of(
questions,
linkTo(methodOn(questionController.class).addQuestion(null)).withRel("Add Question")
);
}
@GetMapping("/get/{id}")
public @ResponseBody EntityModel<Question> getQuestion(@PathVariable Long id) {
Question question = repo.findQuestionById(id);
if (question == null) {
throw new ResourceNotFound(HttpStatus.NOT_FOUND, "Question not found");
}
return EntityModel.of(
question,
linkTo(methodOn(questionController.class).updateQuestion(question.getId(), null)).withRel("Update question"),
linkTo(methodOn(questionController.class).deleteQuestion(question.getId())).withRel("Delete question"),
linkTo(methodOn(questionController.class).getQuestions()).withRel("Questions")
);
}
@PostMapping("/add")
public @ResponseBody EntityModel<Question> addQuestion(@RequestBody Question question) {
repo.save(question);
return EntityModel.of(
question,
linkTo(methodOn(questionController.class).getQuestion(question.getId())).withSelfRel(),
linkTo(methodOn(questionController.class).updateQuestion(question.getId(), null)).withRel("Update question"),
linkTo(methodOn(questionController.class).deleteQuestion(question.getId())).withRel("Delete question"),
linkTo(methodOn(questionController.class).getQuestions()).withRel("Questions")
);
}
@PutMapping("/update/{id}")
public @ResponseBody EntityModel<Question> updateQuestion(@PathVariable Long id,
@RequestBody Question question) {
Question q = repo.findQuestionById(id);
if (q == null) throw new ResourceNotFound(HttpStatus.NOT_FOUND, "Question not found");
if (question.getContent() != null && !question.getContent().isEmpty()) {
q.setContent(question.getContent());
}
if (question.getAnswerA() != null && !question.getAnswerA().isEmpty()) {
q.setAnswerA(question.getAnswerA());
}
if (question.getAnswerB() != null && !question.getAnswerB().isEmpty()) {
q.setAnswerB(question.getAnswerB());
}
if (question.getAnswerC() != null && !question.getAnswerC().isEmpty()) {
q.setAnswerC(question.getAnswerC());
}
if (question.getAnswerD() != null && !question.getAnswerD().isEmpty()) {
q.setAnswerD(question.getAnswerD());
}
if (question.getcAnswer() != null && !question.getcAnswer().isEmpty()) {
q.setcAnswer(question.getcAnswer());
}
repo.save(q);
return EntityModel.of(
q,
linkTo(methodOn(questionController.class).getQuestion(id)).withSelfRel(),
linkTo(methodOn(questionController.class).deleteQuestion(id)).withRel("Delete question"),
linkTo(methodOn(questionController.class).getQuestions()).withRel("Questions")
);
}
@DeleteMapping("delete/{id}")
public @ResponseBody EntityModel<Question> deleteQuestion(@PathVariable Long id) {
Question q = repo.findQuestionById(id);
if (q == null) throw new ResourceNotFound(HttpStatus.NOT_FOUND, "Question not found");
repo.delete(q);
return EntityModel.of(
q,
linkTo(methodOn(questionController.class).getQuestions()).withRel("Questions")
);
}
}

@ -0,0 +1,26 @@
package com.example.wtf.exception;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAllExceptions(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred : " + ex.getMessage());
}
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointerException(NullPointerException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Null pointer exception caught : " + ex.getMessage());
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found : " + ex.getMessage());
}
}

@ -0,0 +1,11 @@
package com.example.wtf.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.FORBIDDEN)
public class ResourceForbidden extends RuntimeException {
public ResourceForbidden(String message) {
super(message);
}
}

@ -1,10 +1,11 @@
package com.example.wtf.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.bind.annotation.ResponseStatus;
public class ResourceNotFound extends ResponseStatusException {
public ResourceNotFound(HttpStatus error, String message) {
super(error, message);
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFound extends RuntimeException {
public ResourceNotFound(String message) {
super(message);
}
}

@ -0,0 +1,29 @@
package com.example.wtf.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Image {
@GeneratedValue(strategy= GenerationType.IDENTITY)
private @Id Long id;
private String path;
public Image(String path) {
this.path = path;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
}

@ -4,12 +4,16 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.*;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Question {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private @Id Long id;
private String content;
private String answerA;
@ -18,70 +22,24 @@ public class Question {
private String answerD;
private String cAnswer;
public Question() {}
public Question(String content, String answerB, String answerA, String answerC, String answerD, String cAnswer) {
this.content = content;
this.answerB = answerB;
this.answerA = answerA;
this.answerC = answerC;
this.answerD = answerD;
this.cAnswer = cAnswer;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAnswerA() {
return answerA;
}
public void setAnswerA(String answerA) {
this.answerA = answerA;
}
public String getAnswerB() {
return answerB;
}
public void setAnswerB(String answerB) {
this.answerB = answerB;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getAnswerC() {
return answerC;
}
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public void setAnswerC(String answerC) {
this.answerC = answerC;
}
public String getAnswerA() { return answerA; }
public void setAnswerA(String answerA) { this.answerA = answerA; }
public String getAnswerD() {
return answerD;
}
public String getAnswerB() { return answerB; }
public void setAnswerB(String answerB) { this.answerB = answerB; }
public void setAnswerD(String answerD) {
this.answerD = answerD;
}
public String getAnswerC() { return answerC; }
public void setAnswerC(String answerC) { this.answerC = answerC; }
public String getcAnswer() {
return cAnswer;
}
public String getAnswerD() { return answerD; }
public void setAnswerD(String answerD) { this.answerD = answerD; }
public void setcAnswer(String cAnswer) {
this.cAnswer = cAnswer;
}
public String getcAnswer() { return cAnswer; }
public void setcAnswer(String cAnswer) { this.cAnswer = cAnswer; }
}

@ -0,0 +1,49 @@
package com.example.wtf.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "app_user")
public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private @Id Long id;
private String username;
private String email;
private String password;
@ManyToOne(cascade = CascadeType.ALL)
private Image image;
private LocalDate creation;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public Image getImage() { return image; }
public void setImage(Image image) { this.image = image; }
public LocalDate getCreation() { return creation; }
public void setCreation(LocalDate creation) { this.creation = creation; }
}

@ -0,0 +1,12 @@
package com.example.wtf.repository;
import com.example.wtf.model.Image;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface ImageRepository extends CrudRepository<Image, Long> {
Optional<Image> findById(Long id);
}

@ -4,7 +4,9 @@ import com.example.wtf.model.Question;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface questionRepository extends CrudRepository<Question, Long> {
Question findQuestionById(Long id);
public interface QuestionRepository extends CrudRepository<Question, Long> {
Optional<Question> findById(Long id);
}

@ -0,0 +1,15 @@
package com.example.wtf.repository;
import com.example.wtf.model.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
Optional<User> findById(Long id);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
}
Loading…
Cancel
Save