Báo cáo thực tập cơ sở PTIT A+

36 49 1
Báo cáo thực tập cơ sở PTIT A+

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Báo cáo môn thực tập cơ sở cô Ngọc PTIT đã được A+. Báo cáo ứng dụng to do list gồm 2 phần app và be ........................................................................................................................................................................................................................................................................................

HỌC VIỆN CƠNG NGHỆ BƯU CHÍNH VIỄN THƠNG KHOA CƠNG NGHỆ THÔNG TIN **************** BÁO CÁO MÔN HỌC THỰC TẬP CƠ SỞ Đề tài:  Ứng dụng ToDo-List Giảng viên: Đỗ Thị Bích Ngọc Sinh viên: Mã sinh viên: SĐT: Hà Nội – 2023 Mục lục I Giới thiệu toán II Bản kế tuần III Tìm hiểu cơng nghệ .4 Tìm hiểu flutter framework Tìm hiểu spring boot IV V Kết làm 11 Những việc chưa làm .11 VI Đặc tả 12 Mô tả chức 13 VII Class diagram 23 VIII IX X Thiết kế sở liệu 24 Kiến trúc code 24 Kiến trúc code backend 24 Triển khai 26 Backend 27 I Giới thiệu toán − Ứng dụng quản lý công việc To-Do List thiết kế để hỗ trợ người dùng việc quản lý theo dõi dự án, nhiệm vụ ghi − Ứng dụng sử dụng phương pháp luận Pomodoro, phương pháp quản lý thời gian phổ biến, nhằm giúp người dùng tập trung nâng cao suất làm việc − Tính ứng dụng cho phép người dùng thêm, sửa đổi xóa dự án, nhiệm vụ ghi − Mỗi dự án chứa nhiều nhiệm vụ nhiều ghi − Ngoài ra, nhiệm vụ trang bị với số lượng Pomodoro, đơn vị thời gian sử dụng để đánh giá thời gian cần thiết để hồn thành nhiệm vụ − Khi người dùng bắt đầu nhiệm vụ, họ chọn phương pháp luận Pomodoro để theo dõi thời gian Mỗi nhiệm vụ chọn tối đa Pomodoro để cơng việc đạt hiệu cao nhất, cần nhiều thời gian nên chia nhỏ thành nhiều nhiệm vụ ngắn − Trong ứng dụng, hiển thị thời gian sử dụng cho Pomodoro thời gian lại cho nhiệm vụ − Ngồi ra, người dùng tạm dừng tiếp tục nhiệm vụ lúc nào, ứng dụng tự động cập nhật thời gian sử dụng − Ứng dụng cung cấp chức nhắc nhở giúp người dùng khơng bỏ sót nhiệm vụ danh sách To-Do List − Người dùng thiết lập thơng báo nhắc nhở cho nhiệm vụ danh sách To-Do List để đảm bảo họ khơng qn hồn thành nhiệm vụ − Ngoài ra, ứng dụng cung cấp cho người dùng khả tùy chỉnh điều chỉnh thông tin dự án, nhiệm vụ ghi cách dễ dàng − Tính giúp người dùng linh hoạt việc quản lý xếp cơng việc − Tính đặc biệt ứng dụng khả tính tốn số lượng Pomodoro cần thiết để hoàn thành nhiệm vụ − Điều giúp người dùng lên kế hoạch quản lý thời gian cách hiệu hơn, từ nâng cao hiệu suất làm việc − Trong tổng quan, ứng dụng quản lý công việc To-Do List với phương pháp luận Pomodoro cơng cụ hữu ích cho người dùng quản lý theo dõi dự án, nhiệm vụ ghi − Sự kết hợp phương pháp luận Pomodoro tính nhắc nhở giúp người dùng tập trung nâng cao suất làm việc, từ nâng cao hiệu làm việc người dùng II Tuần Bản kế tuần Kế hoạch Update 06/03/2022 sửa kế hoạch tuần thêm kế hoạch làm lại tuần 3, lý làm chưa đủ, làm sai Update 14/03 thay đổi kế hoạch tuần 10 xác định nhầm kế Update 19/03 thay đổi hoạch khơng thể dùng kế hoạch ước tính firebase trước viết thời gian không đủ api làm trước cơng làm lại Tìm hiểu Figma để thiết kế giao diện Tuần Xác định thực thể Quan hệ vẽ ERD Xác định bảng Tuần Thiết kế giao diện thêm làm lại tuần Chuyển phần thêm sửa xóa project thêm sửa xóa note thêm sửa xóa task project sang tuần làm với dựng data base postgresql Code giao diện fake data Tuần Đăng kí đăng nhập, thêm sửa xoá project, thêm sửa xoá note, Tuần Tuần Tuần Tuần thêm sửa xoá task project - Xử lý thông báo sử dụng firebase cloud messaging Tìm hiểu dựng db postgresql Tìm hiểu spring, restful api Tìm hiểu authen spring phân quyền Tìm hiểu dựng db postgresql Tìm hiểu spring, restful api Tìm hiểu authen spring phân quyền Viết API cho app - Xử lý thông báo sử dụng firebase cloud messaging Tuần Viết API cho app 10 Tuần 11 Tuần 12 Thêm code giao diện Ghép API vào app Viết báo cáo III Tìm hiểu cơng nghệ Tìm hiểu flutter framework − Flutter framework dựa ngôn ngữ lập trình dart, hỗ trợ lập trình mobile app nhiều tảng (cross-platform) code base − Dựng view Flutter o Tất thành phần view ứng dụng flutter gọi widget o Để tạo hình ta sử dụng widget Scaffold chứa thành phần như: ▪ AppBar ▪ Body ▪ FloatingActionButton ▪ … o Ngồi cịn có widget khác chia thành phần widget để định nghĩa bố cục widget để hiển thị nội dung o Widget định nghĩa bố cục như: ▪ Column: đặt thành phần view Column theo chiều dọc ▪ Row: đặt thành phần view Row theo chiều ngang ▪ Stack: cho phép thành phần view nằm đè lên o Widget để hiển thị nội dung như: ▪ Text: hiển thị nội dung chữ ▪ Button: cho phép hành động click ▪ … − − − − Scaffold widget Container widget Row column Text widget Tìm hiểu spring boot − − − − − − − − − − − Spring boot framework java framework Là framework mạnh mẽ phổ biến, giúp rút ngắn thời gian phát triển, giảm rườm rà tăng tính ổn định Các annotation Spring Boot @Component o Đánh dấu bên Class để Spring biết Bean o ( SB chạy dị tìm tồn Class cấp/ Packet thấp so với Class mà bạn cung cấp cho Spring Trong q trình dị tìm này, gặp Class đánh dấu trên, tạo Instance đưa vào ApplicationContext để quản lí Bean quản lí dạng Singleton ) @ComponentScan("file1") @ComponentScan( {"file1", "file2"} ) o  SpringBoot chạy dị tìm tồn Class cấp/ bên Package thấp tạo Bean từ Class tìm thấy @SpringBootApplication(scanBasePackages = "file1") @SpringBootApplication(scanBasePackages = {"file1", "file2"} ) o  Ngoài ta Config trực tiếp bên @SpringBootApplication Annotation  @DeleteMapping("{id}") o Response delete(@PathVariable("id") Long id){ @GetMapping(“/api/v1/user/{id}”) o Response getById(@PathVariable String id) { o Ví dụ sử dụng @PathVariable phần URI, đại diện giá trị {id} o Response get(@PathVariable(required = false) String id) { o required = false: tức không bắt buộc phải có id, theo path định nghĩa @RequestBody CalculateExtraPointInputDto inputDto o @RequestBody + @ResponseBody:Dùng để ánh xạ liệu truyền từ Client-Server ngược lại o @RequestBody Method Param buộc phải ( bind ) Body HTTP request o Annotation giúp chuyển đổi Body HTTP request thành Domain Object ( đối tượng miền POJO )  o Kiểu liệu phải trùng khớp với Domain Class o ResponseBody dùng để báo với Controller Java Object trả cho Client tự động ánh xạ sang JSON chuyển vào HttpResponse o Ta đặt @ResponseBody method trả − @Autowired o Đánh dấu cho Spring biết tự động Inject Bean tương ứng vào vị trí đánh dấu o Sau tìm Class Annotation tương đương @Component, trình Inject Bean xảy sau: ● Nếu Class KHƠNG có: Constructor + Setter, sử dụng Java Reflection để đưa đối tượng vào thuộc tính có đánh dấu @Autowired ● Nếu có hàm ConstructorL: Inject Bean vào tham số hàm ● Nếu có hàm Setter:sẽ Inject Bean vào tham số hàm  o Tất Bean quản lí ApplicationContext tạo lần có Class yêu cầu @Autowired lấy đối tượng có sẵn ApplicationContext để Inject vào − @Controller − @Service − @Repository o Annotation để giúp đánh dấu tầng với o Bản chất @Service = @Repository = @Component, nên thay đổi cho mà nên đặt theo tên tầng để dễ dàng sửa chữa, code tường minh − @RestController o Là kết hợp @Controller + @ResponseBody ( tức ta không cần thêm @ResponseBody lên method ) − @Configuration o Đánh dấu Class, cho phép SB biết nơi định nghĩa Bean.  o Cũng @Component, khác ý nghĩa sử dụng o Ngồi tìm Class đánh dấu @Component mà SB cịn tìm Class đánh dấu @Configuration tạo đối tượng -> tìm method đánh dấu @Bean đối tượng vừa tạo ra, thực gọi method có đánh dấu để lấy Bean đưa vào Context − @Bean o Đánh dấu Method, cho phép SB biết Bean đưa vào Context.  o Nó nằm Class có đánh dấu @Configuration o Ngồi Method đánh dấu chứa tham số truyền vào, SB tự động Inject Bean có Context vào làm tham số − Controller layer o Controller layer đại diện cho việc xử lí Incoming HTTP Request + Response @Annotation giúp ta mark class phục vụ mục đích sử dụng Controller Layer o − Phần khoanh phần xử lý controller o B1: Request nhận   DispatcherServlet o DispatcherServlet chịu trách nghiệm xử lí Request tới + map Request tới Controller method   − @RequestBody o @Annotation giúp map HTTP Request Body -> Java object cách tự động o Object mà kèm với @Annotation nhận giá trị sau mapping từ Body -> Java object o ( Tuy nhiên phải đảm bảo Type object gán với @Annotation phải corresponse với JSON send với HTTP Request ) − @ResponseBody o @Annotation nói với Controller object trả tự động cách map Java object -> JSON/ HttpResponse object − @RestController o @Annotation kết hợp Annotation @Controller  và   o @RequestMapping o @Annotation class-level + method-level @Annotation giúp xử lí Request tới + map Request tới Controller method để xử lí o Nó chứa Path + Header + HTTP Method − − − − − − − o Sử dụng @Annotation kết hợp với @Annotation khác là: @RequestParam o Chúng ta code hết vào Controller layer dựng lên web server Nhưng để giảm độ phức tạp dễ dàng bảo trì nâng cấp thơng thường chia thành  layer Controller layer (đã nói trên) Service layer Repository layer Service layer o Là nơi xử lý business logic xử lý data từ vào từ o Ngoài từ client gửi lên o Trong từ database o Service nhận Input Dto từ controller thông qua param method map sang Entity sau thực xử lý logic thơng qua entity lưu sửa xóa lấy từ database o Sau trả Output Dto cho controller để trả response cho client o Class Mapper giúp convert Dto sang entity ngược lại Repository layer o Là nơi giao tiếp với database o Nhận yêu cầu từ service layer lấy liệu sau trả lại cho service layer để xử lý ORM  o ORM ( Object relational Mapping ) trình mapping liệu từ Java object CSDL ngược lại o ORM giúp ánh xạ Tables, Columns, DataType, Table Relation, DB thành Class attributes Java  o ORM giúp cho dev tương tác với DB thông qua object mapping mà không cần biết tới kiểu DB, type DB -> giúp làm việc với nhiều kiểu DB, dễ dàng thay đổi DB hơn, câu lệnh SQL không phụ thuộc vào loại DB Hibernate o Trước Hibernate đời ta thao tác với CSDL thơng qua JDBC theo thời gian JDBC bộc lộ nhiều điểm yếu ( boilder code, đổi CSDL viết lại code, giao tiếp Table khó, khơng có tính OOP, ) o Hibernate framework, thư viện ORM ( Object Relational Mapping ) giúp Devs viết application map object tới CSDL + hỗ trợ OOP với CSDL o Có thể hiểu Hibernate layer trung gian Application Database, giao tiếp với Hibernate thay với DB o Như ta thấy hình luồng ứng dụng o Bát đầu client gửi request lên server o Khi request vào dispathcher đưa xuống controller để xử lý request o Từ controller xuông service để thực xử lý logic o Service gọi xuống Persistence hiểu Repository layer để thực thao tác xuống database trả kết o Và để giao tiếp với Hibernate, tạo Class đại diện cho Table, liệu Database Hibernate bind vào Class cho − @Entity o @Annotation class-level annotation, thường đặt POJO để đại diện cho liệu persistence DB o Entity đại diện cho Table lưu trữ DB + instance Entity đại diện cho row Table o Ngoài để sử dụng @Annotation ta phải POJO phải có No-arg Constructor Primary key − @Table o @Annotation cho phép định Table sử dụng để mapping tới Entity − @Id o @Annotation attribute-level annotation đặt attribute đại diện cho Primary key Table − @GeneratedValue o Đây @Annotation kèm với   cung cấp “auto generation strategies” cho giá trị Primary Key o Persistence Layer o Persistence Layer bao gồm thành phần o Entity Classes: define data model Application, sử dụng @Annotation JPA để mapping Java object DB Table o Data Access Object (DAO): đại diện cho việc store + retrive data với DB, sử dụng JPA cung cấp set Interface + @Annotation để làm công việc o Database config: việc config application.properties   bao gồm URL DB, username, password, driver Restful API − API ( Application Programming Interface ) Ứng dụng kiểm tra liệu người dùng nhập vào lưu lại UC ID TD014 Tên chức Chỉnh sửa note Tác nhân User Điều kiện trước Người dùng phân quyền đăng nhập vào ứng dụng thành công Luồng chức Người dùng đăng nhập vào ứng dụng Người dùng tìm note cần chỉnh sửa Người dùng ấn vào note muốn sửa Ứng dụng chuyển đến thông tin chi tiết note Người dùng chọn nút show more góc phải hình Người dùng chọn edit Ứng dụng chuyển đến hình chỉnh sửa thơng tin note Người dùng chỉnh sửa thông tin note Người dùng ấn nút lưu 10 Ứng dụng kiểm tra liệu người dùng nhập vào lưu lại UC ID TD015 Tên chức Xóa note Tác nhân User Điều kiện Người dùng phân quyền đăng nhập vào ứng dụng trước thành công 21 Luồng chức Người dùng đăng nhập vào ứng dụng Người dùng tìm đến note cần xóa Người dùng ấn vào note muốn xóa Ứng dụng chuyển đến thông tin chi tiết note Người dùng chọn nút show more góc phải hình Người dùng chọn delete Ứng dụng xóa note khỏi sở liệu 22 VII Class diagram 23 VIII Thiết kế sở liệu 24 IX Kiến trúc code Kiến trúc code backend − Sử dụng kiến trúc layer ứng dụng spring boot o Presentation layer: Là lớp giao diện với client, controller nhận request từ client sau trả response cho client o Business layer: Là lớp xử lý logic nghiệp vụ ứng dụng Ở service nhận yêu cầu từ presentation layer controller sau xử lý, giao tiếp với data access layer (repository) cần, sau trả kết cho presentation layer o Data access layer: Là lớp giao tiếp với sở liệu nguồn liệu khác cloud Nhận yêu cầu từ business layer sau truy vấn trả liệu cho business layer o Mỗi lớp nên giao tiếp với lớp ví dụ: Presentation layer nên giao tiếp với business layer mà không nên giao tiếp trực tiếp đến data access layer o Tuân thủ theo kiến trúc giúp tách biệt phần ứng dụng, làm cho dễ bảo trì, giảm phụ thuộc tăng khả mở rộng o Cây thư mục ứng dụng spring boot theo kiến trúc layer com.example.myapp ├── controller // Presentation Layer ├── service // Business Layer └── repository // Data Access Layer − Sử dụng kiến trúc clean architecture ứng dụng flutter o Kiến trúc clean architecture Uncle Bob phát minh với mục tiêu tạo hệ thống dễ bảo trì, tái sử dụng kiểm thử o Clean architecture tập trung vào việc tách biệt rõ ràng thành phần hệ thống giúp giảm phụ thuộc tăng tính linh hoạt 25 o Clean architecture chia thành nhiều layer với nhiệm vụ cụ thể, em chia thành layer tạm gọi presentation, domain, data o Presentation layer: thành phần view triển khai giao tiếp với liệu thông qua domain layer o Domain layer: nơi xử lý logic nghiệp vụ ứng dụng không bị phụ thuộc vào framework Domain layer định nghĩa phương thức abstract để truy vấn đến liệu, sau xử lý logic thực thơng qua phương thức sau trả cho tầng presentation o Data layer: nơi triển khai phương thức truy vấn đến liệu định nghĩa tầng domain Việc giúp ứng dụng dễ dàng kiểm thử bảo trì Ví dụ ngày nguồn liệu bị thay đổi, sửa tầng domain hay presentation mà cần sửa data cách triển khai lại phương thức định nghĩa tầng domain o Tương tự tầng data, có thay đổi tầng presentation cần sửa presentation mà khơng cần thay đổi hai tầng cịn lại o Cấu trúc thư mục kiến trúc clean architecture lib ├── main.dart ├── app │ ├── pages // Các trang UI widget │ │ │── view_model // model sử dụng để hiển thị lên UI │ └── routes // Quản lý điều hướng trang domain ├── entities // Các đối tượng cốt lõi ứng dụng ├── repositories // Các lớp định nghĩa phương thức thao tác với liệu └── usecases // Các trường hợp sử dụng chứa logic nghiệp vụ data 26 ├── repositories // Triển khai phương thức lưu trữ liệu ├── data_sources // Các nguồn liệu API, sở liệu cục └── dto // Mơ hình liệu sử dụng ứng dụng X Triển khai Backend - Xử lý project @Override public Pagination getAllByUserId(Long userId, Pageable pageable, SearchProjectInputDto searchProject) { Pagination pageOutputDto = new Pagination(); Page projectEntities = projectRepository.searchInUser(userId, searchProject != null ? searchProject.getKeyword() != null ? searchProject.getKeyword() : "" : "", searchProject != null ? searchProject.getStatus() : null, pageable); pageOutputDto.setItems(projectEntities.stream().map(this::getProjectOutputDt oFromProjectEntity).collect(Collectors.toList())); pageOutputDto.setTotals(projectEntities.getTotalElements()); return pageOutputDto; } @Override public ProjectOutputDto getProjectById(Long projectId, Long userId) { if (!isProjectExist(projectId, userId)) { throw Errors.PROJECT_NOT_FOUND; } ProjectEntity entity = projectRepository.findById(projectId).get(); return getProjectOutputDtoFromProjectEntity(entity); } @Override public ProjectOutputDto createProject(ProjectInputDto projectInputDto, Long userId) { ProjectEntity projectEntity = projectMapper.getProjectEntityFromProjectInputDto(projectInputDto); projectEntity.setUserId(userId); if (projectEntity.getDeadline().isBefore(OffsetDateTime.now())) { throw Errors.PROJECT_DEADLINE_IS_BEFORE_NOW; } return getProjectOutputDtoFromProjectEntity(projectRepository.save(projectEntity)); } @Override public ProjectOutputDto updateProject(ProjectInputDto projectInputDto, Long projectId, Long userId) { if (!isProjectExist(projectId, userId)) { throw Errors.PROJECT_NOT_FOUND; 27 } ProjectEntity projectEntity = projectMapper.getProjectEntityFromProjectInputDto(projectInputDto); if (projectEntity.getDeadline().isBefore(OffsetDateTime.now())) { throw Errors.PROJECT_DEADLINE_IS_BEFORE_NOW; } projectEntity.setUserId(userId); projectEntity.setId(projectId); return getProjectOutputDtoFromProjectEntity(projectRepository.save(projectEntity)); } @Override public void deleteProject(Long projectId, Long userId) { if (!isProjectExist(projectId, userId)) { throw Errors.PROJECT_NOT_FOUND; } taskRepository.deleteByProjectId(projectId); noteRepository.deleteByProjectId(projectId); projectRepository.deleteById(projectId); } @Override public ProjectOutputDto getProjectOutputDtoFromProjectEntity(ProjectEntity projectEntity) { ProjectOutputDto projectOutputDto = projectMapper.getProjectOutputDtoFromProjectEntity(projectEntity); projectOutputDto.setCountAllTask(taskRepository.countAllByProjectId(projectE ntity.getId())); projectOutputDto.setCountDoneTask(taskRepository.countAllByProjectIdAndStatu s(projectEntity.getId(), Status.DONE)); projectOutputDto.setProgress((double) (projectOutputDto.getCountAllTask() == ? : (projectOutputDto.getCountDoneTask() * 100) / projectOutputDto.getCountAllTask())); return projectOutputDto; } @Override public boolean isProjectExist(Long projectId, Long userId) { return projectRepository.existsByIdAndUserId(projectId, userId); } - Xử lý task @Override public TaskDetailOutputDto getTaskDetail(Long taskId, Long userId) { if (!isTaskExist(taskId, userId)) throw Errors.TASK_NOT_FOUND; TaskEntity taskEntity = taskRepository.findById(taskId).orElseThrow(() -> Errors.TASK_NOT_FOUND); return getTaskDetailOutputDtoFromTaskEntity(taskEntity); } @Override public Pagination getTasksByUserId(Long userId, Pageable pageable, SearchTaskInputDto searchTaskInputDto) { 28 Pagination pagination = new Pagination(); Page taskEntities = taskRepository.searchInUser(userId, searchTaskInputDto.getKeyword() != null ? searchTaskInputDto.getKeyword() : "", searchTaskInputDto.getDeadline() != null ? searchTaskInputDto.getDeadline().withOffsetSameInstant(ZoneOffset.UTC).toLocalD ate() : null, searchTaskInputDto.getStatus() != null ? searchTaskInputDto.getStatus() : null, pageable); pagination.setItems(taskEntities.stream().map(this::getTaskOutputDtoFromTaskEnt ity).collect(Collectors.toList())); pagination.setTotals(taskEntities.getTotalElements()); return pagination; } @Override public TaskDetailOutputDto createTask(TaskInputDto taskInputDto, Long userId) { TaskEntity taskEntity = taskMapper.getTaskEntityFromTaskInputDto(taskInputDto); validate(taskEntity, userId); return getTaskDetailOutputDtoFromTaskEntity(taskRepository.save(taskEntity)); } @Override public TaskDetailOutputDto updateTask(TaskInputDto taskInputDto, Long taskId, Long userId) { TaskEntity taskEntity = taskMapper.getTaskEntityFromTaskInputDto(taskInputDto); taskEntity.setId(taskId); validate(taskEntity, userId); return getTaskDetailOutputDtoFromTaskEntity(taskRepository.save(taskEntity)); } @Override public void deleteTask(Long taskId, Long userId) { if (!isTaskExist(taskId, userId)) throw Errors.TASK_NOT_FOUND; taskRepository.deleteById(taskId); } @Override public TaskDetailOutputDto getTaskDetailOutputDtoFromTaskEntity(TaskEntity taskEntity) { TaskDetailOutputDto taskDetailOutputDto = taskMapper.getTaskDetailOutputDtoFromTaskEntity(taskEntity); taskDetailOutputDto.setProject(getProjectById(taskEntity.getProjectId())); if (taskEntity.getCurrentDoingTime() == null) return taskDetailOutputDto; long totalMinutes = taskEntity.getNumberOfPomodoro() * 25; long currentMinutes = taskEntity.getCurrentDoingTime().getMinutes(); if (currentMinutes > totalMinutes) currentMinutes = totalMinutes; taskDetailOutputDto.setProgress((double) (currentMinutes * 100 / totalMinutes)); return taskDetailOutputDto; } @Override public TaskOutputDto getTaskOutputDtoFromTaskEntity(TaskEntity taskEntity) { 29 TaskOutputDto taskOutputDto = taskMapper.getTaskOutputDtoFromTaskEntity(taskEntity); long totalMinutes = taskEntity.getNumberOfPomodoro() * 25; if (taskEntity.getCurrentDoingTime() == null) return taskOutputDto; long currentMinutes = taskEntity.getCurrentDoingTime().getMinutes(); if (currentMinutes > totalMinutes) currentMinutes = totalMinutes; taskOutputDto.setProgress((double) (currentMinutes * 100 / totalMinutes)); return taskOutputDto; } private void validate(TaskEntity taskEntity, Long userId) { if (taskEntity.getId() != null && !isTaskExist(taskEntity.getId(), userId)) throw Errors.TASK_NOT_FOUND; if (taskEntity.getDeadline().isBefore(OffsetDateTime.now())) throw Errors.TASK_DEADLINE_IS_BEFORE_NOW; if (!projectRepository.existsByIdAndUserId(taskEntity.getProjectId(), userId)) throw Errors.PROJECT_NOT_FOUND; ProjectEntity projectEntity = projectRepository.findById(taskEntity.getProjectId()).orElseThrow(() -> Errors.PROJECT_NOT_FOUND); if (taskEntity.getDeadline().isAfter(projectEntity.getDeadline())) throw Errors.PROJECT_DEADLINE_IS_BEFORE_TASK_DEADLINE; if (projectEntity.getStatus() == Status.DONE) { throw Errors.PROJECT_STATUS_IS_DONE; } else if (projectEntity.getStatus() == Status.TODO && taskEntity.getStatus() != Status.TODO && taskEntity.getStatus() != null) { throw Errors.PROJECT_STATUS_IS_TODO; } } @Override public boolean isTaskExist(Long taskId, Long userId) { return taskRepository.existsByIdAndUserId(taskId, userId); } @Override public boolean isTaskExist(Long taskId) { return taskRepository.existsById(taskId); } @Override public Pagination getTaskByProjectId(Long userId, Pageable pageable, SearchTaskInputDto search, Long projectId) { Pagination pagination = new Pagination(); Page taskEntities = taskRepository.searchInProject(projectId, search.getKeyword() != null ? search.getKeyword() : "", userId, search.getDeadline() != null ? search.getDeadline().withOffsetSameInstant(ZoneOffset.UTC).toLocalDate() : null, search.getStatus(), pageable); pagination.setItems(taskEntities.stream().map(this::getTaskOutputDtoFromTaskEnt ity).collect(Collectors.toList())); pagination.setTotals(taskEntities.getTotalElements()); return pagination; } @Override 30 public void doTask(Long id, Long userId, DoTaskInputDto doTaskInputDto) { TaskEntity taskEntity = taskRepository.findById(id).orElseThrow(() -> Errors.TASK_NOT_FOUND); if (taskEntity.getStatus() == Status.DONE) throw Errors.TASK_STATUS_IS_DONE; if (taskEntity.getStatus() == Status.TODO) taskEntity.setStatus(Status.IN_PROGRESS); taskEntity.setCurrentDoingTime(doTaskInputDto.getTotalTime()); if(doTaskInputDto.getTotalTime().getMinutes() >= taskEntity.getNumberOfPomodoro() * 25) taskEntity.setStatus(Status.DONE); taskRepository.save(taskEntity); } private ProjectOutputDto getProjectById(Long id) { ProjectEntity projectEntity = projectRepository.findById(id).orElseThrow(() -> Errors.PROJECT_NOT_FOUND); return projectMapper.getProjectOutputDtoFromProjectEntity(projectEntity); } - Xử lý note @Override public NoteDetailOutputDto getNoteDetail(Long noteId, Long userId) { if (!isNoteExist(noteId, userId)) { throw Errors.NOTE_NOT_FOUND; } NoteEntity noteEntity = noteRepository.findById(noteId).orElseThrow(() -> Errors.NOTE_NOT_FOUND); return getNoteDetailOutputDtoFromNoteEntity(noteEntity); } @Override public Pagination getNotesByUserId(Long userId, Pageable pageable, SearchNoteInputDto searchNoteInputDto) { Pagination pagination = new Pagination(); Page noteEntities = noteRepository.searchInUser(userId, searchNoteInputDto.getKeyword() != null ? searchNoteInputDto.getKeyword() : "", pageable); pagination.setItems(noteEntities.stream().map(noteMapper::getNoteOutputDtoFromN oteEntity).collect(Collectors.toList())); pagination.setTotals(noteEntities.getTotalElements()); return pagination; } @Override public NoteDetailOutputDto createNote(NoteInputDto noteInputDto, Long userId) { NoteEntity noteEntity = noteMapper.getNoteEntityFromNoteInputDto(noteInputDto); validate(noteEntity, userId); return getNoteDetailOutputDtoFromNoteEntity(noteRepository.save(noteEntity)); } @Override public NoteDetailOutputDto updateNote(NoteInputDto noteInputDto, Long noteId, Long userId) { NoteEntity noteEntity = 31 noteMapper.getNoteEntityFromNoteInputDto(noteInputDto); noteEntity.setId(noteId); validate(noteEntity, userId); return getNoteDetailOutputDtoFromNoteEntity(noteRepository.save(noteEntity)); } @Override public void deleteNote(Long noteId, Long userId) { if (!isNoteExist(noteId, userId)) { throw Errors.NOTE_NOT_FOUND; } noteRepository.deleteById(noteId); } @Override public boolean isNoteExist(Long noteId, Long userId) { return noteRepository.existsByIdAndUserId(noteId, userId); } @Override public boolean isNoteExist(Long noteId) { return noteRepository.existsById(noteId); } @Override public Pagination getNotesByProjectId(Long userId, Pageable pageable, SearchNoteInputDto search, Long projectId) { Pagination pagination = new Pagination(); Page noteEntities = noteRepository.searchInProject(projectId, search.getKeyword() != null ? search.getKeyword() : "",userId , pageable); pagination.setItems(noteEntities.stream().map(noteMapper::getNoteOutputDtoFromN oteEntity).collect(Collectors.toList())); pagination.setTotals(noteEntities.getTotalElements()); return pagination; } @Override public NoteDetailOutputDto getNoteDetailOutputDtoFromNoteEntity(NoteEntity noteEntity) { NoteDetailOutputDto noteDetailOutputDto = noteMapper.getNoteDetailOutputDtoFromNoteEntity(noteEntity); ProjectEntity projectEntity = projectRepository.findById(noteEntity.getProjectId()).orElseThrow(() -> Errors.PROJECT_NOT_FOUND); ProjectOutputDto projectOutputDto = projectMapper.getProjectOutputDtoFromProjectEntity(projectEntity); noteDetailOutputDto.setProject(projectOutputDto); return noteDetailOutputDto; } private void validate(NoteEntity noteEntity, Long userId) { if(noteEntity.getId() != null && !isNoteExist(noteEntity.getId(), userId)) { throw Errors.NOTE_NOT_FOUND; } 32 if(!projectRepository.existsByIdAndUserId(noteEntity.getProjectId(), userId)) { throw Errors.PROJECT_NOT_FOUND; } } - Xử lý user @Override public UserDetailOutputDto createUser(UserInputDto userInputDto) { if(userRepository.existsUserEntitiesByUsername(userInputDto.getUsername())) { throw Errors.USERNAME_EXISTED; } UserEntity userEntity = userMapper.getUserEntityFromUserInputDto(userInputDto); return userMapper.getUserDetailOutputDtoFromUserEntity(userRepository.save(userEntity) ); } @Override public UserOutputDto getUserByUserName(Long userId) { return userMapper.getUserOutputDtoFromUserEntity(userRepository.getByUserId(userId)); } @Override public UserDetailOutputDto getUserDetail(Long userId) { return userMapper.getUserDetailOutputDtoFromUserEntity(userRepository.getByUserId(user Id)); } @Override public UserDetailOutputDto updateUser(Long userId, UserInputDto userInputDto) { UserEntity userEntity = userMapper.getUserEntityFromUserInputDto(userInputDto); userEntity.setUserId(userId); return userMapper.getUserDetailOutputDtoFromUserEntity(userRepository.save(userEntity) ); } - Xử lý đăng nhập đăng ký @Override public LoginOutputDto login(LoginInputDto loginInputDto) { if(accountService.isAccountExist(loginInputDto.getUsername())) { String encodePassword = accountService.getAccount(loginInputDto.getUsername()).getPassword(); if(!passwordEncoder.matches(loginInputDto.getPassword(), encodePassword)) throw Errors.USERNAME_OR_PASSWORD_INCORRECT; Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( loginInputDto.getUsername(), loginInputDto.getPassword() 33 ) ); SecurityContextHolder.getContext().setAuthentication(authentication); String jwt = jwtService.generateToken((UserDetailEntity) authentication.getPrincipal()); String refreshJwt = jwtService.generateRefreshToken((UserDetailEntity) authentication.getPrincipal()); return new LoginOutputDto(jwt, refreshJwt); } else { throw Errors.USERNAME_OR_PASSWORD_INCORRECT; } } @Override public RegisterOutputDto register(RegisterInputDto registerInputDto) { AccountInputDto accountInputDto = authMapper.getAccountInputDtoFromRegisterInputDto(registerInputDto); UserInputDto userInputDto = authMapper.getUserInputDtoFromRegisterInputDto(registerInputDto); UserDetailOutputDto userDetailOutputDto = userService.createUser(userInputDto); accountInputDto.setUserId(userDetailOutputDto.getUserId()); accountInputDto.setPassword(passwordEncoder.encode(registerInputDto.getPassword ())); System.out.println(accountInputDto.getPassword()); accountService.createAccount(accountInputDto); accountMapper.getEntityFromInput(accountInputDto); return authMapper.getRegisterOutputDtoFromUserDetailOutputDto(userDetailOutputDto); } @Override public LoginOutputDto refreshToken(String refreshToken) { UserDetailEntity userDetail = (UserDetailEntity) securityService.loadUserByUsername(jwtService.getUserNameFromToken(refreshToken )); String jwt = jwtService.generateToken(userDetail); String refreshJwt = jwtService.generateRefreshToken(userDetail); return new LoginOutputDto(jwt, refreshJwt); } - Xử lý xác thực, phân quyền @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { try { if(request.getRequestURI().contains("/api/v1/auth/")) { filterChain.doFilter(request, response); return; } String jwt = getJwtFromRequest(request); if (StringUtils.hasText(jwt) && jwtService.validateToken(jwt)) { 34 Long userId = jwtService.getUserIdFromToken(jwt); UserDetails userDetails = securityService.loadUserById(userId); if (userDetails != null) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); System.out.println(userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } catch (Exception e) { if(e == Errors.UNAUTHORIZED || e == Errors.TOKEN_EXPIRED) { response.setStatus(403); } else { response.setStatus(500); } } } private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } throw Errors.UNAUTHORIZED; } 35

Ngày đăng: 11/11/2023, 22:46

Tài liệu cùng người dùng

Tài liệu liên quan