Lab4 in progress

This commit is contained in:
Katerina881 2023-03-21 10:21:00 +04:00
parent 2096215195
commit cbf4b0b9a3
20 changed files with 344 additions and 101 deletions

View File

@ -18,6 +18,7 @@ dependencies {
implementation 'com.h2database:h2:2.1.210' implementation 'com.h2database:h2:2.1.210'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.hibernate.validator:hibernate-validator'
} }
tasks.named('test') { tasks.named('test') {

View File

@ -0,0 +1,35 @@
package np.something.DTO;
import np.something.model.Comment;
import np.something.model.Customer;
import np.something.model.Post;
public class CommentDto {
public final long id;
public final String content;
public final Customer customer;
public final Post post;
public CommentDto(Comment comment) {
this.id = comment.getId();
this.content = comment.getContent();
this.customer = comment.getCustomer();
this.post = comment.getPost();
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
public Customer getCustomer() {
return customer;
}
public Post getPost() {
return post;
}
}

View File

@ -0,0 +1,43 @@
package np.something.DTO;
import np.something.model.Comment;
import np.something.model.Customer;
import np.something.model.Post;
import java.util.List;
public class CustomerDto {
public final long id;
public final String username;
public final String hashedPassword;
public final List<Comment> comments;
public final List<Post> posts;
public CustomerDto(Customer customer) {
this.id = customer.getId();
this.username = customer.getUsername();
this.hashedPassword = customer.getPassword();
this.comments = customer.getComments();
this.posts = customer.getPosts();
}
public long getId() {
return id;
}
public String getUsername() {
return username;
}
public String getHashedPassword() {
return hashedPassword;
}
public List<Comment> getComments() {
return comments;
}
public List<Post> getPosts() {
return posts;
}
}

View File

@ -0,0 +1,43 @@
package np.something.DTO;
import np.something.model.Comment;
import np.something.model.Customer;
import np.something.model.Post;
import java.util.List;
public class PostDto {
public final long id;
public final String title;
public final String content;
public final Customer customer;
public final List<Comment> comments;
public PostDto(Post post) {
this.id = post.getId();
this.title = post.getTitle();
this.content = post.getContent();
this.customer = post.getCustomer();
this.comments = post.getComments();
}
public long getId() {
return id;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public Customer getCustomer() {
return customer;
}
public List<Comment> getComments() {
return comments;
}
}

View File

@ -0,0 +1,7 @@
package np.something.Exceptions;
public class CommentNotFoundException extends RuntimeException {
public CommentNotFoundException(Long id) {
super(String.format("Comment with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,7 @@
package np.something.Exceptions;
public class CustomerNotFoundException extends RuntimeException {
public CustomerNotFoundException(Long id) {
super(String.format("Customer with id [%s] is not found", id));
}
}

View File

@ -0,0 +1,7 @@
package np.something.Exceptions;
public class PostNotFoundException extends RuntimeException {
public PostNotFoundException(Long id) {
super(String.format("Post with id [%s] is not found", id));
}
}

View File

@ -1,6 +1,7 @@
package np.something.model; package np.something.model;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.Objects; import java.util.Objects;
@ -11,6 +12,7 @@ public class Comment {
private Long id; private Long id;
@Column @Column
@NotBlank(message = "Content cannot be empty")
private String content; private String content;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)

View File

@ -1,6 +1,7 @@
package np.something.model; package np.something.model;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.*; import java.util.*;
@ -10,9 +11,11 @@ public class Customer {
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private Long id; private Long id;
@Column @Column
@NotBlank(message = "Username cannot be empty")
private String username; private String username;
@Column @Column
private String hashedPassword; @NotBlank(message = "Password cannot be empty")
private String password;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL) @OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL)
private List<Comment> comments; private List<Comment> comments;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL) @OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL)
@ -22,9 +25,9 @@ public class Customer {
} }
public Customer(String username, String hashedPassword) { public Customer(String username, String password) {
this.username = username; this.username = username;
this.hashedPassword = hashedPassword; this.password = password;
this.comments = new ArrayList<>(); this.comments = new ArrayList<>();
this.posts = new ArrayList<>(); this.posts = new ArrayList<>();
} }
@ -37,8 +40,8 @@ public class Customer {
return username; return username;
} }
public String getHashedPassword() { public String getPassword() {
return hashedPassword; return password;
} }
public List<Comment> getComments() { public List<Comment> getComments() {
@ -53,8 +56,8 @@ public class Customer {
this.username = username; this.username = username;
} }
public void setHashedPassword(String hashedPassword) { public void setPassword(String password) {
this.hashedPassword = hashedPassword; this.password = password;
} }
@Override @Override

View File

@ -1,6 +1,7 @@
package np.something.model; package np.something.model;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -12,9 +13,11 @@ public class Post {
private Long id; private Long id;
@Column @Column
@NotBlank(message = "Title cannot be empty")
private String title; private String title;
@Column @Column
@NotBlank(message = "Content cannot be empty")
private String content; private String content;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)

View File

@ -0,0 +1,7 @@
package np.something.repositories;
import np.something.model.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CommentRepository extends JpaRepository<Comment, Long> {
}

View File

@ -0,0 +1,7 @@
package np.something.repositories;
import np.something.model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}

View File

@ -0,0 +1,7 @@
package np.something.repositories;
import np.something.model.Post;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post, Long> {
}

View File

@ -1,72 +1,67 @@
package np.something.services; package np.something.services;
import jakarta.persistence.EntityManager; import np.something.Exceptions.CommentNotFoundException;
import jakarta.persistence.EntityNotFoundException; import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import np.something.model.Comment; import np.something.model.Comment;
import np.something.model.Customer; import np.something.model.Customer;
import np.something.model.Post; import np.something.model.Post;
import np.something.repositories.CommentRepository;
import np.something.util.validation.ValidatorUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List; import java.util.List;
import java.util.Optional;
@Service @Service
public class CommentService { public class CommentService {
@PersistenceContext private final CommentRepository commentRepository;
private EntityManager em; private final ValidatorUtil validatorUtil;
@Transactional public CommentService(CommentRepository commentRepository,
ValidatorUtil validatorUtil) {
this.commentRepository = commentRepository;
this.validatorUtil = validatorUtil;
}
@Transactional(readOnly = true)
public Comment findComment(Long id) { public Comment findComment(Long id) {
final Comment comment = em.find(Comment.class, id); final Optional<Comment> comment = commentRepository.findById(id);
if (comment == null) { return comment.orElseThrow(() -> new CommentNotFoundException(id));
throw new EntityNotFoundException(String.format("Comment with id [%s] is not found", id));
}
return comment;
} }
@Transactional @Transactional(readOnly = true)
public List<Comment> findAllComments() { public List<Comment> findAllComments() {
return em.createQuery("select c from Comment c", Comment.class).getResultList(); return commentRepository.findAll();
} }
@Transactional @Transactional
public Comment addComment(Customer customer, Post post, String content) { public Comment addComment(Customer customer, Post post, String content) {
if (customer == null || post == null) {
throw new IllegalArgumentException("Invalid customer or post");
}
if (!StringUtils.hasText(content)) {
throw new IllegalArgumentException("Invalid comment's content");
}
final Comment comment = new Comment(customer, post, content); final Comment comment = new Comment(customer, post, content);
comment.getCustomer().getComments().add(comment); validatorUtil.validate(comment);
comment.getPost().getComments().add(comment); customer.getComments().add(comment);
em.persist(comment); post.getComments().add(comment);
return comment; return commentRepository.save(comment);
} }
@Transactional @Transactional
public Comment updateComment(Long id, String content) { public Comment updateComment(Long id, String content) {
if (!StringUtils.hasText(content)) { final Comment currentComment = findComment(id);
throw new IllegalArgumentException("Comment's content is empty"); currentComment.setContent(content);
} validatorUtil.validate(currentComment);
final Comment comment = findComment(id); return commentRepository.save(currentComment);
comment.setContent(content);
return em.merge(comment);
} }
@Transactional @Transactional
public Comment deleteComment(Long id) { public Comment deleteComment(Long id) {
final Comment currentComment = findComment(id); final Comment currentComment = findComment(id);
commentRepository.delete(currentComment);
currentComment.getPost().getComments().remove(currentComment); currentComment.getPost().getComments().remove(currentComment);
currentComment.getCustomer().getComments().remove(currentComment); currentComment.getCustomer().getComments().remove(currentComment);
em.remove(currentComment);
return currentComment; return currentComment;
} }
@Transactional @Transactional
public void deleteAllComment() { public void deleteAllComments() {
em.createQuery("delete from Comment").executeUpdate(); commentRepository.deleteAll();
} }
} }

View File

@ -4,7 +4,11 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import np.something.Exceptions.CustomerNotFoundException;
import np.something.model.Customer; import np.something.model.Customer;
import np.something.repositories.CommentRepository;
import np.something.repositories.CustomerRepository;
import np.something.util.validation.ValidatorUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -12,53 +16,50 @@ import java.util.List;
@Service @Service
public class CustomerService { public class CustomerService {
@PersistenceContext private final CustomerRepository customerRepository;
private EntityManager em; private final ValidatorUtil validatorUtil;
public CustomerService(CustomerRepository customerRepository,
ValidatorUtil validatorUtil) {
this.customerRepository = customerRepository;
this.validatorUtil = validatorUtil;
}
@Transactional @Transactional
public Customer findCustomer(Long id) { public Customer findCustomer(Long id) {
final Customer customer = em.find(Customer.class, id); return customerRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id));
if (customer == null) {
throw new EntityNotFoundException(String.format("User with id [%s] is not found", id));
}
return customer;
} }
@Transactional @Transactional
public List<Customer> findAllCustomers() { public List<Customer> findAllCustomers() {
return em.createQuery("select c from Customer c", Customer.class).getResultList(); return customerRepository.findAll();
} }
@Transactional @Transactional
public Customer addCustomer(String username, String password) { public Customer addCustomer(String username, String password) {
if (!StringUtils.hasText(username) || !StringUtils.hasText(password)) { Customer customer = new Customer(username, password);
throw new IllegalArgumentException("Customer's username or password is empty"); validatorUtil.validate(customer);
} return customerRepository.save(customer);
final Customer customer = new Customer(username, password);
em.persist(customer);
return customer;
} }
@Transactional @Transactional
public Customer updateCustomer(Long id, String username, String password) { public Customer updateCustomer(Long id, String username, String password) {
if (!StringUtils.hasText(username) || !StringUtils.hasText(password)) { Customer customer = findCustomer(id);
throw new IllegalArgumentException("Customer's username or password is empty");
}
final Customer customer = findCustomer(id);
customer.setUsername(username); customer.setUsername(username);
customer.setHashedPassword(password); customer.setPassword(password);
return em.merge(customer); validatorUtil.validate(customer);
return customerRepository.save(customer);
} }
@Transactional @Transactional
public Customer deleteCustomer(Long id) { public Customer deleteCustomer(Long id) {
final Customer currentCustomer = findCustomer(id); Customer customer = findCustomer(id);
em.remove(currentCustomer); customerRepository.delete(customer);
return currentCustomer; return customer;
} }
@Transactional @Transactional
public void deleteAllCustomers() { public void deleteAllCustomers() {
em.createQuery("delete from Customer").executeUpdate(); customerRepository.deleteAll();
} }
} }

View File

@ -4,9 +4,13 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional; import jakarta.transaction.Transactional;
import np.something.Exceptions.PostNotFoundException;
import np.something.model.Comment; import np.something.model.Comment;
import np.something.model.Customer; import np.something.model.Customer;
import np.something.model.Post; import np.something.model.Post;
import np.something.repositories.CustomerRepository;
import np.something.repositories.PostRepository;
import np.something.util.validation.ValidatorUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -14,58 +18,52 @@ import java.util.List;
@Service @Service
public class PostService { public class PostService {
@PersistenceContext private final PostRepository postRepository;
private EntityManager em; private final ValidatorUtil validatorUtil;
public PostService(PostRepository postRepository,
ValidatorUtil validatorUtil) {
this.postRepository = postRepository;
this.validatorUtil = validatorUtil;
}
@Transactional @Transactional
public Post findPost(Long id) { public Post findPost(Long id) {
final Post post = em.find(Post.class, id); return postRepository.findById(id).orElseThrow(() -> new PostNotFoundException(id));
if (post == null) {
throw new EntityNotFoundException(String.format("Post with id [%s] is not found", id));
}
return post;
} }
@Transactional @Transactional
public List<Post> findAllPosts() { public List<Post> findAllPosts() {
return em.createQuery("select p from Post p", Post.class).getResultList(); return postRepository.findAll();
} }
@Transactional @Transactional
public Post addPost(Customer customer, String title, String content) { public Post addPost(Customer customer, String title, String content) {
if (customer == null) { Post post = new Post(customer, title, content);
throw new IllegalArgumentException("Invalid customer"); validatorUtil.validate(post);
} customer.getPosts().add(post);
if (!StringUtils.hasText(title) | !StringUtils.hasText(content)) { return postRepository.save(post);
throw new IllegalArgumentException("Invalid post's content or title");
}
final Post post = new Post(customer, title, content);
post.getCustomer().getPosts().add(post);
em.persist(post);
return post;
} }
@Transactional @Transactional
public Post updatePost(Long id, String title, String content) { public Post updatePost(Long id, String title, String content) {
if (!StringUtils.hasText(content) | !StringUtils.hasText(title)) { Post post = findPost(id);
throw new IllegalArgumentException("Post's content or title is empty");
}
final Post post = findPost(id);
post.setTitle(title); post.setTitle(title);
post.setContent(content); post.setContent(content);
return em.merge(post); validatorUtil.validate(post);
return postRepository.save(post);
} }
@Transactional @Transactional
public Post deletePost(Long id) { public Post deletePost(Long id) {
final Post currentPost = findPost(id); Post post = findPost(id);
currentPost.getCustomer().getPosts().remove(currentPost); post.getCustomer().getPosts().remove(post);
em.remove(currentPost); postRepository.delete(post);
return currentPost; return post;
} }
@Transactional @Transactional
public void deleteAllPosts() { public void deleteAllPosts() {
em.createQuery("delete from Post").executeUpdate(); postRepository.deleteAll();
} }
} }

View File

@ -0,0 +1,38 @@
package np.something.util.error;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import ru.ulstu.is.sbapp.student.service.StudentNotFoundException;
import ru.ulstu.is.sbapp.util.validation.ValidationException;
import java.util.stream.Collectors;
@ControllerAdvice
public class AdviceController {
@ExceptionHandler({
StudentNotFoundException.class,
ValidationException.class
})
public ResponseEntity<Object> handleException(Throwable e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleBindException(MethodArgumentNotValidException e) {
final ValidationException validationException = new ValidationException(
e.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toSet()));
return handleException(validationException);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleUnknownException(Throwable e) {
e.printStackTrace();
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

View File

@ -0,0 +1,9 @@
package np.something.util.validation;
import java.util.Set;
public class ValidationException extends RuntimeException {
public ValidationException(Set<String> errors) {
super(String.join("\n", errors));
}
}

View File

@ -0,0 +1,30 @@
package np.something.util.validation;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidatorUtil {
private final Validator validator;
public ValidatorUtil() {
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
this.validator = factory.getValidator();
}
}
public <T> void validate(T object) {
final Set<ConstraintViolation<T>> errors = validator.validate(object);
if (!errors.isEmpty()) {
throw new ValidationException(errors.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toSet()));
}
}
}

View File

@ -22,7 +22,7 @@ public class SocialNetworkTest {
@Test @Test
void testCustomers() { void testCustomers() {
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
@ -43,16 +43,16 @@ public class SocialNetworkTest {
Customer c4 = customerService.updateCustomer(c3.getId(), "fourth", "4"); Customer c4 = customerService.updateCustomer(c3.getId(), "fourth", "4");
Assertions.assertNotEquals(c3.getUsername(), c4.getUsername()); Assertions.assertNotEquals(c3.getUsername(), c4.getUsername());
Assertions.assertNotEquals(c3.getHashedPassword(), c4.getHashedPassword()); Assertions.assertNotEquals(c3.getPassword(), c4.getPassword());
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
} }
@Test @Test
void testPost() { void testPost() {
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
@ -82,14 +82,14 @@ public class SocialNetworkTest {
Assertions.assertNotEquals(p2.getTitle(), p4.getTitle()); Assertions.assertNotEquals(p2.getTitle(), p4.getTitle());
Assertions.assertNotEquals(p2.getContent(), p4.getContent()); Assertions.assertNotEquals(p2.getContent(), p4.getContent());
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
} }
@Test @Test
void testComment() { void testComment() {
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
@ -116,7 +116,7 @@ public class SocialNetworkTest {
Assertions.assertNotEquals(com3.getContent(), com4.getContent()); Assertions.assertNotEquals(com3.getContent(), com4.getContent());
Assertions.assertEquals(com3.getCustomer().getId(), com4.getCustomer().getId()); Assertions.assertEquals(com3.getCustomer().getId(), com4.getCustomer().getId());
commentService.deleteAllComment(); commentService.deleteAllComments();
postService.deleteAllPosts(); postService.deleteAllPosts();
customerService.deleteAllCustomers(); customerService.deleteAllCustomers();
} }