Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ dependencies {
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'com.mysql:mysql-connector-j'
implementation 'org.modelmapper:modelmapper:3.2.0'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.liquibase:liquibase-core'

// testImplementation "org.testcontainers:testcontainers:1.19.7"
testImplementation('org.testcontainers:mysql') //no version specified
testImplementation 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
1,379 changes: 1,353 additions & 26 deletions myfile.log

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/lombok.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config.stopbubbling=true
lombok.copyableannotations += org.springframework.beans.factory.annotation.Value
lombok.copyableannotations += org.springframework.beans.factory.annotation.Qualifier
29 changes: 10 additions & 19 deletions src/main/java/com/study/springjrproj/config/AppConfig.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
package com.study.springjrproj.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.stereotype.Component;
import com.study.springjrproj.repository.TaskRepository;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Pageable;

@Configuration
//@PropertySource("classpath:application.yaml")
//@ComponentScan(basePackages = "org.example",
// resourcePattern = "**/*.class",
// useDefaultFilters = false,
// includeFilters = {
// @Filter(type = FilterType.ANNOTATION,
// value = Component.class),
// @Filter(type = FilterType.ASSIGNABLE_TYPE,
// value = CompanyRepository.class),
// @Filter(type = FilterType.REGEX,
// pattern = "org\\..Repository"),
// }
//)

public class AppConfig {
@Bean
public ModelMapper getModelMapper() {
return new ModelMapper();
}
}

45 changes: 45 additions & 0 deletions src/main/java/com/study/springjrproj/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.study.springjrproj.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring6.ISpringTemplateEngine;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/tasks").setViewName("tasks");
}

@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}

private ISpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}

private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
75 changes: 63 additions & 12 deletions src/main/java/com/study/springjrproj/controller/TaskController.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,76 @@
package com.study.springjrproj.controller;


import com.study.springjrproj.repository.TaskRepository;
import com.study.springjrproj.dto.CreateTaskDto;
import com.study.springjrproj.dto.TaskDto;
import com.study.springjrproj.exception.TaskNotFoundException;
import com.study.springjrproj.service.TaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

@Controller
@RequiredArgsConstructor

