실습
API 명세서
//초기데이터 (나중에는 서버에서 받아올 부분)
let basicDatas = [];
function getTodos(){
const xhr = new XMLHttpRequest();
xhr.open("get","http://localhost:8080/api/todos");
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 ){
if(xhr.status === 200){
// json 문자열을 json 객체로 변환시킨다.
let todos = JSON.parse(this.responseText);
// console.log(todos);
for(let i = 0; i < todos.length; i++){
todoItemAdd(todos[i]);
}
}
}
}
xhr.send();
}
function updateTodo(id){
// let updateTodo = {"id":id};
let xhr = new XMLHttpRequest();
xhr.open('PATCH','http://localhost:8080/api/todos/'+id);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
// xhr.send(JSON.stringify(updateTodo));
xhr.send();
}
function deleteTodo(id){
let delTodo = {"id": id}; //이거 주석처리가 딜리트 위아래를 나타냄
let xhr = new XMLHttpRequest();
// xhr.open('DELETE','http://localhost:8080/api/todos');
xhr.open('DELETE','http://localhost:8080/api/todos/'+id);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(JSON.stringify());
// xhr.send(JSON.stringify(delTodo));
}
function postTodo(todo){
let xhr = new XMLHttpRequest();
xhr.open('post','http://localhost:8080/api/todos');
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onload = function(){
// 글쓰기를 할 경우 ajax의 결과를 json 오브젝트로 변환하여 추가한다.
todoItemAdd(JSON.parse(xhr.responseText));
};
xhr.send(JSON.stringify({"todo":todo}));
}
getTodos();
let todoUl = document.querySelector("#todo-item-list");
todoUl.addEventListener('click',function(event){
let eventTarget = event.target;
if(event.target.tagName === 'LI' || event.target.tagName === 'SPAN'){
if(event.target.tagName ==='LI'){
eventTarget =eventTarget.querySelector('.todo-text');
}
let liObj = eventTarget.parentElement;
updateTodo(liObj.getAttribute("id"));
eventTarget.classList.toggle('checked');
}
});
const inputbtn = document.querySelector('.add-button');
// const myinput = document.querySelector('#myInput');
inputbtn.addEventListener('click', function(){
inputValue = document.querySelector('#myInput').value;
if(inputValue === ''){
alert("할 일을 입력해 주세요^^ ");
return;
}
document.querySelector('#myInput').value = '';
postTodo(inputValue);
});
function todoItemAdd(todoObj){
console.log(todoObj);
const li = document.createElement('li');
li.className = "todo-item";
const textSpan = document.createElement('SPAN');
textSpan.className = "todo-text" ;
const todotxt = document.createTextNode(todoObj.todo);
textSpan.appendChild(todotxt);
if(todoObj.done == true){
// 완료된 작업일 경우 css를 이용하여 줄을 긋는다.
textSpan.classList.toggle('checked');
}
li.appendChild(textSpan);
li.setAttribute("id", todoObj.id);
document.getElementById('todo-item-list').appendChild(li);
const removeSpan = document.createElement("SPAN");
const removetxt = document.createTextNode("\u00D7");
removeSpan.className = "remove";
removeSpan.appendChild(removetxt);
li.appendChild(removeSpan);
// 동적으로 x버튼을 클릭했을 때 처리해야할 이벤트를 추가한다.
removeSpan.addEventListener('click',function(){
let liObj = this.parentElement;
console.log(liObj);
deleteTodo(liObj.getAttribute("id"));
liObj.remove();
return false; // return false를 하지 않으면 수정이 되면서 update를 호출한다.이미 삭제된 것을 수정하려고 하니 오류가 발생한다. https://programmingsummaries.tistory.com/313
});
};
@Service
@RequiredArgsConstructor
public class TodoService {
private final TodoRepository todoRepository;
@Transactional(readOnly = true)
public List<Todo> getTodos(){
return todoRepository.findAll(Sort.by("id").descending());
}
@Transactional
public Todo addTodo(String todo){
return todoRepository.save(new Todo(todo));
}
@Transactional
public Todo updateTodo(Long id){
boolean exists = todoRepository.existsById(id);
if(!exists){
throw new EntityNotFoundException("이미 삭제된 Todo 입니다." + id);
}
Todo todo = todoRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("id에 해당되는 todo를 찾을 수 없어요." + id));
todo.setDone(!todo.isDone());
return todo;
}
@Transactional
public void deleteTodo(Long id){
if(!todoRepository.existsById(id)){
throw new RuntimeException("id에 해당하는 todo가 없어요."+id);
}
todoRepository.deleteById(id);
}
}
public interface TodoRepository extends JpaRepository<Todo,Long> {
}
@Entity
@Table(name = "todos")
@Getter
@Setter
@NoArgsConstructor
@ToString
public class Todo {
@Id@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String todo; // 할 일 내용
private boolean done; // 완료 여부
public Todo(String todo) {
this.todo = todo;
}
}
@RestController
@RequestMapping("/api/todos")
@RequiredArgsConstructor
public class TodoController {
private final TodoService todoService;
@GetMapping
public ResponseEntity<List<Todo>> getTodos(){
return ResponseEntity.ok(todoService.getTodos());
}
//todo 추가
@PostMapping
public ResponseEntity<Todo> addTodo(@RequestBody Todo todo){
Todo createTodo = todoService.addTodo(todo.getTodo());
return ResponseEntity.status(HttpStatus.CREATED).body(createTodo);
}
//todo의 done 수정
@PatchMapping("/{id}")
public ResponseEntity<Todo> updateTodd(@PathVariable("id")Long id){
Todo updateTodo = todoService.updateTodo(id);
return ResponseEntity.ok(updateTodo);
}
//
@DeleteMapping
public ResponseEntity<Void> deleteTodo2(@RequestBody Todo todo){
todoService.deleteTodo(todo.getId());
return ResponseEntity.noContent().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteTodo(@PathVariable("id")Long id){
todoService.deleteTodo(id);
return ResponseEntity.noContent().build();
}
}