├── src ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── entity │ │ │ ├── enums │ │ │ │ ├── PaymentEnum.java │ │ │ │ ├── TransactionsEnum.java │ │ │ │ └── Role.java │ │ │ ├── ClassEntity.java │ │ │ ├── Feedback.java │ │ │ ├── Major.java │ │ │ ├── Payment.java │ │ │ ├── Pet.java │ │ │ ├── OrderDetail.java │ │ │ ├── Koi.java │ │ │ ├── Transactions.java │ │ │ ├── Orders.java │ │ │ ├── Student.java │ │ │ └── Account.java │ │ │ ├── model │ │ │ ├── MajorRequest.java │ │ │ ├── NotificationFcm.java │ │ │ ├── OrdersDetailRequest.java │ │ │ ├── AccountResponse.java │ │ │ ├── EmailDetail.java │ │ │ ├── OrdersRequest.java │ │ │ ├── forgotPass │ │ │ │ ├── ForgotPasswordRequest.java │ │ │ │ ├── FeedbackRequest.java │ │ │ │ └── ResetPasswordRequest.java │ │ │ ├── StudentResponse.java │ │ │ ├── LoginRequest.java │ │ │ ├── StudentRequest.java │ │ │ └── RegisterRequest.java │ │ │ ├── exception │ │ │ ├── DuplicateEntity.java │ │ │ ├── AccountException.java │ │ │ ├── AuthenticateException.java │ │ │ ├── NotFoundException.java │ │ │ └── ValidationHandler.java │ │ │ ├── repository │ │ │ ├── MajorRepository.java │ │ │ ├── PetRepository.java │ │ │ ├── FeedbackRepository.java │ │ │ ├── PaymentRepository.java │ │ │ ├── TransactionsRepository.java │ │ │ ├── KoiRepository.java │ │ │ ├── OrderRepository.java │ │ │ ├── AccountRepository.java │ │ │ └── StudentRepository.java │ │ │ ├── service │ │ │ ├── KoiService.java │ │ │ ├── MajorService.java │ │ │ ├── FeedbackService.java │ │ │ ├── PetService.java │ │ │ ├── AdminService.java │ │ │ ├── EmailService.java │ │ │ ├── TokenService.java │ │ │ ├── StudentService.java │ │ │ ├── AuthenticationService.java │ │ │ └── OrdersService.java │ │ │ ├── api │ │ │ ├── MajorAPI.java │ │ │ ├── DashboardAPI.java │ │ │ ├── OrdersAPI.java │ │ │ ├── KoiAPI.java │ │ │ ├── FeedbackAPI.java │ │ │ ├── PetAPI.java │ │ │ ├── StudentAPI.java │ │ │ └── AuthenticationAPI.java │ │ │ ├── config │ │ │ ├── ThymeleafConfig.java │ │ │ ├── SecurityConfig.java │ │ │ └── Filter.java │ │ │ └── DemoApplication.java │ └── resources │ │ └── templates │ │ └── welcome-template.html └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java ├── .gitignore ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── pom.xml ├── mvnw.cmd └── mvnw /src/main/java/com/example/demo/entity/enums/PaymentEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity.enums; 2 | 3 | public enum PaymentEnum { 4 | BANKING, 5 | CASH 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/enums/TransactionsEnum.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity.enums; 2 | 3 | public enum TransactionsEnum { 4 | SUCCESS, 5 | FAILED 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/MajorRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class MajorRequest { 7 | String code; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/enums/Role.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity.enums; 2 | 3 | public enum Role { 4 | STUDENT, 5 | TEACHER, 6 | 7 | ADMIN, 8 | CUSTOMER, 9 | OWNER 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/exception/DuplicateEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.exception; 2 | 3 | public class DuplicateEntity extends RuntimeException{ 4 | public DuplicateEntity(String mess){ 5 | super(mess); 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/exception/AccountException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.exception; 2 | 3 | public class AccountException extends RuntimeException{ 4 | public AccountException(String mess) 5 | { 6 | super(mess); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/NotificationFcm.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class NotificationFcm { 7 | String title; 8 | String message; 9 | String fcmToken; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/OrdersDetailRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.UUID; 6 | 7 | @Data 8 | public class OrdersDetailRequest { 9 | UUID koiId; 10 | int quantity; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/exception/AuthenticateException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.exception; 2 | 3 | public class AuthenticateException extends RuntimeException{ 4 | public AuthenticateException(String mess) 5 | { 6 | super(mess); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/exception/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.exception; 2 | 3 | public class NotFoundException extends RuntimeException{ 4 | public NotFoundException(String mess){ 5 | 6 | super(mess); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/AccountResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class AccountResponse { 7 | long Id; 8 | String email; 9 | String phone; 10 | String studentCode; 11 | String token; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/EmailDetail.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import com.example.demo.entity.Account; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class EmailDetail { 8 | Account receiver; 9 | String subject; 10 | String link; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/MajorRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Major; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface MajorRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/OrdersRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import com.example.demo.entity.OrderDetail; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class OrdersRequest { 10 | List details; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/PetRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Pet; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface PetRepository extends JpaRepository { 7 | Pet findPetById(long Id); 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/com/example/demo/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/forgotPass/ForgotPasswordRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.forgotPass; 2 | 3 | import jakarta.validation.constraints.Email; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class ForgotPasswordRequest { 8 | @Email(message = "Email is not valid") 9 | String email; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/FeedbackRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Feedback; 4 | import com.example.demo.entity.Major; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface FeedbackRepository extends JpaRepository { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/forgotPass/FeedbackRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.forgotPass; 2 | 3 | import com.example.demo.model.OrdersDetailRequest; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class FeedbackRequest { 10 | String content; 11 | int rating; 12 | long shopId; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/StudentResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import com.example.demo.entity.Student; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class StudentResponse { 10 | List content; 11 | int pageNumbers; 12 | int totalElements; 13 | int totalPages; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class LoginRequest { 13 | String email; 14 | String password; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/PaymentRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Major; 4 | import com.example.demo.entity.Payment; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface PaymentRepository extends JpaRepository { 8 | Payment findPaymentById(Long id); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/TransactionsRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Koi; 4 | import com.example.demo.entity.Transactions; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import java.util.UUID; 8 | 9 | public interface TransactionsRepository extends JpaRepository { 10 | Koi findTransactionsById(long id); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/forgotPass/ResetPasswordRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model.forgotPass; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.Size; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class ResetPasswordRequest { 9 | @NotBlank(message = "Password can not be blank") 10 | @Size(min = 6, message = "Password must more than 6 letter") 11 | String password; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/KoiRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Koi; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | public interface KoiRepository extends JpaRepository { 11 | Koi findKoiById(UUID id); 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/ClassEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Data; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | @Entity 10 | @Data 11 | public class ClassEntity { 12 | 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | long id; 16 | 17 | String name; 18 | 19 | @ManyToMany(mappedBy = "classEntities") 20 | List students = new ArrayList<>(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Feedback.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Data; 5 | 6 | @Entity 7 | @Data 8 | public class Feedback { 9 | @Id 10 | @GeneratedValue(strategy = GenerationType.IDENTITY) 11 | long id; 12 | 13 | String content; 14 | 15 | int rating; 16 | 17 | @ManyToOne 18 | @JoinColumn(name = "customer_id") 19 | Account customer; 20 | 21 | @ManyToOne 22 | @JoinColumn(name = "shop_id") 23 | Account shop; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.entity.Koi; 5 | import com.example.demo.entity.Orders; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Query; 8 | 9 | import java.util.List; 10 | import java.util.UUID; 11 | 12 | public interface OrderRepository extends JpaRepository { 13 | List findOrdersByCustomer(Account account); 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Major.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | import java.util.Set; 10 | @AllArgsConstructor 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | @Entity 15 | public class Major { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | long id; 19 | 20 | @Column(unique = true) 21 | String code; 22 | 23 | @OneToMany(mappedBy = "major") 24 | Set students; 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | ### App prop ### 36 | application.properties 37 | *.log 38 | fcm-credentials.json -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/KoiService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Koi; 4 | import com.example.demo.repository.KoiRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.List; 9 | 10 | @Service 11 | public class KoiService { 12 | 13 | @Autowired 14 | KoiRepository koiRepository; 15 | 16 | public Koi create(Koi koi){ 17 | return koiRepository.save(koi); 18 | } 19 | 20 | public List getAll(){ 21 | return koiRepository.findAll(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Payment.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.example.demo.entity.enums.PaymentEnum; 4 | import jakarta.persistence.*; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | import java.util.List; 9 | 10 | @Entity 11 | @Data 12 | public class Payment { 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | long id; 16 | 17 | Date createAt; 18 | 19 | PaymentEnum paymentMethod; 20 | 21 | @OneToOne 22 | @JoinColumn(name = "order_id") 23 | Orders order; 24 | 25 | @OneToMany(mappedBy = "payment") 26 | List transactions; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.entity.enums.Role; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.data.repository.query.Param; 8 | 9 | //dùng interface extend lại JpaRepository 10 | public interface AccountRepository extends JpaRepository { 11 | Account findByEmail(String email); 12 | Account findAccountByID(Long Id); 13 | 14 | @Query("SELECT COUNT(a) FROM Account a WHERE a.role = :role") 15 | long countByRole(@Param("role") Role role); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/repository/StudentRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.repository; 2 | 3 | import com.example.demo.entity.Student; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import java.util.List; 9 | 10 | public interface StudentRepository extends JpaRepository { 11 | // Tìm 1 thằng = id của nó 12 | // find + tên thực thể + by + (type data) 13 | // findStudentById(long id) 14 | Student findStudentById(long id); 15 | 16 | //lấy danh sách những th student có isDeleted = false; 17 | List findStudentsByIsDeletedFalse(); 18 | 19 | Page findAll(Pageable pageable); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/MajorAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | import com.example.demo.entity.Major; 4 | import com.example.demo.model.MajorRequest; 5 | import com.example.demo.service.MajorService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | @RestController 11 | @CrossOrigin("*") 12 | public class MajorAPI { 13 | 14 | @Autowired 15 | MajorService majorService; 16 | @PostMapping("/api/major") 17 | public ResponseEntity createMajor(@RequestBody MajorRequest majorRequest) { 18 | Major major = majorService.createMajor(majorRequest); 19 | return ResponseEntity.ok(major); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Pet.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import jakarta.persistence.*; 4 | import jakarta.validation.constraints.Min; 5 | import jakarta.validation.constraints.NotBlank; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Entity 16 | public class Pet { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | long Id; 21 | 22 | @NotBlank(message = "type can not be blank") 23 | String type; 24 | 25 | @NotBlank(message = "Id can not be blank") 26 | @Column(unique = true) 27 | String PetId; 28 | 29 | @Min(value = 0, message = "weight must be positive number") 30 | float weight; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/OrderDetail.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | import java.util.UUID; 11 | 12 | @Entity 13 | @Getter 14 | @Setter 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class OrderDetail { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.UUID) 21 | UUID id; 22 | 23 | int quantity; 24 | 25 | float price; 26 | 27 | @ManyToOne(cascade = CascadeType.ALL) 28 | @JoinColumn(name = "order_id") 29 | @JsonIgnore 30 | Orders order; 31 | 32 | @ManyToOne(cascade = CascadeType.ALL) 33 | @JsonIgnore 34 | @JoinColumn(name = "koi_id") 35 | Koi koi; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Koi.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | import java.util.List; 11 | import java.util.UUID; 12 | 13 | @Entity 14 | @Getter 15 | @Setter 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | public class Koi { 19 | 20 | @Id 21 | @GeneratedValue(strategy = GenerationType.UUID) 22 | UUID id; 23 | 24 | String image; 25 | String name; 26 | String description; 27 | float price; 28 | 29 | @OneToMany(mappedBy = "koi") 30 | @JsonIgnore 31 | List orderDetails; 32 | 33 | @ManyToOne 34 | @JoinColumn(name = "owner_id") 35 | @JsonIgnore 36 | Account account; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/MajorService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Major; 4 | import com.example.demo.model.MajorRequest; 5 | import com.example.demo.repository.MajorRepository; 6 | import org.modelmapper.ModelMapper; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class MajorService { 12 | @Autowired 13 | MajorRepository majorRepository; 14 | 15 | @Autowired 16 | ModelMapper modelMapper; 17 | 18 | public Major createMajor(MajorRequest majorRequest) { 19 | try{ 20 | Major major = modelMapper.map(majorRequest, Major.class); 21 | return majorRepository.save(major); 22 | }catch (Exception e){ 23 | e.printStackTrace(); 24 | } 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Transactions.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | 4 | import com.example.demo.entity.enums.TransactionsEnum; 5 | import jakarta.persistence.*; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | import java.util.Date; 12 | import java.util.UUID; 13 | @Entity 14 | @Getter 15 | @Setter 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | public class Transactions { 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.IDENTITY) 21 | long id; 22 | 23 | @ManyToOne 24 | @JoinColumn(name = "from_id") 25 | Account from; 26 | 27 | @ManyToOne 28 | @JoinColumn(name = "to_id") 29 | Account to; 30 | 31 | @ManyToOne 32 | @JoinColumn(name = "payment_id") 33 | Payment payment; 34 | 35 | TransactionsEnum status; 36 | 37 | String description; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/DashboardAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | import com.example.demo.service.AdminService; 4 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.CrossOrigin; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @CrossOrigin("*") //cho phép tất cả code truy cập 13 | @SecurityRequirement(name = "api") //bắt buộc có, nên nhớ 14 | public class DashboardAPI { 15 | 16 | @Autowired 17 | AdminService adminService; 18 | 19 | // @GetMapping("/api/dashboard") 20 | // public ResponseEntity getDashboardStats(){ 21 | // return ResponseEntity.ok(adminService.getDashboardStats()); 22 | // } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Orders.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | import java.util.Date; 11 | import java.util.List; 12 | import java.util.UUID; 13 | 14 | @Entity 15 | @Getter 16 | @Setter 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | public class Orders { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.UUID) 23 | UUID id; 24 | 25 | Date date; 26 | 27 | float total; 28 | 29 | @ManyToOne 30 | @JoinColumn(name = "customer_id") 31 | @JsonIgnore 32 | Account customer; 33 | 34 | @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) 35 | List orderDetails; 36 | 37 | @OneToOne(mappedBy = "order") 38 | Payment payment; 39 | } 40 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/StudentRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.validation.constraints.Max; 5 | import jakarta.validation.constraints.Min; 6 | import jakarta.validation.constraints.NotBlank; 7 | import jakarta.validation.constraints.Pattern; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | 13 | @Getter 14 | @Setter 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class StudentRequest { 18 | 19 | @NotBlank(message = "Name can not blank!") 20 | String name; 21 | 22 | @NotBlank(message = "Studen Code can not blank") //ngoài ra cần format partten SE000001 // 23 | @Pattern(regexp = "SE\\d{6}", message = "format must be |SExxxxxx| with x is numbers") 24 | @Column(unique = true) //duy nhất, không được trùng 25 | String studentCode; 26 | 27 | @Min(value = 0, message = "Score must be at least 0") 28 | @Max(value = 10, message = "Score must not be more than 10") 29 | float Score; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/model/RegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.model; 2 | 3 | import com.example.demo.entity.enums.Role; 4 | import jakarta.persistence.Column; 5 | import jakarta.validation.constraints.Email; 6 | import jakarta.validation.constraints.NotBlank; 7 | import jakarta.validation.constraints.Pattern; 8 | import jakarta.validation.constraints.Size; 9 | import lombok.Data; 10 | 11 | @Data 12 | public class RegisterRequest { 13 | @NotBlank(message = "not blank") 14 | @Pattern(regexp = "SE\\d{6}", message = "format must be |SExxxxxx| with x is numbers") 15 | @Column(unique = true) 16 | String studentCode; 17 | 18 | Role role; 19 | 20 | @Email(message = "Email not valid") 21 | @Column(unique = true) 22 | String email; 23 | 24 | @Pattern(regexp = "(84|0[3|5|7|8|9])+([0-9]{8})", message = "Invalid phone number!") 25 | @Column(unique = true) 26 | String phone; 27 | 28 | @NotBlank(message = "Password can not be blank") 29 | @Size(min = 6, message = "Password must more than 6 letter") 30 | String password; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/OrdersAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | 4 | import com.example.demo.entity.Orders; 5 | import com.example.demo.model.OrdersRequest; 6 | import com.example.demo.service.OrdersService; 7 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | @RestController 13 | @CrossOrigin("*") //cho phép tất cả code truy cập 14 | @SecurityRequirement(name = "api") //bắt buộc có, nên nhớ 15 | public class OrdersAPI { 16 | 17 | @Autowired 18 | OrdersService ordersService; 19 | 20 | @PostMapping("/api/orders") 21 | public ResponseEntity createOrder(@RequestBody OrdersRequest orderRequest) throws Exception { 22 | String vnpUrl = ordersService.createURL(orderRequest); 23 | return ResponseEntity.ok(vnpUrl); 24 | } 25 | 26 | @GetMapping("/api/orders") 27 | public ResponseEntity getOrders(){ 28 | return ResponseEntity.ok(ordersService.getOrdersByCustomer()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/KoiAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | import com.example.demo.entity.Koi; 4 | import com.example.demo.service.KoiService; 5 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | @CrossOrigin("*") //cho phép tất cả code truy cập 14 | @SecurityRequirement(name = "api") //bắt buộc có, nên nhớ 15 | public class KoiAPI { 16 | 17 | @Autowired 18 | KoiService koiService; 19 | 20 | @GetMapping("/api/koi") 21 | public ResponseEntity getAllKoi(){ 22 | List koi = koiService.getAll(); 23 | return ResponseEntity.ok(koi); 24 | } 25 | 26 | @PostMapping("/api/koi") 27 | public ResponseEntity createKoi(@RequestBody Koi koi){ 28 | Koi newKoi = koiService.create(koi); 29 | return ResponseEntity.ok(newKoi); 30 | } 31 | } 32 | 33 | // 1. API lấy danh sách lên => phân trang ở BE 34 | // 2. Tạo v lưu đơn hàng 35 | // 3. Lịch sử đơn hàng 36 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/FeedbackAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | import com.example.demo.entity.Feedback; 4 | import com.example.demo.model.forgotPass.FeedbackRequest; 5 | import com.example.demo.service.FeedbackService; 6 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.CrossOrigin; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | @RestController 15 | @CrossOrigin("*") //cho phép tất cả code truy cập 16 | @SecurityRequirement(name = "api") //bắt buộc có, nên nhớ 17 | public class FeedbackAPI { 18 | @Autowired 19 | FeedbackService feedbackService; 20 | 21 | @PostMapping("/api/feedback") 22 | public ResponseEntity createFeedback(@RequestBody FeedbackRequest feedbackRequest){ 23 | Feedback feedback = feedbackService.createNewFeedback(feedbackRequest); 24 | return ResponseEntity.ok(feedback); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/PetAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | 4 | import com.example.demo.entity.Pet; 5 | import com.example.demo.service.PetService; 6 | import jakarta.validation.Valid; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | @RestController 16 | public class PetAPI { 17 | @Autowired 18 | private PetService petService; 19 | 20 | @PostMapping("/api/pet") 21 | public ResponseEntity createPet(@Valid @RequestBody Pet pet) { 22 | Pet newPet = petService.createPet(pet); 23 | return ResponseEntity.ok(newPet); 24 | } 25 | 26 | @GetMapping("/api/pet") 27 | public ResponseEntity getAllPets() { 28 | return ResponseEntity.ok(petService.getAllPets()); 29 | } 30 | 31 | 32 | @DeleteMapping("/api/pet/{id}") 33 | public ResponseEntity deletePet(@PathVariable String id) { 34 | 35 | return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Pet not found"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/ThymeleafConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.thymeleaf.TemplateEngine; 6 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; 7 | 8 | @Configuration 9 | public class ThymeleafConfig { 10 | 11 | @Bean 12 | public ClassLoaderTemplateResolver templateResolver() { 13 | ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver(); 14 | templateResolver.setPrefix("templates/"); // Thư mục chứa template 15 | templateResolver.setSuffix(".html"); // Đuôi file template 16 | templateResolver.setTemplateMode("HTML5"); // Chế độ template (HTML5) 17 | templateResolver.setCharacterEncoding("UTF-8"); // Mã hóa ký tự 18 | templateResolver.setCacheable(false); // Không cache template trong quá trình phát triển 19 | return templateResolver; 20 | } 21 | 22 | @Bean 23 | public TemplateEngine templateEngine() { 24 | TemplateEngine templateEngine = new TemplateEngine(); 25 | templateEngine.setTemplateResolver(templateResolver()); // Sử dụng resolver ở trên 26 | return templateEngine; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/FeedbackService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.entity.Feedback; 5 | import com.example.demo.entity.Koi; 6 | import com.example.demo.exception.NotFoundException; 7 | import com.example.demo.model.forgotPass.FeedbackRequest; 8 | import com.example.demo.repository.AccountRepository; 9 | import com.example.demo.repository.FeedbackRepository; 10 | import com.example.demo.repository.KoiRepository; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.util.List; 15 | 16 | @Service 17 | public class FeedbackService { 18 | 19 | @Autowired 20 | FeedbackRepository feedbackRepository; 21 | 22 | @Autowired 23 | AuthenticationService authenticationService; 24 | 25 | @Autowired 26 | AccountRepository accountRepository; 27 | 28 | public Feedback createNewFeedback(FeedbackRequest feedbackRequest) { 29 | Account shop = accountRepository.findById(feedbackRequest.getShopId()) 30 | .orElseThrow(() -> new NotFoundException("Shop not found")); 31 | Feedback feedback = new Feedback(); 32 | feedback.setContent(feedbackRequest.getContent()); 33 | feedback.setRating(feedbackRequest.getRating()); 34 | feedback.setCustomer(authenticationService.getCurrentAccount()); 35 | feedback.setShop(shop); 36 | return feedbackRepository.save(feedback); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/PetService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Pet; 4 | import com.example.demo.exception.DuplicateEntity; 5 | import com.example.demo.exception.NotFoundException; 6 | import com.example.demo.repository.PetRepository; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | public class PetService { 14 | @Autowired 15 | PetRepository petRepository; 16 | 17 | public List getAllPets(){ 18 | List list = petRepository.findAll(); 19 | return list; 20 | } 21 | 22 | public Pet createPet(Pet pet){ 23 | try{ 24 | Pet newPet = petRepository.save(pet); 25 | return newPet; 26 | }catch (Exception e){ 27 | throw new DuplicateEntity("This pet is existed!!"); 28 | } 29 | 30 | } 31 | 32 | public Pet updatePet(Pet pet, long Id){ 33 | 34 | Pet oldPet = petRepository.findPetById(Id); 35 | if(oldPet == null){ 36 | throw new NotFoundException("Not found!"); 37 | } 38 | try{ 39 | oldPet.setPetId(pet.getPetId()); 40 | oldPet.setWeight(pet.getWeight()); 41 | oldPet.setType(pet.getType()); 42 | return petRepository.save(oldPet); 43 | }catch (Exception e){ 44 | throw new DuplicateEntity("This pet ID already existed!! Try another one"); 45 | } 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import io.swagger.v3.oas.annotations.OpenAPIDefinition; 4 | import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; 5 | import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; 6 | import io.swagger.v3.oas.annotations.info.Info; 7 | import io.swagger.v3.oas.annotations.security.SecurityScheme; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; 11 | 12 | @SpringBootApplication 13 | @OpenAPIDefinition(info = @Info(title = "Student API", version = "1.0", description = "Information")) 14 | @SecurityScheme(name = "api", scheme = "bearer", type = SecuritySchemeType.HTTP, in = SecuritySchemeIn.HEADER) 15 | public class DemoApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(DemoApplication.class, args); 19 | } 20 | // Resfull API 21 | // Cach đặt tên API 22 | 23 | // Thêm 1 sinh viên mới 24 | // /api/student => POST: tạo 1 thằng student mới 25 | // /api/student/studentId => PUT: update thông tin của student với id gì đấy. ví dụ /api/student/1 -> student với id=1 26 | // /api/student/studentId => GET: lấy thông tin của 1 thằng cụ thể /api/student/1 -> lấy info th có id=1 27 | // /api/student => GET: lấy tất cả student 28 | 29 | 30 | // METHOD: 31 | /* 32 | * POST => create 33 | * PUT => update 34 | * DELETE => delete 35 | * GET => get 36 | * 37 | **/ 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/AdminService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.enums.Role; 4 | import com.example.demo.repository.AccountRepository; 5 | import com.example.demo.repository.KoiRepository; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.security.Key; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | @Service 14 | public class AdminService { 15 | 16 | @Autowired 17 | KoiRepository koiRepository; 18 | 19 | @Autowired 20 | AccountRepository accountRepository; 21 | 22 | public Map getDashboardStats(){ 23 | 24 | Map stats = new HashMap<>(); 25 | 26 | //dem so luong san pham 27 | long totalProduct = koiRepository.count(); 28 | 29 | //dem so luong customer 30 | long totalCustomer = accountRepository.countByRole(Role.CUSTOMER); 31 | 32 | //dem so luong admin 33 | long totalAdmin = accountRepository.countByRole(Role.ADMIN); 34 | 35 | //dem so luong owner 36 | long totalOwner = accountRepository.countByRole(Role.OWNER); 37 | 38 | //dem so luong student 39 | long totalStudent = accountRepository.countByRole(Role.STUDENT); 40 | 41 | stats.put("totalProduct", totalProduct); 42 | stats.put("totalCustomer", totalCustomer); 43 | stats.put("totalAdmin", totalAdmin); 44 | stats.put("totalOwner", totalOwner); 45 | stats.put("totalStudent", totalStudent); 46 | 47 | return stats; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Student.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import jakarta.persistence.*; 5 | import jakarta.validation.constraints.Max; 6 | import jakarta.validation.constraints.Min; 7 | import jakarta.validation.constraints.NotBlank; 8 | import jakarta.validation.constraints.Pattern; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Getter; 11 | import lombok.NoArgsConstructor; 12 | import lombok.Setter; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | @Getter 18 | @Setter 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @Entity // để đánh dấu đây là 1 entity lưu xuống database, Data JPA giúp mình làm việc với DB, nếu chưa có => tự tạo dùm table 22 | public class Student { 23 | 24 | //Khóa chính 25 | @Id //đánh dấu đây là primary key 26 | @GeneratedValue(strategy = GenerationType.IDENTITY) //auto generate ra cột Id 27 | long Id; 28 | 29 | String name; 30 | 31 | 32 | @Column(unique = true) //duy nhất, không được trùng 33 | String studentCode; 34 | 35 | float Score; 36 | 37 | boolean isDeleted = false; 38 | 39 | @ManyToOne 40 | @JoinColumn(name = "account_id") 41 | Account account; 42 | 43 | @ManyToOne 44 | @JoinColumn(name = "major_id") 45 | @JsonIgnore 46 | Major major; 47 | 48 | @ManyToMany 49 | @JoinTable( 50 | name = "student_class", 51 | joinColumns = @JoinColumn(name = "student_id"), 52 | inverseJoinColumns = @JoinColumn(name = "class_id") 53 | ) 54 | List classEntities = new ArrayList<>(); 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/EmailService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.model.EmailDetail; 4 | import jakarta.mail.MessagingException; 5 | import jakarta.mail.internet.MimeMessage; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.mail.javamail.JavaMailSender; 8 | import org.springframework.mail.javamail.MimeMessageHelper; 9 | import org.springframework.stereotype.Service; 10 | import org.thymeleaf.TemplateEngine; 11 | import org.thymeleaf.context.Context; 12 | 13 | @Service 14 | public class EmailService { 15 | 16 | @Autowired 17 | TemplateEngine templateEngine; 18 | 19 | @Autowired 20 | JavaMailSender javaMailSender; 21 | 22 | public void sendEmail(EmailDetail emailDetail){ 23 | try { 24 | Context context = new Context(); 25 | context.setVariable("name",emailDetail.getReceiver().getEmail()); 26 | context.setVariable("button","Click here"); 27 | context.setVariable("link",emailDetail.getLink()); 28 | context.setVariable("subject",emailDetail.getSubject()); 29 | 30 | String template = templateEngine.process("welcome-template", context); 31 | // 32 | 33 | MimeMessage mimeMessage = javaMailSender.createMimeMessage(); 34 | MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage); 35 | 36 | mimeMessageHelper.setFrom("Koikichi@gmail.com"); 37 | mimeMessageHelper.setTo(emailDetail.getReceiver().getEmail()); 38 | mimeMessageHelper.setSubject(emailDetail.getSubject()); 39 | mimeMessageHelper.setText(template, true); 40 | javaMailSender.send(mimeMessage); 41 | }catch (MessagingException e){ 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/TokenService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.repository.AccountRepository; 5 | import io.jsonwebtoken.Claims; 6 | import io.jsonwebtoken.Jwts; 7 | import io.jsonwebtoken.SignatureAlgorithm; 8 | import io.jsonwebtoken.io.Decoders; 9 | import io.jsonwebtoken.security.Keys; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import javax.crypto.SecretKey; 14 | import java.util.Date; 15 | 16 | @Service 17 | // thằng này giúp tạo ra token và verify token 18 | public class TokenService { 19 | 20 | public final String SECRET_KEY = "4bb6d1dfbafb64a681139d1586b6f1160d18159afd57c8c79136d7490630407c"; 21 | 22 | @Autowired 23 | AccountRepository accountRepository; 24 | 25 | private SecretKey getSigninKey(){ 26 | byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY); //Decoders.BASE64.decode(SECRET_KEY): giải mã chuỗi thành mảng byte 27 | return Keys.hmacShaKeyFor(keyBytes); //Tạo một SecretKey cho HMAC-SHA từ mảng byte 28 | } 29 | 30 | // mỗi account từ FE gửi xuống BE sẽ nhận được 1 token riêng (mã định danh) 31 | public String generateToken(Account account){ 32 | String token = Jwts.builder().subject(account.getID()+"") 33 | .issuedAt(new Date(System.currentTimeMillis())) // thời gian khởi tạo, thời gian theo miligiay 34 | .expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) //thời gian hết hạn 35 | .signWith(getSigninKey()) 36 | .compact(); 37 | return token; 38 | } 39 | 40 | public Account getAccountByToken(String token){ 41 | Claims claims = Jwts.parser() 42 | .verifyWith(getSigninKey()) 43 | .build() 44 | .parseSignedClaims(token) 45 | .getPayload(); //lấy info từ token, jwt giải mã với signinKey, getPayload trả về Account thông tin và lưu trong claims 46 | 47 | String idString = claims.getSubject(); 48 | Long id = Long.parseLong(idString); 49 | return accountRepository.findAccountByID(id); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/StudentAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | import com.example.demo.entity.Student; 4 | import com.example.demo.exception.AccountException; 5 | import com.example.demo.exception.DuplicateEntity; 6 | import com.example.demo.exception.NotFoundException; 7 | import com.example.demo.model.StudentRequest; 8 | import com.example.demo.service.StudentService; 9 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 10 | import jakarta.validation.ConstraintViolationException; 11 | import jakarta.validation.Valid; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.dao.DataIntegrityViolationException; 14 | import org.springframework.data.domain.Page; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.security.access.prepost.PreAuthorize; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | @RestController //đánh dấu đây là controller api 23 | @CrossOrigin("*") //cho phép tất cả code truy cập 24 | @SecurityRequirement(name = "api") 25 | @PreAuthorize("hasAuthority('TEACHER')") 26 | public class StudentAPI { 27 | //thêm 1 sing viên mới 28 | // /api/student => POST 29 | 30 | @Autowired 31 | StudentService studentService; 32 | 33 | @PostMapping("/api/student") 34 | public ResponseEntity createStudent(@Valid @RequestBody StudentRequest student){ 35 | //@RequestBody lấy dữ liệu Student từ Front End để create, khi mình mark @RequestBody thì FE phải buộc gửi 1 object Student 36 | StudentRequest newStudent = studentService.createNewStudent(student); 37 | return ResponseEntity.ok(newStudent); 38 | } 39 | 40 | @GetMapping("/api/student") 41 | public ResponseEntity getAllStudent(@RequestParam int page, @RequestParam(defaultValue = "3") int size){ 42 | return ResponseEntity.ok(studentService.getAllStudent(page, size)); 43 | } 44 | 45 | @PutMapping("/api/student/{id}") 46 | public ResponseEntity updateStudent(@Valid @RequestBody Student student, @PathVariable long id ){ 47 | Student newStudent = studentService.updateStudent(student,id); 48 | return ResponseEntity.ok(newStudent); 49 | } 50 | 51 | @DeleteMapping("/api/student/{id}") 52 | public ResponseEntity deleteStudent(@PathVariable long id ){ 53 | Student newStudent = studentService.deleteStudent(id); 54 | return ResponseEntity.ok(newStudent); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/exception/ValidationHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.exception; 2 | 3 | import jakarta.validation.ConstraintViolationException; 4 | import org.springframework.dao.DataIntegrityViolationException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.validation.FieldError; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | import org.springframework.web.bind.annotation.RestControllerAdvice; 12 | 13 | import java.sql.SQLException; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | @RestControllerAdvice //đánh dấu đây là class handle exception cho spring boot hiểu 18 | public class ValidationHandler { 19 | //định nghĩa cho nó chạy mỗi khi nó gặp exception nào đó 20 | 21 | //MethodArgumentNotValidException là lỗi khi user nhập sai 22 | @ExceptionHandler(MethodArgumentNotValidException.class) 23 | // @ResponseStatus(HttpStatus.BAD_REQUEST) //response bad request, phải nhập lại input đúng valid 24 | public ResponseEntity handleValidation(MethodArgumentNotValidException ex){ 25 | String mess = ""; 26 | 27 | //cứ mỗi thuộc tính lỗi => xử lý 28 | for(FieldError fieldError : ex.getBindingResult().getFieldErrors()){ 29 | //fieldError là những field bị lỗi 30 | mess += fieldError.getField() + ": " + fieldError.getDefaultMessage() + ", "; 31 | } 32 | return new ResponseEntity(mess, HttpStatus.BAD_REQUEST); //bad request, phải nhập lại input đúng valid 33 | } 34 | 35 | @ExceptionHandler(DuplicateEntity.class) 36 | public ResponseEntity handleValidation(Exception ex) { 37 | return new ResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST); 38 | } 39 | 40 | // @ExceptionHandler(NotFoundException.class) 41 | // public ResponseEntity notFound(Exception ex) { 42 | // return new ResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST); 43 | // } 44 | 45 | @ExceptionHandler(NotFoundException.class) 46 | public ResponseEntity notFound(Exception ex) { 47 | Map error = new HashMap<>(); 48 | error.put("error", ex.getMessage()); 49 | return new ResponseEntity(error, HttpStatus.BAD_REQUEST); 50 | } 51 | 52 | @ExceptionHandler(AuthenticateException.class) 53 | public ResponseEntity authenticateException(Exception ex) { 54 | return new ResponseEntity(ex.getMessage(), HttpStatus.BAD_REQUEST); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/api/AuthenticationAPI.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.api; 2 | 3 | 4 | import com.example.demo.entity.Account; 5 | import com.example.demo.model.AccountResponse; 6 | import com.example.demo.model.forgotPass.ForgotPasswordRequest; 7 | import com.example.demo.model.LoginRequest; 8 | import com.example.demo.model.RegisterRequest; 9 | import com.example.demo.model.forgotPass.ResetPasswordRequest; 10 | import com.example.demo.service.AuthenticationService; 11 | import io.swagger.v3.oas.annotations.security.SecurityRequirement; 12 | import jakarta.validation.Valid; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import java.util.List; 18 | 19 | @RestController 20 | @CrossOrigin("*") //cho phép tất cả code truy cập 21 | @SecurityRequirement(name = "api") //bắt buộc có, nên nhớ 22 | public class AuthenticationAPI { 23 | 24 | //DI: Dependency Injection 25 | @Autowired 26 | AuthenticationService authenticationService; //tương tự new package: AuthenticationService a = new AuthenticationService(); 27 | @PostMapping("/api/register") 28 | public ResponseEntity register(@RequestBody @Valid RegisterRequest registerRequest) { 29 | //api nhận request và object từ FE, sau đó nhờ service xử lý, thông qua lớp authenticationService 30 | //bản chất API là chỉ nhận request và response 31 | AccountResponse newAccount = authenticationService.register(registerRequest); 32 | return ResponseEntity.ok(newAccount); 33 | } 34 | 35 | LoginRequest loginRequest; 36 | @PostMapping("/api/login") 37 | public ResponseEntity login(@RequestBody LoginRequest loginRequest) 38 | { 39 | AccountResponse a = authenticationService.login(loginRequest); 40 | return ResponseEntity.ok(a); 41 | } 42 | 43 | 44 | @GetMapping("/api/account") 45 | public ResponseEntity getAllAccounts() { 46 | List list = authenticationService.getAllAccounts(); 47 | return ResponseEntity.ok(list); 48 | } 49 | 50 | @PostMapping("/api/forgot-password") 51 | public ResponseEntity forgotPassword(@RequestBody @Valid ForgotPasswordRequest forgotPasswordRequest) { 52 | authenticationService.forgotPassword(forgotPasswordRequest); 53 | return ResponseEntity.ok("Email sent"); 54 | } 55 | 56 | @PostMapping("/api/reset-password") 57 | public ResponseEntity resetPassword(@RequestBody ResetPasswordRequest request) { 58 | authenticationService.resetPassword(request); 59 | return ResponseEntity.ok("Password reset successfully"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config; 2 | 3 | import com.example.demo.service.AuthenticationService; 4 | import org.modelmapper.ModelMapper; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.security.authentication.AuthenticationManager; 9 | import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; 10 | import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 11 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.security.crypto.password.PasswordEncoder; 14 | import org.springframework.security.web.SecurityFilterChain; 15 | 16 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 17 | import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; 18 | import org.springframework.security.config.http.SessionCreationPolicy; 19 | 20 | @Configuration //chỉ ra rằng lớp này chứa các cấu hình của ứng dụng. Khi ứng dụng khởi động, Spring sẽ quét và nạp các lớp được chú thích bằng @Configuration. 21 | @EnableMethodSecurity 22 | public class SecurityConfig { 23 | 24 | @Autowired 25 | AuthenticationService authenticationService; 26 | 27 | @Autowired 28 | Filter filter; 29 | 30 | @Bean //đánh dấu là thư viện khi sài chỉ cần gọi @Autowire 31 | public PasswordEncoder passwordEncoder(){ 32 | return new BCryptPasswordEncoder(); 33 | } 34 | 35 | @Bean public ModelMapper modelMapper(){ 36 | return new ModelMapper(); 37 | } 38 | 39 | @Bean 40 | public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception{ 41 | return configuration.getAuthenticationManager(); 42 | } 43 | 44 | @Bean 45 | public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 46 | return http 47 | .csrf(AbstractHttpConfigurer::disable) 48 | .authorizeHttpRequests( 49 | req -> req 50 | .requestMatchers("/**") 51 | .permitAll() 52 | .anyRequest() 53 | .authenticated() 54 | 55 | ) 56 | .userDetailsService(authenticationService) 57 | .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) 58 | .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class).build(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/StudentService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.entity.Student; 5 | import com.example.demo.exception.DuplicateEntity; 6 | import com.example.demo.exception.NotFoundException; 7 | import com.example.demo.model.StudentRequest; 8 | import com.example.demo.model.StudentResponse; 9 | import com.example.demo.repository.AccountRepository; 10 | import com.example.demo.repository.StudentRepository; 11 | import org.modelmapper.ModelMapper; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.data.domain.Page; 14 | import org.springframework.data.domain.PageRequest; 15 | import org.springframework.data.domain.Pageable; 16 | import org.springframework.stereotype.Service; 17 | 18 | import java.util.List; 19 | 20 | @Service //đánh dấu cho spring biết đây là lớp xử lý logic 21 | public class StudentService { 22 | 23 | @Autowired 24 | StudentRepository studentRepository; 25 | 26 | @Autowired 27 | ModelMapper modelMapper; 28 | 29 | @Autowired 30 | AuthenticationService authenticationService; 31 | 32 | public StudentRequest createNewStudent(StudentRequest studentRequest){ 33 | try{ 34 | Student student = modelMapper.map(studentRequest, Student.class); 35 | //thong qua duoc filter roi 36 | //luu lai 37 | Account accountRequest = authenticationService.getCurrentAccount(); 38 | student.setAccount(accountRequest); 39 | studentRepository.save(student); 40 | return studentRequest; 41 | } catch (Exception e) { 42 | throw new RuntimeException(e); 43 | } 44 | 45 | } 46 | 47 | public StudentResponse getAllStudent(int page, int size){ 48 | Page studentPage = studentRepository.findAll(PageRequest.of(page, size)); //lấy tất cả lên 49 | StudentResponse studentResponse = new StudentResponse(); 50 | studentResponse.setContent(studentPage.getContent()); 51 | studentResponse.setPageNumbers(studentPage.getNumber()); 52 | studentResponse.setTotalElements(studentPage.getNumberOfElements()); 53 | studentResponse.setTotalPages(studentPage.getTotalPages()); 54 | return studentResponse; 55 | 56 | } 57 | 58 | public Student updateStudent(Student student, long Id) { 59 | //find student có id cần update 60 | Student oldStudent = studentRepository.findStudentById(Id); 61 | 62 | if (oldStudent == null) { 63 | throw new NotFoundException("Student not found"); 64 | } 65 | try { 66 | oldStudent.setName(student.getName()); 67 | oldStudent.setStudentCode(student.getStudentCode()); 68 | oldStudent.setScore(student.getScore()); 69 | return studentRepository.save(oldStudent); 70 | } catch (Exception e) { 71 | throw new DuplicateEntity("Student Code already existed! Try again!"); 72 | 73 | } 74 | } 75 | 76 | public Student deleteStudent(long Id){ 77 | Student oldStudent = studentRepository.findStudentById(Id); 78 | if(oldStudent == null){ 79 | throw new NotFoundException("Student not found"); 80 | } 81 | oldStudent.setDeleted(true); 82 | return studentRepository.save(oldStudent); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/entity/Account.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.entity; 2 | 3 | import com.example.demo.entity.enums.Role; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import jakarta.persistence.*; 6 | import jakarta.validation.constraints.Email; 7 | import jakarta.validation.constraints.NotBlank; 8 | import jakarta.validation.constraints.Pattern; 9 | import jakarta.validation.constraints.Size; 10 | import lombok.AllArgsConstructor; 11 | import lombok.Getter; 12 | import lombok.NoArgsConstructor; 13 | import lombok.Setter; 14 | import org.springframework.security.core.GrantedAuthority; 15 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 16 | import org.springframework.security.core.userdetails.UserDetails; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.Date; 21 | import java.util.List; 22 | 23 | 24 | @Getter 25 | @Setter 26 | @AllArgsConstructor 27 | @NoArgsConstructor 28 | @Entity 29 | //implement UserDetails để Spring security hiểu mốt để dùng phân quyền 30 | public class Account implements UserDetails { 31 | @Id 32 | @GeneratedValue(strategy = GenerationType.IDENTITY) 33 | long ID; 34 | 35 | @Enumerated(EnumType.STRING) 36 | Role role; 37 | 38 | @NotBlank(message = "not blank") 39 | @Pattern(regexp = "SE\\d{6}", message = "format must be |SExxxxxx| with x is numbers") 40 | @Column(unique = true) 41 | String studentCode; 42 | 43 | @Email(message = "Email not valid") 44 | @Column(unique = true) 45 | String email; 46 | 47 | @Pattern(regexp = "(84|0[3|5|7|8|9])+([0-9]{8})", message = "Invalid phone number!") 48 | @Column(unique = true) 49 | String phone; 50 | 51 | Date createAt; 52 | 53 | @NotBlank(message = "Password can not be blank") 54 | @Size(min = 6, message = "Password must more than 6 letter") 55 | String password; 56 | 57 | @OneToMany(mappedBy = "account") 58 | @JsonIgnore 59 | List students; 60 | 61 | @OneToMany(mappedBy = "customer") 62 | List orders; 63 | 64 | @OneToMany(mappedBy = "from") 65 | List transactionsFrom; 66 | 67 | @OneToMany(mappedBy = "to") 68 | List transactionsTo; 69 | 70 | @OneToMany(mappedBy = "account") 71 | List kois; 72 | 73 | @OneToMany(mappedBy = "customer") 74 | List customer_feedbacks; 75 | 76 | @OneToMany(mappedBy = "shop") 77 | @JsonIgnore 78 | List shop_feedbacks; 79 | 80 | @Override 81 | public Collection getAuthorities() { 82 | // định nghĩa những quyền hạn mà account có thể làm được 83 | List authorities = new ArrayList<>(); 84 | if(this.role!=null) 85 | authorities.add(new SimpleGrantedAuthority(this.role.toString())); 86 | return authorities; 87 | } 88 | 89 | @Override 90 | public String getUsername() { 91 | return this.email; //dang nhap bang email, this.phone -> dang nhap bang phone 92 | } 93 | 94 | @Override 95 | public boolean isAccountNonExpired() { 96 | return true; 97 | } 98 | 99 | @Override 100 | public boolean isAccountNonLocked() { 101 | return true; 102 | } 103 | 104 | @Override 105 | public boolean isCredentialsNonExpired() { 106 | return true; 107 | } 108 | 109 | @Override 110 | public boolean isEnabled() { 111 | return true; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.3 9 | 10 | 11 | com.example 12 | demo 13 | 0.0.1-SNAPSHOT 14 | demo 15 | Demo project for Spring Boot 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 21 31 | 21 32 | 21 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | true 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-validation 54 | 3.3.3 55 | 56 | 57 | org.springdoc 58 | springdoc-openapi-starter-webmvc-ui 59 | 2.5.0 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-data-jpa 65 | 66 | 67 | 68 | 69 | com.microsoft.sqlserver 70 | mssql-jdbc 71 | runtime 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-starter-security 78 | 3.3.3 79 | 80 | 81 | 82 | org.springframework.security 83 | spring-security-crypto 84 | 85 | 86 | 87 | 88 | org.modelmapper 89 | modelmapper 90 | 3.2.1 91 | 92 | 93 | 94 | 95 | io.jsonwebtoken 96 | jjwt-api 97 | 0.12.5 98 | 99 | 100 | 101 | io.jsonwebtoken 102 | jjwt-impl 103 | 0.12.5 104 | runtime 105 | 106 | 107 | 108 | 109 | io.jsonwebtoken 110 | jjwt-jackson 111 | 0.12.5 112 | runtime 113 | 114 | 115 | 116 | 117 | org.springframework.boot 118 | spring-boot-starter-mail 119 | 3.3.3 120 | 121 | 122 | 123 | 124 | org.thymeleaf 125 | thymeleaf 126 | 127 | 128 | 129 | com.google.firebase 130 | firebase-admin 131 | 9.1.1 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | org.springframework.boot 140 | spring-boot-maven-plugin 141 | 142 | 143 | 144 | org.projectlombok 145 | lombok 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/config/Filter.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.config; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.exception.AuthenticateException; 5 | import com.example.demo.service.TokenService; 6 | import io.jsonwebtoken.ExpiredJwtException; 7 | import io.jsonwebtoken.MalformedJwtException; 8 | import jakarta.servlet.FilterChain; 9 | import jakarta.servlet.ServletException; 10 | import jakarta.servlet.http.HttpServletRequest; 11 | import jakarta.servlet.http.HttpServletResponse; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.beans.factory.annotation.Qualifier; 14 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 15 | import org.springframework.security.core.context.SecurityContext; 16 | import org.springframework.security.core.context.SecurityContextHolder; 17 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 18 | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.util.AntPathMatcher; 21 | import org.springframework.web.filter.OncePerRequestFilter; 22 | import org.springframework.web.servlet.HandlerExceptionResolver; 23 | 24 | import java.io.IOException; 25 | import java.util.List; 26 | 27 | //extend de filter 28 | @Component 29 | public class Filter extends OncePerRequestFilter { 30 | 31 | @Autowired 32 | TokenService tokenService; 33 | 34 | @Autowired 35 | @Qualifier("handlerExceptionResolver") 36 | HandlerExceptionResolver resolver;//xử lý exception trong các yêu cầu http 37 | 38 | private final List AUTH_PERMISSION = List.of( 39 | "/swagger-ui/**", 40 | "/v3/api-docs/**", 41 | "/swagger-resources/**", 42 | "/api/login", 43 | "/api/register", 44 | "/api/forgot-password", 45 | "/api/major" 46 | ); 47 | 48 | public boolean isPublicAPI(String uri){ 49 | //VD: uri: /api/register 50 | //nếu gặp các api ở trên cho truy cập luôn 51 | AntPathMatcher pathMatcher = new AntPathMatcher(); 52 | //không thì check token => false 53 | return AUTH_PERMISSION.stream().anyMatch(pattern -> pathMatcher.match(pattern, uri)); //check trong List có ít nhất 1 thì true, ngược lại false 54 | } 55 | 56 | @Override 57 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 58 | 59 | //check xem api mà người dùng yêu cầu có phải là 1 public api hay không?(ai cũng dùng được) 60 | 61 | boolean isPublicAPI = isPublicAPI(request.getRequestURI()); 62 | if(isPublicAPI){ 63 | filterChain.doFilter(request,response); 64 | } 65 | else{ 66 | String token = getToken(request); 67 | if(token == null){ 68 | //không đươc phép truy cập 69 | resolver.resolveException(request, response, null, new AuthenticateException("Empty token")); 70 | return; 71 | } 72 | 73 | // => có token 74 | //check token có đúng không, lấy thông tin account từ token 75 | Account account; 76 | try{ 77 | account = tokenService.getAccountByToken(token); 78 | }catch (ExpiredJwtException e){ 79 | //response token hết hạn 80 | resolver.resolveException(request, response, null, new AuthenticateException("Expired token")); 81 | return; 82 | } catch (MalformedJwtException e) { 83 | resolver.resolveException(request, response, null, new AuthenticateException("Invalid token")); 84 | // response token sai 85 | return; 86 | } 87 | 88 | //token chuẩn 89 | //cho phép truy cập 90 | //lưu lại thông tin account 91 | UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( 92 | account, 93 | token, 94 | account.getAuthorities() 95 | ); 96 | authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); 97 | SecurityContextHolder.getContext().setAuthentication(authenticationToken); //lưu trữ đối tượng xác thực vào SecurityContext, trong suốt quá trình của phiên làm việc, mọi yêu cầu tiếp theo sẽ được nhận diện là từ người dùng này. 98 | //cho token đó vào 99 | filterChain.doFilter(request,response); 100 | } 101 | } 102 | 103 | public String getToken(HttpServletRequest request){ 104 | String authHeader = request.getHeader("Authorization"); //token nằm trong header của Authorization 105 | if(authHeader == null){ 106 | return null; 107 | } 108 | return authHeader.substring(7); //bỏ Bearer 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/AuthenticationService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.exception.DuplicateEntity; 5 | import com.example.demo.exception.NotFoundException; 6 | import com.example.demo.model.*; 7 | import com.example.demo.model.forgotPass.ForgotPasswordRequest; 8 | import com.example.demo.model.forgotPass.ResetPasswordRequest; 9 | import com.example.demo.repository.AccountRepository; 10 | import org.modelmapper.ModelMapper; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.authentication.AuthenticationManager; 13 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 14 | import org.springframework.security.core.Authentication; 15 | import org.springframework.security.core.context.SecurityContextHolder; 16 | import org.springframework.security.core.userdetails.UserDetails; 17 | import org.springframework.security.core.userdetails.UserDetailsService; 18 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 19 | import org.springframework.security.crypto.password.PasswordEncoder; 20 | import org.springframework.stereotype.Service; 21 | 22 | 23 | import java.util.Date; 24 | import java.util.List; 25 | 26 | @Service //đánh dấu cho srping boot đây là service 27 | public class AuthenticationService implements UserDetailsService { 28 | //xử lý logic, xử lý nghiệp vụ 29 | @Autowired 30 | AccountRepository accountRepository; 31 | 32 | @Autowired 33 | PasswordEncoder passwordEncoder; 34 | 35 | @Autowired 36 | ModelMapper modelMapper; 37 | 38 | @Autowired 39 | EmailService emailService; 40 | 41 | @Autowired 42 | AuthenticationManager authenticationManager; 43 | 44 | @Autowired 45 | TokenService tokenService; 46 | 47 | public AccountResponse register(RegisterRequest registerRequest){ 48 | Account account = modelMapper.map(registerRequest, Account.class); 49 | try{ 50 | String originPass = account.getPassword(); 51 | account.setCreateAt(new Date()); 52 | account.setPassword(passwordEncoder.encode(originPass)); 53 | Account newAccount = accountRepository.save(account); 54 | //đăng ký thành công, gửi mail cho người dùng 55 | EmailDetail emailDetail = new EmailDetail(); 56 | emailDetail.setReceiver(newAccount); 57 | emailDetail.setSubject("Welcome to KOIKICHI"); 58 | emailDetail.setLink("https://cdn-i.doisongphapluat.com.vn/resize/th/upload/2024/05/29/chan-dung-tinh-dau-quoc-dan-bae-suzy-2-09540259.jpg"); 59 | emailService.sendEmail(emailDetail); 60 | 61 | return modelMapper.map(newAccount, AccountResponse.class); 62 | } catch (Exception e) { 63 | if(e.getMessage().contains(account.getEmail())) 64 | { 65 | throw new DuplicateEntity("Duplicated Email! Created Fail"); 66 | } 67 | else if(e.getMessage().contains(account.getPhone())){ 68 | throw new DuplicateEntity("Duplicated Phone! Created Fail"); 69 | } 70 | else{ 71 | throw new DuplicateEntity("Duplicated Phone! Created Fail"); 72 | } 73 | 74 | 75 | } 76 | // tương tự context.add C# 77 | } 78 | 79 | public AccountResponse login(LoginRequest loginRequest){ 80 | try { 81 | 82 | Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken( 83 | loginRequest.getEmail(), 84 | loginRequest.getPassword())); //kh có thì catch exception 85 | Account account = (Account) authentication.getPrincipal(); //lấy thông tin ng dùng và cast về account 86 | AccountResponse accountResponse = modelMapper.map(account, AccountResponse.class); 87 | accountResponse.setToken(tokenService.generateToken(account)); 88 | return accountResponse; 89 | }catch (Exception e){ 90 | //error => throw new exception 91 | throw new NotFoundException("Email or Password is invalid!!"); 92 | } 93 | 94 | } 95 | 96 | public List getAllAccounts(){ 97 | List list = accountRepository.findAll(); // findAll() lấy tất cả account trong DB 98 | return list; 99 | } 100 | 101 | 102 | @Override 103 | public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { 104 | return accountRepository.findByEmail(email); 105 | } 106 | 107 | //lấy thông tin account dc lưu từ token trong SecurityContextHolder 108 | public Account getCurrentAccount(){ 109 | Account account = (Account) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 110 | return accountRepository.findAccountByID(account.getID()); 111 | } 112 | 113 | public void forgotPassword(ForgotPasswordRequest forgotPassword){ 114 | Account account = accountRepository.findByEmail(forgotPassword.getEmail()); 115 | if(account == null){ 116 | throw new NotFoundException("Account not found"); 117 | } 118 | else{ 119 | EmailDetail emailDetail = new EmailDetail(); 120 | emailDetail.setReceiver(account); 121 | emailDetail.setSubject("Reset Your Password"); 122 | emailDetail.setLink("https://www.google.com/?token=" + tokenService.generateToken(account)); 123 | emailService.sendEmail(emailDetail); 124 | } 125 | } 126 | 127 | public void resetPassword(ResetPasswordRequest request){ 128 | Account account = getCurrentAccount(); 129 | account.setPassword(passwordEncoder.encode(request.getPassword())); 130 | accountRepository.save(account); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/example/demo/service/OrdersService.java: -------------------------------------------------------------------------------- 1 | package com.example.demo.service; 2 | 3 | import com.example.demo.entity.Account; 4 | import com.example.demo.entity.Koi; 5 | import com.example.demo.entity.OrderDetail; 6 | import com.example.demo.entity.Orders; 7 | import com.example.demo.model.OrdersDetailRequest; 8 | import com.example.demo.model.OrdersRequest; 9 | import com.example.demo.repository.KoiRepository; 10 | import com.example.demo.repository.OrderRepository; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.authentication.AuthenticationManager; 13 | import org.springframework.stereotype.Service; 14 | 15 | import javax.crypto.Mac; 16 | import javax.crypto.spec.SecretKeySpec; 17 | import java.io.UnsupportedEncodingException; 18 | import java.net.URLEncoder; 19 | import java.nio.charset.StandardCharsets; 20 | import java.time.LocalDate; 21 | import java.time.LocalDateTime; 22 | import java.time.format.DateTimeFormatter; 23 | import java.util.*; 24 | 25 | @Service 26 | public class OrdersService { 27 | @Autowired 28 | AuthenticationService authenticationService; 29 | 30 | @Autowired 31 | OrderRepository ordersREpository; 32 | 33 | AuthenticationManager authenticationManager; 34 | 35 | @Autowired 36 | KoiRepository koiRepository; 37 | 38 | public Orders create(OrdersRequest ordersRequest) { 39 | Orders orders = new Orders(); 40 | Account customer = authenticationService.getCurrentAccount(); 41 | orders.setDate(new Date(System.currentTimeMillis())); 42 | orders.setCustomer(customer); 43 | List ordersDetail = new ArrayList<>(); 44 | float total = 0; 45 | for (OrdersDetailRequest i : ordersRequest.getDetails()) { 46 | Koi koi = koiRepository.findKoiById(i.getKoiId()); 47 | OrderDetail orderDetail = new OrderDetail(); 48 | orderDetail.setQuantity(i.getQuantity()); 49 | orderDetail.setPrice(koi.getPrice()); 50 | orderDetail.setKoi(koi); 51 | orderDetail.setOrder(orders); 52 | total += orderDetail.getPrice() * orderDetail.getQuantity(); 53 | ordersDetail.add(orderDetail); 54 | } 55 | orders.setOrderDetails(ordersDetail); 56 | orders.setTotal(total); 57 | return ordersREpository.save(orders); 58 | } 59 | 60 | public List getOrdersByCustomer() { 61 | Account customer = authenticationService.getCurrentAccount(); 62 | return ordersREpository.findOrdersByCustomer(customer); 63 | } 64 | 65 | public String createURL(OrdersRequest ordersRequest) throws Exception { 66 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); 67 | LocalDateTime createdDate = LocalDateTime.now(); 68 | String formattedDateTime = createdDate.format(formatter); 69 | 70 | //code thanh toan 71 | Orders order = create(ordersRequest); 72 | float money = order.getTotal() * 100; // Vnp requires the amount * 100 and no decimal 73 | String amount = String.valueOf((int) money); 74 | 75 | String tmnCode = "FCQGXYEF"; 76 | String secretKey = "5DHWJUAO6ELG2KFHDGET7OCSEK9NF33R"; 77 | String vnpUrl = "https://sandbox.vnpayment.vn/paymentv2/vpcpay.html"; 78 | String returnUrl = "https://www.google.com/?orderId=" + order.getId(); 79 | String currCode = "VND"; 80 | 81 | Map vnp_Params = new TreeMap<>(); 82 | vnp_Params.put("vnp_Version", "2.1.0"); 83 | vnp_Params.put("vnp_Command", "pay"); 84 | vnp_Params.put("vnp_TmnCode", tmnCode); 85 | vnp_Params.put("vnp_Locale", "vn"); 86 | vnp_Params.put("vnp_CurrCode", currCode); 87 | vnp_Params.put("vnp_TxnRef", order.getId().toString()); 88 | vnp_Params.put("vnp_OrderInfo", "Thanh toan cho ma giao dich: " + order.getId()); 89 | vnp_Params.put("vnp_OrderType", "other"); 90 | vnp_Params.put("vnp_Amount", amount); 91 | vnp_Params.put("vnp_ReturnUrl", returnUrl); 92 | vnp_Params.put("vnp_CreateDate", formattedDateTime); 93 | vnp_Params.put("vnp_IpAddr", "192.168.101.19");// thanh toan thanh cong 94 | 95 | StringBuilder signDataBuilder = new StringBuilder(); 96 | for (Map.Entry entry : vnp_Params.entrySet()) { 97 | signDataBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.toString())); 98 | signDataBuilder.append("="); 99 | signDataBuilder.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString())); 100 | signDataBuilder.append("&"); 101 | } 102 | signDataBuilder.deleteCharAt(signDataBuilder.length() - 1); //remove last "$" 103 | String signData = signDataBuilder.toString(); 104 | 105 | String singed = generateHMAC(secretKey, signData); 106 | 107 | vnp_Params.put("vnp_SecureHash", singed); 108 | 109 | StringBuilder urlBuilder = new StringBuilder(vnpUrl); 110 | urlBuilder.append("?"); 111 | for (Map.Entry entry : vnp_Params.entrySet()) { 112 | urlBuilder.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.toString())); 113 | urlBuilder.append("="); 114 | urlBuilder.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString())); 115 | urlBuilder.append("&"); 116 | } 117 | urlBuilder.deleteCharAt(urlBuilder.length() - 1); //remove last "$" 118 | 119 | return urlBuilder.toString(); 120 | } 121 | 122 | private String generateHMAC(String secretKey, String data) throws Exception { 123 | Mac hmacSha512 = Mac.getInstance("HmacSHA512"); 124 | SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA512"); 125 | hmacSha512.init(keySpec); 126 | byte[] hmacBytes = hmacSha512.doFinal(data.getBytes(StandardCharsets.UTF_8)); 127 | 128 | StringBuilder result = new StringBuilder(); 129 | for (byte b : hmacBytes) { 130 | result.append(String.format("%02x", b)); 131 | } 132 | return result.toString(); 133 | } 134 | } 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM http://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | if ($env:MAVEN_USER_HOME) { 83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" 84 | } 85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 87 | 88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 91 | exit $? 92 | } 93 | 94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 96 | } 97 | 98 | # prepare tmp dir 99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 102 | trap { 103 | if ($TMP_DOWNLOAD_DIR.Exists) { 104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 106 | } 107 | } 108 | 109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 110 | 111 | # Download and Install Apache Maven 112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 113 | Write-Verbose "Downloading from: $distributionUrl" 114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 115 | 116 | $webclient = New-Object System.Net.WebClient 117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 119 | } 120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 122 | 123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 125 | if ($distributionSha256Sum) { 126 | if ($USE_MVND) { 127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 128 | } 129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 132 | } 133 | } 134 | 135 | # unzip and move 136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 138 | try { 139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 140 | } catch { 141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 142 | Write-Error "fail to move MAVEN_HOME" 143 | } 144 | } finally { 145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 147 | } 148 | 149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 150 | -------------------------------------------------------------------------------- /src/main/resources/templates/welcome-template.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 66 | 67 | 68 | 69 |
9 |
10 | 12 | 13 | 14 | 18 | 19 | 20 | 51 | 52 | 53 |
16 | [[${subject}]] 17 |
21 | 22 | 23 | 24 | 27 | 28 | 29 | 32 | 33 | 34 | 37 | 38 | 39 | 42 | 43 | 44 | 47 | 48 | 49 |
25 | Hi [[${name}]] 26 |
30 | Welcome to Koikichi. 31 |
35 | Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quae, alias ab? Sed ad debitis placeat iusto officia commodi distinctio velit. 36 |
40 | [[${button}]] 41 |
45 | Thanks for choosing Koikichi Admin. 46 |
50 |
54 | 64 |
65 |
70 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Apache Maven Wrapper startup batch script, version 3.3.2 23 | # 24 | # Optional ENV vars 25 | # ----------------- 26 | # JAVA_HOME - location of a JDK home dir, required when download maven via java source 27 | # MVNW_REPOURL - repo url base for downloading maven distribution 28 | # MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 29 | # MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output 30 | # ---------------------------------------------------------------------------- 31 | 32 | set -euf 33 | [ "${MVNW_VERBOSE-}" != debug ] || set -x 34 | 35 | # OS specific support. 36 | native_path() { printf %s\\n "$1"; } 37 | case "$(uname)" in 38 | CYGWIN* | MINGW*) 39 | [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" 40 | native_path() { cygpath --path --windows "$1"; } 41 | ;; 42 | esac 43 | 44 | # set JAVACMD and JAVACCMD 45 | set_java_home() { 46 | # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched 47 | if [ -n "${JAVA_HOME-}" ]; then 48 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 49 | # IBM's JDK on AIX uses strange locations for the executables 50 | JAVACMD="$JAVA_HOME/jre/sh/java" 51 | JAVACCMD="$JAVA_HOME/jre/sh/javac" 52 | else 53 | JAVACMD="$JAVA_HOME/bin/java" 54 | JAVACCMD="$JAVA_HOME/bin/javac" 55 | 56 | if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then 57 | echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 58 | echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 59 | return 1 60 | fi 61 | fi 62 | else 63 | JAVACMD="$( 64 | 'set' +e 65 | 'unset' -f command 2>/dev/null 66 | 'command' -v java 67 | )" || : 68 | JAVACCMD="$( 69 | 'set' +e 70 | 'unset' -f command 2>/dev/null 71 | 'command' -v javac 72 | )" || : 73 | 74 | if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then 75 | echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 76 | return 1 77 | fi 78 | fi 79 | } 80 | 81 | # hash string like Java String::hashCode 82 | hash_string() { 83 | str="${1:-}" h=0 84 | while [ -n "$str" ]; do 85 | char="${str%"${str#?}"}" 86 | h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) 87 | str="${str#?}" 88 | done 89 | printf %x\\n $h 90 | } 91 | 92 | verbose() { :; } 93 | [ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } 94 | 95 | die() { 96 | printf %s\\n "$1" >&2 97 | exit 1 98 | } 99 | 100 | trim() { 101 | # MWRAPPER-139: 102 | # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. 103 | # Needed for removing poorly interpreted newline sequences when running in more 104 | # exotic environments such as mingw bash on Windows. 105 | printf "%s" "${1}" | tr -d '[:space:]' 106 | } 107 | 108 | # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties 109 | while IFS="=" read -r key value; do 110 | case "${key-}" in 111 | distributionUrl) distributionUrl=$(trim "${value-}") ;; 112 | distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; 113 | esac 114 | done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" 115 | [ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" 116 | 117 | case "${distributionUrl##*/}" in 118 | maven-mvnd-*bin.*) 119 | MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ 120 | case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in 121 | *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; 122 | :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; 123 | :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; 124 | :Linux*x86_64*) distributionPlatform=linux-amd64 ;; 125 | *) 126 | echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 127 | distributionPlatform=linux-amd64 128 | ;; 129 | esac 130 | distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" 131 | ;; 132 | maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; 133 | *) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; 134 | esac 135 | 136 | # apply MVNW_REPOURL and calculate MAVEN_HOME 137 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 138 | [ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" 139 | distributionUrlName="${distributionUrl##*/}" 140 | distributionUrlNameMain="${distributionUrlName%.*}" 141 | distributionUrlNameMain="${distributionUrlNameMain%-bin}" 142 | MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" 143 | MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" 144 | 145 | exec_maven() { 146 | unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : 147 | exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" 148 | } 149 | 150 | if [ -d "$MAVEN_HOME" ]; then 151 | verbose "found existing MAVEN_HOME at $MAVEN_HOME" 152 | exec_maven "$@" 153 | fi 154 | 155 | case "${distributionUrl-}" in 156 | *?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; 157 | *) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; 158 | esac 159 | 160 | # prepare tmp dir 161 | if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then 162 | clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } 163 | trap clean HUP INT TERM EXIT 164 | else 165 | die "cannot create temp dir" 166 | fi 167 | 168 | mkdir -p -- "${MAVEN_HOME%/*}" 169 | 170 | # Download and Install Apache Maven 171 | verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 172 | verbose "Downloading from: $distributionUrl" 173 | verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 174 | 175 | # select .zip or .tar.gz 176 | if ! command -v unzip >/dev/null; then 177 | distributionUrl="${distributionUrl%.zip}.tar.gz" 178 | distributionUrlName="${distributionUrl##*/}" 179 | fi 180 | 181 | # verbose opt 182 | __MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' 183 | [ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v 184 | 185 | # normalize http auth 186 | case "${MVNW_PASSWORD:+has-password}" in 187 | '') MVNW_USERNAME='' MVNW_PASSWORD='' ;; 188 | has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; 189 | esac 190 | 191 | if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then 192 | verbose "Found wget ... using wget" 193 | wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" 194 | elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then 195 | verbose "Found curl ... using curl" 196 | curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" 197 | elif set_java_home; then 198 | verbose "Falling back to use Java to download" 199 | javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" 200 | targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" 201 | cat >"$javaSource" <<-END 202 | public class Downloader extends java.net.Authenticator 203 | { 204 | protected java.net.PasswordAuthentication getPasswordAuthentication() 205 | { 206 | return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); 207 | } 208 | public static void main( String[] args ) throws Exception 209 | { 210 | setDefault( new Downloader() ); 211 | java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); 212 | } 213 | } 214 | END 215 | # For Cygwin/MinGW, switch paths to Windows format before running javac and java 216 | verbose " - Compiling Downloader.java ..." 217 | "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" 218 | verbose " - Running Downloader.java ..." 219 | "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" 220 | fi 221 | 222 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 223 | if [ -n "${distributionSha256Sum-}" ]; then 224 | distributionSha256Result=false 225 | if [ "$MVN_CMD" = mvnd.sh ]; then 226 | echo "Checksum validation is not supported for maven-mvnd." >&2 227 | echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 228 | exit 1 229 | elif command -v sha256sum >/dev/null; then 230 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then 231 | distributionSha256Result=true 232 | fi 233 | elif command -v shasum >/dev/null; then 234 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then 235 | distributionSha256Result=true 236 | fi 237 | else 238 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 239 | echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 240 | exit 1 241 | fi 242 | if [ $distributionSha256Result = false ]; then 243 | echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 244 | echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 245 | exit 1 246 | fi 247 | fi 248 | 249 | # unzip and move 250 | if command -v unzip >/dev/null; then 251 | unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" 252 | else 253 | tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" 254 | fi 255 | printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" 256 | mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" 257 | 258 | clean || : 259 | exec_maven "$@" 260 | --------------------------------------------------------------------------------