@RequestMapping("/tasks")
@Slf4j
public class TaskController {
private final TaskRepository taskRepository;
private final TaskService taskService;

@RequestMapping(method = RequestMethod.GET, value = "tasks")
public String hello() {
var modelAndView = new ModelAndView();
var tasks = taskRepository.findAll();
modelAndView.addObject("tasks", tasks);
modelAndView.setViewName("tasks");
@RequestMapping(method = RequestMethod.GET)
public String getAllTasks(Model model,
@RequestParam(defaultValue = "0", required = false) int page,
@RequestParam(defaultValue = "5", required = false) int size) {
Pageable pageable = PageRequest.of(page, size);
var tasksPerPage = taskService.findAllBy(pageable);
model.addAttribute("tasksPerPage", tasksPerPage);
log.trace("Added attribute - tasksPerPage");
return "tasks";
}

@RequestMapping(method = RequestMethod.POST, value = "/edit/{id}")
public String edit(@PathVariable Integer id, @ModelAttribute TaskDto taskToUpdate) {
taskService.update(taskToUpdate);
log.info("Updated task");
return "redirect:/tasks";
}

@RequestMapping(method = RequestMethod.GET, value = "/edit/{id}")
public String editForm(@PathVariable Integer id, Model model) {
try {
var taskDto = taskService.findById(id);
model.addAttribute("task", taskDto.get());
log.trace("Added attribute - task");
return "edit";
} catch (TaskNotFoundException e) {
log.warn("Task not found");
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
@PostMapping("/delete/{id}")
public String delete(@PathVariable Integer id) {
try {
taskService.deleteById(id);
log.info("Task was deleted");
return "redirect:/tasks";
} catch (TaskNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
@GetMapping("/create")
public String createForm(Model model) {
model.addAttribute("task", new TaskDto());
log.trace("Added attribute - task");
return "create";
}
@PostMapping("/create")
public String createForm(@ModelAttribute("task") CreateTaskDto taskDto) {
taskService.save(taskDto);
return "redirect:/tasks";
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/study/springjrproj/domain/Task.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ public class Task {
@Column(nullable = false)
private String description;
private Status status;
@ManyToOne
@JoinColumn(name = "user_id")
private Users user;
}
24 changes: 24 additions & 0 deletions src/main/java/com/study/springjrproj/domain/Users.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.study.springjrproj.domain;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true)
private String username;
@Column(unique = true)
private String email;
@Column(name = "birth_date")
private LocalDate birthDate;
}
11 changes: 11 additions & 0 deletions src/main/java/com/study/springjrproj/dto/CreateTaskDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.study.springjrproj.dto;

import com.study.springjrproj.domain.Status;
import lombok.Value;

@Value
public class CreateTaskDto {
String description;
Status status;

}
15 changes: 15 additions & 0 deletions src/main/java/com/study/springjrproj/dto/TaskDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.study.springjrproj.dto;

import com.study.springjrproj.domain.Status;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TaskDto {
private int id;
private String description;
private Status status;
}
10 changes: 10 additions & 0 deletions src/main/java/com/study/springjrproj/dto/UserDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.study.springjrproj.dto;

import java.time.LocalDate;

public class UserDto {
private int id;
private String username;
private String email;
private LocalDate birthDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.study.springjrproj.exception;

public class TaskNotFoundException extends RuntimeException {
public TaskNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package com.study.springjrproj.repository;

import com.study.springjrproj.domain.Status;
import com.study.springjrproj.domain.Task;
import com.study.springjrproj.dto.TaskDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface TaskRepository extends JpaRepository<Task, Integer> {

@Query(value = "update Task t set t.status = :description")
Task updateBy(String description);

@Query(value = "update Task t set t.status = :status")
Task updateBy(Status status);

Page<TaskDto> findAllBy(Pageable pageable);
}
72 changes: 72 additions & 0 deletions src/main/java/com/study/springjrproj/service/TaskService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.study.springjrproj.service;

import com.study.springjrproj.domain.Task;
import com.study.springjrproj.dto.CreateTaskDto;
import com.study.springjrproj.dto.TaskDto;
import com.study.springjrproj.exception.TaskNotFoundException;
import com.study.springjrproj.repository.TaskRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class TaskService {
private final TaskRepository taskRepository;
private final ModelMapper mapper;

public List<TaskDto> findAll() {
var tasks = taskRepository.findAll();
log.info("Received {} tasks", tasks.size());
var taskDtoStream = tasks.stream().map(task -> mapper.map(task, TaskDto.class));
return taskDtoStream
.collect(Collectors.toList());
}

public Page<TaskDto> findAllBy(Pageable pageable) {
var tasks = taskRepository.findAll(pageable);
log.info("Received {} tasks on the page", tasks.stream().count());
return tasks.map(task -> mapper.map(task, TaskDto.class));
}

public Optional<TaskDto> findById(Integer id) {
return Optional.ofNullable(taskRepository.findById(id)
.map(task -> mapper.map(task, TaskDto.class))
.orElseThrow(() -> new TaskNotFoundException("Task with" + id + " not found")));
}

public void update(TaskDto taskDto) {
var task = mapper.map(taskDto, Task.class);
log.info("Received task {}", task);
taskRepository.save(task);
}

public void deleteById(Integer id) {
var maybeTask = taskRepository.findById(id);
maybeTask.ifPresent(task -> {
log.info("Received task {}", task);
taskRepository.delete(task);
});
maybeTask.orElseThrow(() -> new TaskNotFoundException("Task with id {} not found"));
}

public void save(CreateTaskDto createTaskDto) {
var task = mapper.map(createTaskDto, Task.class);
taskRepository.saveAndFlush(task);
if (taskRepository.findById(task.getId()).isPresent()) {
log.info("Task was added successfully");
} else {
log.info("Task not found");
}
}
}
4 changes: 2 additions & 2 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ spring:
name : springJRproj
mvc:
view:
suffix: .jsp
prefix : /WEB-INF/views/
suffix: .html

profiles:
active: qa
datasource :
Expand Down
19 changes: 19 additions & 0 deletions src/main/resources/db/changelog/db.changelog-1.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--liquibase formatted sql

--changeset Volodymyr Malyniak:1
create table IF NOT EXISTS `users` (
`id` int primary key auto_increment,
`username` varchar(32) unique ,
`email` varchar(32) unique ,
`birth_date` date
);

--changeset Volodymyr Malyniak:2
CREATE TABLE IF NOT EXISTS `task` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(100) NOT NULL,
`status` int(11) NOT NULL,
user_id int,
PRIMARY KEY (`id`),
foreign key (user_id) references users(id)
)
Loading