: 매일 저녁, 하루를 마무리하며 작성 !
: ⭕ 지식 위주, 학습한 것을 노트 정리한다고 생각하고 작성하면서 머리 속 흩어져있는 지식들을 정리 !
class Solution {
public int solution(int[] absolutes, boolean[] signs) {
int answer = 0;
for(int i=0; i<absolutes.length; i++){
if(signs[i]){
answer = answer + absolutes[i];
}else if(!signs[i]){
answer = answer - absolutes[i];
}
}
return answer;
}
}
6단계까지 구현
// SchedulerController.java
package com.sparta.scheduler.controller;
import com.sparta.scheduler.dto.SchedulerRequestDto;
import com.sparta.scheduler.dto.SchedulerResponseDto;
import com.sparta.scheduler.entity.Scheduler;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Date;
import java.util.List;
@RestController
@RequestMapping("/api")
public class SchedulerController {
private final JdbcTemplate jdbcTemplate;
public SchedulerController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostMapping("/schedulers")
public SchedulerResponseDto createScheduler(@RequestBody SchedulerRequestDto requestDto) {
// RequestDto -> Entity
Scheduler scheduler = new Scheduler(requestDto);
// DB 저장
KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체
String sql = "INSERT INTO scheduler (title, contents, username, password, date) VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.update(con -> {
PreparedStatement preparedStatement = con.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, scheduler.getTitle());
preparedStatement.setString(2, scheduler.getContents());
preparedStatement.setString(3, scheduler.getUsername());
preparedStatement.setString(4, scheduler.getPassword());
preparedStatement.setDate(5, scheduler.getDate());
return preparedStatement;
},
keyHolder);
// DB Insert 후 받아온 기본키 확인
Long id = keyHolder.getKey().longValue();
scheduler.setId(id);
// Entity -> ResponseDto
SchedulerResponseDto schedulerResponseDto = new SchedulerResponseDto(scheduler);
return schedulerResponseDto;
}
@GetMapping("/schedulers")
public List<SchedulerResponseDto> getschedulers() {
// DB 조회
String sql = "SELECT * FROM scheduler";
return jdbcTemplate.query(sql, new RowMapper<SchedulerResponseDto>() {
@Override
public SchedulerResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
// SQL 의 결과로 받아온 Schedulers 데이터들을 SchedulersResponseDto 타입으로 변환해줄 메서드
Long id = rs.getLong("id");
String title = rs.getString("title");
String contents = rs.getString("contents");
String username = rs.getString("username");
String password = rs.getString("password");
Date date = rs.getDate("date");
return new SchedulerResponseDto(id, title, contents, username, password, date);
}
});
}
@PutMapping("/schedulers/{id}")
public Long updateScheduler(@PathVariable Long id, @RequestBody SchedulerRequestDto requestDto) {
// 해당 메모가 DB에 존재하는지 확인
Scheduler scheduler = findById(id);
if (scheduler != null) {
// 비밀번호 확인
if (!scheduler.getPassword().equals(requestDto.getPassword())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "비밀번호가 올바르지 않습니다.");
}
// Null 및 빈 값 검사 추가
validateRequestDto(requestDto);
// scheduler 내용 수정
String sql = "UPDATE scheduler SET title = ?, contents = ?, username = ?, password = ?, date = ? WHERE id = ?";
jdbcTemplate.update(sql, requestDto.getTitle(), requestDto.getContents(),
requestDto.getUsername(), requestDto.getPassword(), requestDto.getDate(), id);
return id;
} else {
throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
}
}
private void validateRequestDto(SchedulerRequestDto requestDto) {
if (requestDto.getTitle() == null || requestDto.getTitle().isEmpty()) {
throw new IllegalArgumentException("Title cannot be null or empty");
}
if (requestDto.getContents() == null || requestDto.getContents().isEmpty()) {
throw new IllegalArgumentException("Contents cannot be null or empty");
}
if (requestDto.getUsername() == null || requestDto.getUsername().isEmpty()) {
throw new IllegalArgumentException("Username cannot be null or empty");
}
if (requestDto.getPassword() == null || requestDto.getPassword().isEmpty()) {
throw new IllegalArgumentException("Password cannot be null or empty");
}
if (requestDto.getDate() == null) {
throw new IllegalArgumentException("Date cannot be null");
}
}
@DeleteMapping("/schedulers/{id}")
public Long deleteScheduler(@PathVariable Long id, @RequestBody SchedulerRequestDto requestDto) {
// 해당 메모가 DB에 존재하는지 확인
Scheduler scheduler = findById(id);
if (scheduler != null) {
// 비밀번호 확인
if (!scheduler.getPassword().equals(requestDto.getPassword())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "비밀번호가 올바르지 않습니다.");
}
// scheduler 삭제
String sql = "DELETE FROM scheduler WHERE id = ?";
jdbcTemplate.update(sql, id);
return id;
} else {
throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
}
}
private Scheduler findById(Long id) {
// DB 조회
String sql = "SELECT * FROM scheduler WHERE id = ?";
return jdbcTemplate.query(sql, resultSet -> {
if (resultSet.next()) {
Scheduler scheduler = new Scheduler();
scheduler.setTitle(resultSet.getString("title"));
scheduler.setContents(resultSet.getString("contents"));
scheduler.setUsername(resultSet.getString("username"));
scheduler.setPassword(resultSet.getString("password"));
scheduler.setDate(resultSet.getDate("date"));
return scheduler;
} else {
return null;
}
}, id);
}
}
// SchedulerRequestDto.java ------------------------------------------
package com.sparta.scheduler.dto;
import lombok.Getter;
import java.sql.Date;
@Getter
public class SchedulerRequestDto {
private String title;
private String contents;
private String username;
private String password;
private Date date;
}
// SchedulerResponseDto.java ------------------------------------------
package com.sparta.scheduler.dto;
import com.sparta.scheduler.entity.Scheduler;
import lombok.Getter;
import java.sql.Date;
@Getter
public class SchedulerResponseDto {
private Long id;
private String title;
private String contents;
private String username;
private String password;
private Date date;
public SchedulerResponseDto(Scheduler scheduler) {
this.id = scheduler.getId();
this.title = scheduler.getTitle();
this.contents = scheduler.getContents();
this.username = scheduler.getUsername();
this.password = scheduler.getPassword();
this.date = scheduler.getDate();
}
public SchedulerResponseDto(Long id, String title, String contents, String username, String password, Date date ) {
this.id = id;
this.title = title;
this.contents = contents;
this.username = username;
this.password = password;
this.date = date;
}
}
// Scheduler.java ------------------------------------------
package com.sparta.scheduler.entity;
import com.sparta.scheduler.dto.SchedulerRequestDto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.sql.Date;
@Getter
@Setter
@NoArgsConstructor
public class Scheduler {
private Long id;
private String title;
private String contents;
private String username;
private String password;
private Date date;
public Scheduler(SchedulerRequestDto requestDto) {
this.title = requestDto.getTitle();
this.contents = requestDto.getContents();
this.username = requestDto.getUsername();
this.password = requestDto.getPassword();
this.date = requestDto.getDate();
}
public void update(SchedulerRequestDto requestDto) {
this.title = requestDto.getTitle();
this.contents = requestDto.getContents();
this.username = requestDto.getUsername();
this.password = requestDto.getPassword();
this.date = requestDto.getDate();
}
}
// index.html ------------------------------------------
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>일정 관리 서비스</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@500&display=swap" rel="stylesheet">
<style>
@import url(//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-kr.css);
body {
margin: 0px;
}
.area-edit {
display: none;
}
.wrap {
width: 538px;
margin: 10px auto;
}
.area-write {
position: relative;
width: 538px;
padding: 20px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.area-write img {
cursor: pointer;
position: absolute;
width: 22.2px;
height: 18.7px;
bottom: 20px;
right: 20px;
}
.background-header {
position: fixed;
z-index: -1;
top: 0px;
width: 100%;
height: 428px;
background-color: #339af0;
}
.background-body {
position: fixed;
z-index: -1;
top: 428px;
height: 100%;
width: 100%;
background-color: #dee2e6;
}
.header {
margin-top: 50px;
}
.header h2 {
height: 33px;
font-size: 42px;
font-weight: 500;
text-align: center;
color: #ffffff;
}
.header p {
margin: 40px auto;
width: 217px;
height: 48px;
font-family: 'Noto Sans KR', sans-serif;
font-size: 16px;
font-weight: 500;
text-align: center;
color: #ffffff;
}
.field, .field-title, .field-username, .field-password, .field-date {
width: 100%;
border-radius: 5px;
background-color: #ffffff;
border: 1px solid #ced4da;
padding: 18px;
resize: none;
margin-bottom: 10px;
box-sizing: border-box;
}
textarea.field::placeholder, .field-title::placeholder, .field-username::placeholder, .field-password::placeholder, .field-date::placeholder {
font-family: 'Noto Sans KR', sans-serif;
font-size: 16px;
font-weight: normal;
text-align: left;
color: #868e96;
}
.card {
width: 538px;
border-radius: 5px;
background-color: #ffffff;
margin-bottom: 12px;
}
.card .metadata {
position: relative;
display: flex;
font-family: 'Spoqa Han Sans';
font-size: 11px;
font-weight: normal;
text-align: left;
color: #adb5bd;
height: 14px;
padding: 10px 23px;
}
.card .metadata .date {
}
.card .metadata .username {
margin-left: 20px;
}
.title, .contents {
padding: 0px 23px;
}
.title .text, .contents .text {
word-wrap: break-word;
word-break: break-all;
}
.edit {
display: none;
}
.te-edit {
border-right: none;
border-top: none;
border-left: none;
resize: none;
border-bottom: 1px solid #212529;
width: 100%;
font-family: 'Spoqa Han Sans';
}
.footer {
position: relative;
height: 40px;
}
.footer img.icon-start-edit {
cursor: pointer;
position: absolute;
bottom: 14px;
right: 55px;
width: 18px;
height: 18px;
}
.footer img.icon-end-edit {
cursor: pointer;
position: absolute;
display: none;
bottom: 14px;
right: 55px;
width: 20px;
height: 15px;
}
.footer img.icon-delete {
cursor: pointer;
position: absolute;
bottom: 12px;
right: 19px;
width: 14px;
height: 18px;
}
#cards-box {
margin-top: 12px;
}
</style>
<script>
// 사용자가 내용을 올바르게 입력하였는지 확인합니다.
function isValidContents(contents) {
if (contents == '') {
alert('내용을 입력해주세요');
return false;
}
if (contents.trim().length > 500) {
alert('공백 포함 500자 이하로 입력해주세요');
return false;
}
return true;
}
// 수정 버튼을 눌렀을 때, 기존 작성 내용을 textarea 에 전달합니다.
// 숨길 버튼을 숨기고, 나타낼 버튼을 나타냅니다.
function editPost(id) {
showEdits(id);
let title = $(`#${id}-title`).text().trim();
let contents = $(`#${id}-content`).text().trim();
let username = $(`#${id}-username`).text().trim();
let date = $(`#${id}-date`).text().trim();
$(`#${id}-title-textarea`).val(title);
$(`#${id}-content-textarea`).val(contents);
$(`#${id}-username-textarea`).val(username);
$(`#${id}-date-textarea`).val(date);
}
function showEdits(id) {
// title, content, username, date 텍스트 에어리어만 표시
$(`#${id}-editarea-title`).show();
$(`#${id}-editarea-content`).show();
$(`#${id}-editarea-username`).show();
$(`#${id}-editarea-date`).show();
$(`#${id}-editarea-password`).show(); // 비밀번호 입력 필드 표시
$(`#${id}-submit`).show();
$(`#${id}-delete`).show();
// 기존 텍스트는 숨김
$(`#${id}-title`).hide();
$(`#${id}-content`).hide();
$(`#${id}-username`).hide();
$(`#${id}-date`).hide();
$(`#${id}-edit`).hide();
// 이전 값 유지
let prevTitle = $(`#${id}-title`).text().trim();
let prevContents = $(`#${id}-content`).text().trim();
let prevUsername = $(`#${id}-username`).text().trim();
let prevDate = $(`#${id}-date`).text().trim();
$(`#${id}-title-textarea`).val(prevTitle);
$(`#${id}-content-textarea`).val(prevContents);
$(`#${id}-username-textarea`).val(prevUsername);
$(`#${id}-date-textarea`).val(prevDate);
}
$(document).ready(function() {
// HTML 문서를 로드할 때마다 실행합니다.
getMessages();
// 수정 버튼 클릭 시 이벤트 설정
$(document).on("click", ".icon-start-edit", function() {
let id = $(this).attr("id").split("-")[0];
showEdits(id);
});
});
// 일정을 불러와서 보여줍니다.
function getMessages() {
// 1. 기존 메모 내용을 지웁니다.
$('#cards-box').empty();
// 2. 일정 목록을 불러와서 HTML로 붙입니다.
$.ajax({
type: 'GET',
url: '/api/schedulers',
success: function (response) {
for (let i = 0; i < response.length; i++) {
let message = response[i];
let id = message['id'];
let title = message['title'];
let username = message['username'];
let contents = message['contents'];
let date = message['date'];
addHTML(id, title, username, contents, date);
}
}
})
}
// 메모 하나를 HTML로 만들어서 body 태그 내 원하는 곳에 붙입니다.
function addHTML(id, title, username, contents, date) {
// 1. HTML 태그를 만듭니다.
let tempHtml = `<div class="card">
<!-- date/username 영역 -->
<div class="metadata">
<div id="${id}-date" class="date">
${date}
</div>
<div id="${id}-username" class="username">
${username}
</div>
</div>
<!-- title 영역 -->
<div class="title">
<div id="${id}-title" class="text">
${title}
</div>
<div id="${id}-editarea-title" class="edit">
<textarea id="${id}-title-textarea" class="te-edit" name="" cols="30" rows="1"></textarea>
</div>
</div>
<!-- contents 조회/수정 영역-->
<div class="contents">
<div id="${id}-content" class="text">
${contents}
</div>
<div id="${id}-editarea-content" class="edit">
<textarea id="${id}-content-textarea" class="te-edit" name="" cols="30" rows="5"></textarea>
</div>
<div id="${id}-editarea-username" class="edit">
<textarea id="${id}-username-textarea" class="te-edit" name="" cols="30" rows="1"></textarea>
</div>
<div id="${id}-editarea-date" class="edit">
<input type="date" id="${id}-date-textarea" class="field-date te-edit">
</div>
<div id="${id}-editarea-password" class="edit">
<input type="password" id="${id}-password-textarea" class="te-edit" placeholder="비밀번호를 입력해주세요">
</div>
</div>
<!-- 버튼 영역-->
<div class="footer">
<img id="${id}-edit" class="icon-start-edit" src="images/edit.png" alt="수정"token interpolation">${id}')">
<img id="${id}-delete" class="icon-delete" src="images/delete.png" alt="삭제"token interpolation">${id}')">
<img id="${id}-submit" class="icon-end-edit" src="images/done.png" alt="완료"token interpolation">${id}')">
</div>
</div>`;
// 2. #cards-box 에 HTML을 붙인다.
$('#cards-box').append(tempHtml);
}
// 일정을 생성합니다.
function writePost() {
// 1. 입력된 값을 읽어옵니다.
let title = $('#title').val();
let contents = $('#contents-textarea').val();
let username = $('#username').val();
let password = $('#password').val();
let date = $('#date').val(); // 사용자가 선택한 날짜 값 읽기
// 2. 유효성 검사를 진행합니다.
if (!isValidContents(contents)) {
return;
}
// 3. 일정을 생성합니다.
let data = {title: title, contents: contents, username: username, password: password, date: date}; // date 포함
$.ajax({
type: 'POST',
url: '/api/schedulers',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (response) {
// 4. 성공하면, 일정을 목록에 추가하고 입력 필드를 초기화합니다.
addHTML(response.id, title, username, contents, date); // date 포함
$('#title').val('');
$('#contents-textarea').val('');
$('#username').val('');
$('#password').val('');
$('#date').val(''); // 입력 필드 초기화
}
});
}
// 일정을 삭제합니다.
function deleteOne(id) {
$.ajax({
type: 'DELETE',
url: `/api/schedulers/${id}`,
success: function (response) {
alert('메모를 삭제했습니다.');
getMessages();
}
})
}
// 수정을 반영합니다.
function submitEdit(id) {
let title = $(`#${id}-title-textarea`).val().trim();
let contents = $(`#${id}-content-textarea`).val().trim();
let username = $(`#${id}-username-textarea`).val().trim();
let date = $(`#${id}-date-textarea`).val().trim();
let password = $(`#${id}-password-textarea`).val().trim();
if (!isValidContents(contents)) {
return;
}
let data = {title, contents, username, date, password};
$.ajax({
type: "PUT",
url: `/api/schedulers/${id}`,
contentType: "application/json",
data: JSON.stringify(data),
success: function(response) {
alert('일정이 수정되었습니다.');
getMessages();
},
error: function(response) {
if (response.status === 403) {
alert('비밀번호가 올바르지 않습니다. 다시 시도해주세요.');
}
}
});
}
function deleteOne(id) {
let password = prompt("비밀번호를 입력해주세요.");
if (password == null) {
return; // 사용자가 취소를 누른 경우
}
let data = {password};
$.ajax({
type: "DELETE",
url: `/api/schedulers/${id}`,
contentType: "application/json",
data: JSON.stringify(data),
success: function(response) {
alert('일정이 삭제되었습니다.');
getMessages();
},
error: function(response) {
if (response.status === 403) {
alert('비밀번호가 올바르지 않습니다. 다시 시도해주세요.');
}
}
});
}
</script>
</head>
<body>
<div class="wrap">
<!-- header 영역-->
<div class="header">
<h2>나만의 일정 관리 서비스</h2>
<p>스케줄을 작성하고 관리하세요</p>
</div>
<!-- write 영역 -->
<div class="area-write">
<input type="text" id="title" class="field-title" placeholder="제목을 입력해주세요">
<textarea id="contents-textarea" class="field" placeholder="내용을 입력해주세요"></textarea>
<input type="text" id="username" class="field-username" placeholder="작성자를 입력해주세요">
<input type="password" id="password" class="field-password" placeholder="비밀번호를 입력해주세요">
<input type="date" id="date" class="field-date"> <!-- 날짜 선택 입력 칸 추가 -->
<img src="images/send.png" alt="작성" onclick="writePost()">
</div>
<!-- card 영역 -->
<div id="cards-box"></div>
</div>
<div class="background-header"></div>
<div class="background-body"></div>
</body>
</html>