<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>롤로야</title>
    <link>https://cej4297.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 11 Jul 2026 03:41:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>호롤로</managingEditor>
    <item>
      <title>TIL 2025/02/26</title>
      <link>https://cej4297.tistory.com/46</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 오늘 한일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 차주 목요일에 발재된 Spring 심화 주차 개인 과제 필수 단계를 완성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행 사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- LV 1 ~ LV 3 까지의 필수 단계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ LV 1. 코드 개선&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;● 코드 개선 퀴즈 - Early Return&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 수정 (검사 우선 순위 변경)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Transactional
    public SignupResponse signup(SignupRequest signupRequest) {

        if (userRepository.existsByEmail(signupRequest.getEmail())) { // 중복여부 선 검사 진행
            throw new InvalidRequestException(&quot;이미 존재하는 이메일입니다.&quot;);
        }

        String encodedPassword = passwordEncoder.encode(signupRequest.getPassword()); // 비밀번호 암호화

        UserRole userRole = UserRole.of(signupRequest.getUserRole()); // 사용자 역할 지정

//        if (userRepository.existsByEmail(signupRequest.getEmail())) { // 중복여부 검사
//            throw new InvalidRequestException(&quot;이미 존재하는 이메일입니다.&quot;);
//        }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;● 리팩토링 퀴즈 - 불필요한 if-else 피하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 수정 (if 이후 return 또는 실행할 코드가 있을경우 else 불필요)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Component
public class WeatherClient {

    private final RestTemplate restTemplate;

    public WeatherClient(RestTemplateBuilder builder) {
        this.restTemplate = builder.build();
    }

    public String getTodayWeather() {
        ResponseEntity&amp;lt;WeatherDto[]&amp;gt; responseEntity =
                restTemplate.getForEntity(buildWeatherApiUri(), WeatherDto[].class);

        WeatherDto[] weatherArray = responseEntity.getBody();
        if (!HttpStatus.OK.equals(responseEntity.getStatusCode())) { // 단순히 else 부분 제거
            throw new ServerException(&quot;날씨 데이터를 가져오는데 실패했습니다. 상태 코드: &quot; + responseEntity.getStatusCode()); // if 바로뒤에 실행할 코드가 있으면 else 가 필요 없음
        }
        if (weatherArray == null || weatherArray.length == 0) { // if(검사)를 개별적으로 수행하여 가독성 향상
            throw new ServerException(&quot;날씨 데이터가 없습니다.&quot;);
        }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;● 코드 개선 퀴즈 - Validation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 수정&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;    @Transactional
    public void changePassword(long userId, UserChangePasswordRequest userChangePasswordRequest) {
//        if (userChangePasswordRequest.getNewPassword().length() &amp;lt; 8 ||
//                !userChangePasswordRequest.getNewPassword().matches(&quot;.*\\d.*&quot;) ||
//                !userChangePasswordRequest.getNewPassword().matches(&quot;.*[A-Z].*&quot;)) {
//            throw new InvalidRequestException(&quot;새 비밀번호는 8자 이상이어야 하고, 숫자와 대문자를 포함해야 합니다.&quot;);
//        } // DTO 에서 처리하도록 수정&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;darr;&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserChangePasswordRequest {

    @NotBlank(message = &quot;새로운 비밀번호를 입력해주세요.&quot;)
    @Size(min = 8, message = &quot;새 비밀번호는 최소 8자 이상이어야 합니다.&quot;) // 비밀번호 길이 체크
    @Pattern(regexp = &quot;.*\\d.*&quot;, message = &quot;비밀번호는 숫자를 포함해야 합니다.&quot;)
    @Pattern(regexp = &quot;.*[A-Z]*&quot;, message = &quot;비밀번호는 대문자를 포함해야 합니다.&quot;) // 숫자와 대문자 포함
    private String oldPassword;

    @NotBlank(message = &quot;기존 비밀번호를 입력해주세요.&quot;)
    private String newPassword;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ LV 2. N+1 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 수정 (@EntityGraph 는 Fetch Join 의 간편 버전인것을 배움)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public interface TodoRepository extends JpaRepository&amp;lt;Todo, Long&amp;gt; {

    // @EntityGraph 는 FETCH JOIN 의 간편 버전

//    @Query(&quot;SELECT t FROM Todo t LEFT JOIN FETCH t.user u ORDER BY t.modifiedAt DESC&quot;)
    @EntityGraph(attributePaths = {&quot;user&quot;})
    Page&amp;lt;Todo&amp;gt; findAllByOrderByModifiedAtDesc(Pageable pageable);

//    @Query(&quot;SELECT t FROM Todo t &quot; +
//            &quot;LEFT JOIN FETCH t.user &quot; +
//            &quot;WHERE t.id = :todoId&quot;)
    @EntityGraph(attributePaths = {&quot;user&quot;}) // 기존 페치 조인을 위한 JPQL 퀴리를 짜지 않고, @EntityGraph 를 활용하여 페치 조인을 진행
    Optional&amp;lt;Todo&amp;gt; findById(@Param(&quot;todoId&quot;) Long todoId);

    int countById(Long todoId);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ LV 3. 테스트 코드 연습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;● 예상대로 성공하는지에 대한 케이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ■ 수정 (rawPassword 와 encodedPassword 의 인자 순서 변경)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;@ExtendWith(SpringExtension.class)
class PasswordEncoderTest {

    @InjectMocks // 테스트 대상 객체
    private PasswordEncoder passwordEncoder;

    @Test
    void matches_메서드가_정상적으로_동작한다() {
        // given
        String rawPassword = &quot;testPassword&quot;;
        String encodedPassword = passwordEncoder.encode(rawPassword);

        // when
        boolean matches = passwordEncoder.matches(rawPassword, encodedPassword); // 인자 순서 변경
        // 원본 비밀번호를 암호화한 후 기존 암호화 된 값을 비교하기 때문

        // then
        assertTrue(matches);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;● 예상대로 예외처리 하는지에 대한 케이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ Case 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;■ 수정 (코드와 메서드명 변경)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;d&quot;&gt;&lt;code&gt;@Test
public void manager_목록_조회_시_Todo가_없다면_InvalidRequestException_을_던진다() { // 메서드명 변경
    // given
    long todoId = 1L;
    given(todoRepository.findById(todoId)).willReturn(Optional.empty());

    // when &amp;amp; then
    InvalidRequestException exception = assertThrows(InvalidRequestException.class,
            () -&amp;gt; managerService.getManagers(todoId),
            &quot;Manager not found&quot;
        );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ Case 2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;■ 수정 (CommentService 에 saveComment 가 InvalidRequestException으로 던지므로 맞게 수정)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Test
public void comment_등록_중_할일을_찾지_못해_에러가_발생한다() {
    // given
    long todoId = 1;
    CommentSaveRequest request = new CommentSaveRequest(&quot;contents&quot;);
    AuthUser authUser = new AuthUser(1L, &quot;email&quot;, UserRole.USER);

    given(todoRepository.findById(anyLong())).willReturn(Optional.empty());

    // when
    Exception exception = assertThrows(InvalidRequestException.class, () -&amp;gt; {
        commentService.saveComment(authUser, todoId, request);
    });

    // then
    assertEquals(&quot;Todo not found&quot;, exception.getMessage());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ Case 3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;■ 수정 (getUser 가 null 일 경우 추가)&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;@Transactional
public ManagerSaveResponse saveManager(AuthUser authUser, long todoId, ManagerSaveRequest managerSaveRequest) {
    // 일정을 만든 유저
    User user = User.fromAuthUser(authUser);
    Todo todo = todoRepository.findById(todoId)
            .orElseThrow(() -&amp;gt; new InvalidRequestException(&quot;Todo not found&quot;));

    if (todo.getUser() == null) { // getUser 가 null 일 경우 추가
        throw new InvalidRequestException(&quot;담당자를 등록하려고 하는 유저가 일정을 만든 유저가 유효하지 않습니다.&quot;);
    }

    if (!ObjectUtils.nullSafeEquals(user.getId(), todo.getUser().getId())) {
        throw new InvalidRequestException(&quot;담당자를 등록하려고 하는 유저가 일정을 만든 유저가 유효하지 않습니다.&quot;);
    }

    User managerUser = userRepository.findById(managerSaveRequest.getManagerUserId())
            .orElseThrow(() -&amp;gt; new InvalidRequestException(&quot;등록하려고 하는 담당자 유저가 존재하지 않습니다.&quot;));

    if (ObjectUtils.nullSafeEquals(user.getId(), managerUser.getId())) {
        throw new InvalidRequestException(&quot;일정 작성자는 본인을 담당자로 등록할 수 없습니다.&quot;);
    }

    Manager newManagerUser = new Manager(managerUser, todo);
    Manager savedManagerUser = managerRepository.save(newManagerUser);

    return new ManagerSaveResponse(
            savedManagerUser.getId(),
            new UserResponse(managerUser.getId(), managerUser.getEmail())
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이번 과제는 큰 어려움 없이 기존 진행됫던 강의와 세션들만 들으면 어렵지 않게 필수 단계를 해결할 수 있었다. 하지만 처음 세션을 수강할때 들었던 내용도 막상 과제를 진행할땐 도저히 이해가 안가, 세션과 강의를 수차례 돌려보기 일수였다. 이번 주차에선 과제를 진행하며 막힐때마다 세션을 돌려보느라 허송새월을 한 것 같다. 하지만 결국 이렇게 필수 과제를 완성한 것에 적지않은 성취감 또한 느껴진다. 느려도 이렇게 천천히 조금씩 배워나가는게 요즘 나름 즐겁게 느껴진다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/46</guid>
      <comments>https://cej4297.tistory.com/46#entry46comment</comments>
      <pubDate>Thu, 27 Feb 2025 02:32:28 +0900</pubDate>
    </item>
    <item>
      <title>TIL 2025/02/12</title>
      <link>https://cej4297.tistory.com/45</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 이번주의 새로 발제된 과제 '일정 관리 앱 Develop' 의 작성을 완료했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ API 명세서 작성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Postman(포스트맨)을 활용하여 드디어 API 제작에 성공했다. 할줄 아는게 늘었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ &lt;a href=&quot;https://documenter.getpostman.com/view/41325087/2sAYXCidA7&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://documenter.getpostman.com/view/41325087/2sAYXCidA7&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ ERD 작성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8qcZt/btsMfEX3vmi/JBG8tgYDZcyBIkNNKbKrH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8qcZt/btsMfEX3vmi/JBG8tgYDZcyBIkNNKbKrH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8qcZt/btsMfEX3vmi/JBG8tgYDZcyBIkNNKbKrH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8qcZt%2FbtsMfEX3vmi%2FJBG8tgYDZcyBIkNNKbKrH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;628&quot; height=&quot;288&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 작성 툴 (SqlDBM) &amp;rarr; &lt;a href=&quot;https://sqldbm.com/Home/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sqldbm.com/Home/&amp;nbsp;&lt;/a&gt; (바로가기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ 깔끔하니 보기좋은 툴인것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 작성 코드 바로가기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&amp;nbsp;&lt;a href=&quot;https://github.com/Roloya28/Schedule&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Roloya28/Schedule&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 트러블 슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스케쥴 생성시 오류 발생&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제점 : 코드 작성 후, 포스트맨 찔러보기 중 계정생성, 계정 조회 등은 정상 작동했으나, 스케쥴 생성에서 오류 발생&lt;/li&gt;
&lt;li&gt;검토 : 처음부터 코드를 하나부터 재 확인해봄, 스케쥴 생성 클래스부터 모든 연관관계를 확인해봤으나, 큰 문제가 없다는게 결론, 여기서 시간을 상당히 많이 뺏겻다.&lt;/li&gt;
&lt;li&gt;해결 : 처음으로 돌아가 최초의 작성된 코드부터 확인 진행 &amp;rarr; 처음 테이블 생성할때 불필요한 요소가 포함된것 확인 후 삭제 &amp;rarr; Postman 찔러보기 결과 성공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ※ 아니 테이블에 컬럼 하나 잘못들어갔다고 이게 안되네;; 이래서 선 CRUD 와 ERD 작성이 중요하구나 느낌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;(근데 먼저하고 한건데 실수한거니 내탓 ㅇㅈ. 몸이 고생함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이번에 진행된 과제에서는 바보같은 실수 외에 큰 문제는 발생하지 않아 순탄한 진행을 할수 있었다.. Spring 숙련 3주차의 마지막 강의 실습이 과제와 너무 비슷해서 솔직히 몇몇 명칭을 바꿔 작성한것 말고는 한게 별로 없는것 같지만서도 그래도 이제는 조금씩 스프링이 뭔지 느껴지는 단계엔 들어온것 같다. 튜터님에 말씀처럼 계속해서 때려박다보면 머리가 안되면 몸이 알아서 해주지 않을까.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/45</guid>
      <comments>https://cej4297.tistory.com/45#entry45comment</comments>
      <pubDate>Thu, 13 Feb 2025 00:53:25 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2025/02/03</title>
      <link>https://cej4297.tistory.com/44</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 진행중인 '일정 관리 앱' 만들기 과제의 제출이 내일까지라, 오늘은 온종일 과제에 집중했다. 원래 목표로는 도전 단계까지 모두 진행해보는것을 노렸으나, 아직 배움이 많이 부족하여 필수 단계를 간신히 진행하고있는 상황이 슬프다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ '일정관리 앱' 필수 단계 (완료)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 작성 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ CalendarController&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/api&quot;)
public class CalendarController {

    @Autowired
    private CalendarService calendarService;

    @PostMapping(&quot;/calendars&quot;)
    public void createCalendar(@RequestBody CalendarModel calendarModel) {
        calendarService.createCalendar(calendarModel);
    }

    @GetMapping(&quot;/lists&quot;)
    public List&amp;lt;CalendarModel&amp;gt; getAllCalendars(@RequestParam(required = false) String author,
                                               @RequestParam(required = false) String updateDate) {
        return calendarService.getAllCalendars(author, updateDate);
    }

    @GetMapping(&quot;/lists/{id}&quot;)
    public CalendarModel getCalendarById(@PathVariable Long id) {
        return calendarService.getCalendarById(id);
    }

    @PutMapping(&quot;/{id}&quot;)
    public String updateCalendar(@PathVariable Long id, @RequestBody CalendarDto calendarDto) {
        try {
            calendarService.updateCalendar(id, calendarDto);
            return &quot;수정완료&quot;;
        } catch (IllegalArgumentException e) {
            return e.getMessage();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ CalendarDto&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Getter
@Setter
public class CalendarDto {

    private String todolist;
    private String author;
    private String password;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ CalendarModel&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CalendarModel {

    private Long id;
    private String author;
    private String todolist;
    private String password;
    private LocalDateTime createDate;
    private LocalDateTime updateDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ CalendarRepository&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Repository
public class CalendarRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int createCalendar(CalendarModel calendarModel) {
        String sql = &quot;insert into calendar (author, todolist, password, createDate, updateDate) values(?,?,?,?,?)&quot;;
        return jdbcTemplate.update(sql, calendarModel.getAuthor(), calendarModel.getTodolist(), calendarModel.getPassword(), calendarModel.getCreateDate(), calendarModel.getUpdateDate());
    }

    public List&amp;lt;CalendarModel&amp;gt; getAllCalendars(String author, String updateDate) {
        StringBuilder sql = new StringBuilder(&quot;select * from calendar where 1=1&quot;);
        List&amp;lt;Object&amp;gt; params = new ArrayList&amp;lt;&amp;gt;();

        if (author != null &amp;amp;&amp;amp; !author.isEmpty()) {
            sql.append(&quot; and author = ?&quot;);
            params.add(author);
        }

        if (updateDate != null &amp;amp;&amp;amp; !updateDate.isEmpty()) {
            sql.append(&quot; and date(updateDate) = ?&quot;);
            params.add(Date.valueOf(updateDate));
        }

        sql.append(&quot; order by updateDate desc&quot;);

        return jdbcTemplate.query(sql.toString(), params.toArray(), new BeanPropertyRowMapper&amp;lt;&amp;gt;(CalendarModel.class));
    }

    public CalendarModel getCalendarById(Long id) {
        String sql = &quot;select * from calendar where id = ?&quot;;
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper&amp;lt;&amp;gt;(CalendarModel.class), id);
    }

    public void updateCalendar(CalendarModel calendarModel) {
        String sql = &quot;update calendar set todolist = ?, author = ?, updateDate = ?, where id = ?&quot;;
        jdbcTemplate.update(sql, calendarModel.getTodolist(), calendarModel.getAuthor(), calendarModel.getUpdateDate(), calendarModel.getId());
    }

    public void deleteCalendar(Long id) {
        String sql = &quot;delete from calendar where id = ?&quot;;
        jdbcTemplate.update(sql, id);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ CalendarService&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Service
public class CalendarService {

    @Autowired
    private CalendarRepository calendarRepository;

    // 일정 생성
    public void createCalendar(CalendarModel calendarModel) {

        LocalDateTime now = LocalDateTime.now();

        calendarModel.setCreateDate(now);
        calendarModel.setUpdateDate(now);

        calendarRepository.createCalendar(calendarModel);
    }

    // 전체 일정 조회
    public List&amp;lt;CalendarModel&amp;gt; getAllCalendars(String author, String updateDate) {
        return calendarRepository.getAllCalendars(author, updateDate);
    }

    // 단건 조회
    public CalendarModel getCalendarById(Long id) {
        return calendarRepository.getCalendarById(id);
    }

    // 수정
    public void updateCalendar(Long id, CalendarDto calendarDto) {

        LocalDateTime now = LocalDateTime.now();
        CalendarModel existingCalendar;

        try {
            existingCalendar = calendarRepository.getCalendarById(id);
        } catch (Exception e) {
            throw new IllegalArgumentException(&quot;해당 일정을 찾을 수 없습니다.&quot;, e);
        }

        if (!existingCalendar.getPassword().equals(calendarDto.getPassword())) {
            throw new IllegalArgumentException(&quot;비밀번호가 일치하지 않습니다.&quot;);
        }

        existingCalendar.setTodolist(calendarDto.getTodolist());
        existingCalendar.setAuthor(calendarDto.getAuthor());
        existingCalendar.setUpdateDate(now);

        calendarRepository.updateCalendar(existingCalendar);
    }

    // 삭제
    public void deleteCalendar(Long id, String password) {
        CalendarModel existingCalendar;

        try {
            existingCalendar = calendarRepository.getCalendarById(id);
        } catch (Exception e) {
            throw new IllegalArgumentException(&quot;해당 일정을 찾을 수 없습니다.&quot;, e);
        }

        if (!existingCalendar.getPassword().equals(password)) {
            throw new IllegalArgumentException(&quot;비밀번호가 일치하지 않습니다.&quot;);
        }

        calendarRepository.deleteCalendar(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 트러블슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Lombok 패키지 추가 안함 (해결 完)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ 처음 프로젝트 생성時, 롬복 패키지를 추가 안했는지, 프로그램이 인식을 하지 못하는 문제가 발생하여, 해당 문제 해결방법을 인터넷등에서 찾아본 결과, 직접 build.gradle 파일 內 에서 추가하여 해결 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 데이터베이스 연결 오류 (해결 完)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;└ 현재 과제를 완료하고 마지막 확인도중, 프로그램 실행 時, 데이터베이스 연결이 안되는 오류가 발생하고 있다. 여러 방면으로 해결방법을 물색해봤고, 결국 처음으로 돌아가 처음부터 다시 세팅을 해보는 식으로 문제를 해결해보고자 접근해봤다. 결과적으로 새로 시작한 프로젝트에선 데이터베이스 연동이 정상적으로 작동했으나, 그럴듯한 해결방법이 뭐였는지는 정확하진 않으나, schema 설정이 제대로 되지 않았던게 아닌가 하는 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 처음으로 스프링 과제를 진행하며 여러가지 문제에 막히는 경험들을 해봤다. 이 경험을 기반으로 다음번엔 좀더 수월히 스프링을 운용할수 있을 밑거름이 될거라 긍정적인 마인드로 앞으로도 화이팅해보자.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/44</guid>
      <comments>https://cej4297.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 3 Feb 2025 23:53:51 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2025/01/23</title>
      <link>https://cej4297.tistory.com/43</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘부로 Spring 5기의 신규 과제가 발제되었다. 새롭게 배우기 시작한 Spring 을 활용하여 일정관리 앱을 만들어 보는 과제이나, 아직 Spring에 대해 공부가 부족한 관계로 강의와 과제를 동시에 진행하느라, 많은 단계를 진행하진 못하고, 가까스로 LV0단계를 구성할수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ '일정관리 앱' 필수 LV0 단계&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ API 명세서 작성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q1HWp/btsLZveAcM2/cf6EkH82gAnkHjcNBcKPu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q1HWp/btsLZveAcM2/cf6EkH82gAnkHjcNBcKPu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q1HWp/btsLZveAcM2/cf6EkH82gAnkHjcNBcKPu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq1HWp%2FbtsLZveAcM2%2Fcf6EkH82gAnkHjcNBcKPu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;907&quot; height=&quot;377&quot; data-origin-width=&quot;907&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ ERD 작성 (ERDCloud 사용)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bfi9O/btsLYpM0wCm/5CeetKivaszIIHeD7nt1k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bfi9O/btsLYpM0wCm/5CeetKivaszIIHeD7nt1k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bfi9O/btsLYpM0wCm/5CeetKivaszIIHeD7nt1k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBfi9O%2FbtsLYpM0wCm%2F5CeetKivaszIIHeD7nt1k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;614&quot; height=&quot;246&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 데이터베이스 구축 (Mysql)&lt;/p&gt;
&lt;div style=&quot;background-color: #1a2426; color: #afb9c3;&quot;&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;CREATE TABLE calendar (
    id INT NOT NULL AUTO_INCREMENT,
    todo VARCHAR(100) NULL COMMENT '스케쥴',
    author VARCHAR(100) NOT NULL COMMENT '작성자',
    passwrod VARCHAR(50) NOT NULL COMMENT '비밀번호',
    date DATETIME NULL,
    CONSTRAINT CALENDAR_PK PRIMARY KEY(id)
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 다이어그램 체크&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkxQIh/btsLXXjnJHz/GoeiTrIp930e60i9PzzLM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkxQIh/btsLXXjnJHz/GoeiTrIp930e60i9PzzLM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkxQIh/btsLXXjnJHz/GoeiTrIp930e60i9PzzLM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkxQIh%2FbtsLXXjnJHz%2FGoeiTrIp930e60i9PzzLM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;363&quot; height=&quot;246&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 트러블슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- POSTMAN 을 활용하여 API 작성중 사용법 숙지에 큰 어려움이 있었으나, 빠른 포기로 문제 해결. (수기작성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 처음 API 명세서를 작성할때, 추천 Tool인 'POSTMAN' 을 이용하여 API 작성을 시도해 보았으나, 여러 경로에서 사용법을 찾아봐도 영 익숙해지질 않아 결국 포기하고 수기 작성을 하였다... 하루 대부분을 사용법 숙지에 쏟아부은거 치곤 성과가 하나도 없다고 할수 있다.(시간 날렷네;;; 나중에 다시 배워야지).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이후 ERD 작성법을 공부하며 동시에 내게 필요한 ERD 작성을 완료한 후, 본격적인 sql 데이터베이스 구축에 들어갔다. 확실히 우선적으로 ERD 작성과 막히는 부분이 있을경우 다시 강의로 돌아가 차근차근 따라가보니 수월하게 진행할수 있었다. 가능하다면 이번주가 끝나기 전에 필수 과정을 마치고 싶으니, 부지런히 진행해보자&lt;/p&gt;</description>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/43</guid>
      <comments>https://cej4297.tistory.com/43#entry43comment</comments>
      <pubDate>Thu, 23 Jan 2025 21:32:06 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2025/01/17</title>
      <link>https://cej4297.tistory.com/42</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 개인과제 '키오스크 만들기' LV4 ~ LV5를 진행 및 최종 검토를 진행하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 키오스크 만들기 LV4 ~ 5&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 객체 지향 설계를 적용해 음식 메뉴와 주문 내역을 클래스 기반으로 관리 및 캡슐화 진행하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ Kiosk 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public class Kiosk {

    // 객체 생성 및 메뉴 목록 초기화
    private List&amp;lt;Menu&amp;gt; menus;

    public Kiosk(List&amp;lt;Menu&amp;gt; menus) {
        this.menus = menus;
    }

    // Getter
    public List&amp;lt;Menu&amp;gt; getMenu() {
        return menus;
    }

    // SettER
    public void setMenu(List&amp;lt;Menu&amp;gt; menus) {
        this.menus = menus;
    }

    // 키오스크 프로그램 시작
    public void start() {
        Scanner sc = new Scanner(System.in);

        // 반복문 while 을 이용한 리스트에 메뉴를 차례대로 출력 (앞에 번호 부여 및 출력시 상품명, 가격, 제품설명 출력)
        while (true) {
            System.out.println(&quot;[ MAIN MENU ]&quot;);
            for (int i = 0; i &amp;lt; menus.size(); i++) {
                System.out.printf(&quot;%d. %s\n&quot;, i + 1, menus.get(i).getCategory());
            }
            System.out.println(&quot;0. 종료       | 종료&quot;);

            System.out.print(&quot;메뉴를 선택하세요: &quot;);
            String input = sc.nextLine();

            // 종료 조건
            if (input.equals(&quot;0&quot;)) {
                System.out.println(&quot;프로그램을 종료합니다.&quot;);
                break;
            }

            // 메뉴 선택 처리
            try {
                int choice = Integer.parseInt(input); // 입력 값을 정수로 변환
                if (choice &amp;gt; 0 &amp;amp;&amp;amp; choice &amp;lt;= menus.size()) {
                    // 선택한 메뉴 출력
                    Menu selectedMenu = menus.get(choice - 1);
                    menuSelection(sc, selectedMenu);
                } else { // 메뉴 번호가 범위를 벗어난 경우
                    System.out.println(&quot;유효하지 않은 선택입니다. 다시 입력해주세요.&quot;);
                }
            } catch (NumberFormatException e) { // 입력값이 숫자가 아닌 경우
                System.out.println(&quot;잘못된 입력입니다. 숫자를 입력해주세요.&quot;);
            }
        }
        sc.close();
    }

    // 입력받은 값의 메뉴항목 처리
    private void menuSelection(Scanner sc, Menu selectedMenu) {
        while (true) {
            selectedMenu.displayMenuItems();

            System.out.print(&quot;메뉴를 선택하세요: &quot;);
            String input = sc.nextLine();

            // 0을 입력시 다시 초기 화면으로 돌아감
            if (input.equals(&quot;0&quot;)) {
                System.out.println(&quot;메인 메뉴로 돌아갑니다.&quot;);
                break;
            }

            // 입력 처리
            try {
                int choice = Integer.parseInt(input); // 입력 값을 정수로 변환
                List&amp;lt;MenuItem&amp;gt; items = selectedMenu.getMenuItems();
                if (choice &amp;gt; 0 &amp;amp;&amp;amp; choice &amp;lt;= items.size()) { // 입력한 값이 유효한 범위 내에 있는지 확인하고
                    MenuItem selectedItem = items.get(choice - 1); // 값이 맞다면 해당 번호에 맞는 메뉴를 출력 (items 리스트에서 -1 번째 항목을 가져옴 - 인덱스 0 데이터)
                    System.out.printf(&quot;선택한 메뉴: %s | W %.1f | %s\n&quot;, selectedItem.getName(), selectedItem.getPrice(), selectedItem.getProductInfo());
                return; // 해당 메서드 종료
                } else { // 메뉴 번호가 범위를 벗어난 경우
                    System.out.println(&quot;유효하지 않은 선택입니다. 다시 입력해주세요.&quot;);
                }
            } catch (NumberFormatException e) { // 입력값이 숫자가 아닌 경우
                System.out.println(&quot;잘못된 입력입니다. 숫자를 입력해주세요.&quot;);
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ Menu 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Menu {
    private String category;
    private final List menuItems;

    public Menu(String category) {
        this.category = category;
        this.menuItems = new ArrayList();
    }

    // Getter
    public String getCategory() {
        return category;
    }

    public List&amp;lt;MenuItem&amp;gt; getMenuItems() {
        return menuItems;
    }

    // Setter
    public void setCategory(String category) {
        this.category = category;
    }

    // 메뉴 항목 추가
    public void addMenuItem(MenuItem item) {
        menuItems.add(item);
    }

    // 메뉴 항목 출력
    public void displayMenuItems() {
        System.out.printf(&quot;[ %s MENU ]\n&quot;, category); // 선택별로 ~~ 메뉴인지 표시
        for (int i = 0; i &amp;lt; menuItems.size(); i++) { // 번호 부여
            MenuItem item = (MenuItem) menuItems.get(i);
            // 번호, 음식이름, 가격, 상품정보 차례대로 출력
            System.out.printf(&quot;%d. %-15s | W %.1f | %s\n&quot;, i + 1, item.getName(), item.getPrice(), item.getProductInfo());
        }
        System.out.println(&quot;0. 뒤로가기&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ MenuItem 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class MenuItem {
    private String name;
    private double price;
    private String productInfo;

    public MenuItem(String name, double price, String productInfo) {
        this.name = name;
        this.price = price;
        this.productInfo = productInfo;
    }

    // Getter
    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public String getProductInfo() {
        return productInfo;
    }

    // Setter
    public void setName(String name) {
        this.name = name;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void setProductInfo(String productInfo) {
        this.productInfo = productInfo;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ Main 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {

        // 메뉴별로 초기화 진행
        Menu burgers = new Menu(&quot;Burgers&quot;); // 버거 메뉴 초기화
        burgers.addMenuItem(new MenuItem(&quot;ShackBurger&quot;, 6.9, &quot;토마토, 양상추, 쉑소스가 토핑된 치즈버거&quot;));
        burgers.addMenuItem(new MenuItem(&quot;SmokeShack&quot;, 8.9, &quot;베이컨, 체리 페퍼에 쉑솟브가 토핑된 치즈버거&quot;));
        burgers.addMenuItem(new MenuItem(&quot;Cheeseburger&quot;, 6.9, &quot;포테이토 번과 비프패티, 치즈가 토핑된 치즈버거&quot;));
        burgers.addMenuItem(new MenuItem(&quot;Hamburger&quot;, 5.4, &quot;비프패티를 기반으로 야채가 들어간 기본버거&quot;));

        Menu drinks = new Menu(&quot;Drinks&quot;); // 쥬스 메뉴 초기화
        drinks.addMenuItem(new MenuItem(&quot;Coke&quot;, 2.0, &quot;시원한 코카콜라&quot;));
        drinks.addMenuItem(new MenuItem(&quot;Sprite&quot;, 2.0, &quot;상쾌한 스프라이트&quot;));
        drinks.addMenuItem(new MenuItem(&quot;Water&quot;, 1.5, &quot;깨끗한 생수&quot;));

        Menu desserts = new Menu(&quot;Desserts&quot;); // 디저트 메뉴 초기화
        desserts.addMenuItem(new MenuItem(&quot;Ice Cream&quot;, 3.5, &quot;바닐라 이이스크림&quot;));
        desserts.addMenuItem(new MenuItem(&quot;Brownie&quot;, 4.0, &quot;진한 초콜릿 브라우니&quot;));

        // 전체 메뉴로 묶음
        List&amp;lt;Menu&amp;gt; allMenu = new ArrayList&amp;lt;&amp;gt;();
        allMenu.add(burgers);
        allMenu.add(drinks);
        allMenu.add(desserts);

        // 키오스크 객체 생성 및 실행 , 프로그램 시작
        Kiosk kiosk = new Kiosk(allMenu);
        kiosk.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 트러블슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷문제점 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- LV4~5 진행 中, 클래스 호출에서 문제가 발생하여, 클래스가 제대로 호출되지 않는 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;(해당 클래스의 정보가 제대로 연동되지 못하고 계속 없는 해당 클래스를 생성하라는 오류 메세지가 뜸)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 이유 분석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 분명히 해당 클래스 및 필요한 메서드가 정의되어 있는지 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;□ Getter, Setter 설정 중 실수는 없엇는가? O&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;□ 단순한 타이핑 실수는 아닌가? X&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;□ 객체 생성에 문제는 없는가? O (문제 발견)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;└ private List menus;(문제점) &amp;rarr; private List&amp;lt;Menu&amp;gt; menus;(해결) - 선언이 잘못되었네...?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ Java 문법 종합반 3주차 제 정독 中 문제점 발견...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 해결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 장장 하루를 넘게 코드를 처음부터 뜯어 읽어보며 문제가 된 부분을 몇번씩이나 지나쳣지만, 문제점을 인지 못하고 지나쳤다는게 정말 황당한 경험이다. 자바에 기초인 객체 생성에서 단순한 실수로 잡아먹은 시간이 어이가 없을 지경이다. 이게 다 부족한 기본 지식에서 나오는 단순한 실수지 않을까.. 멍청하면 몸이 고생한다는 말이 딱 들어맞았다.... 허무해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이번 프로젝트를 진행하며, 자신의 기초가 얼마나 부족한지 여실히 깨닫는 시간이 되었다. 전주에 이미 계산기 만들기 과제를 하며 충분히 기본을 쌓아둿다 생각했으나, 다시금 새로운 프로젝트를 시작하니, 시작점부터 막히는 자신을 볼수 있었다...(계산기 과제야 고마워... 다 너 배낀거같아) 다음 프로젝트 이전까지 시간이 남는다면 자바에 기초를 더욱 다듬을수 있는 시간을 가져보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/42</guid>
      <comments>https://cej4297.tistory.com/42#entry42comment</comments>
      <pubDate>Fri, 17 Jan 2025 20:47:51 +0900</pubDate>
    </item>
    <item>
      <title>TIL 2024/01/09</title>
      <link>https://cej4297.tistory.com/41</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 3주차 강의 이해가 안되는 부분 복습과 '계산기 만들기' 프로젝트의 2단계 부분 마무리를 지었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 계산기 만들기 LV2 - 마무리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어제의 연장선으로 오늘은 계산기 만들기 프로젝트의 2단계 부분의 코드를 좀더 보완하고 깔끔하게 작동시키기 위해 어느 부분을 수정하면 좋을까로 코드를 하루종일 쳐다보고 있었던것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로는 필요없는 일부 코드를 삭제, 개선 후 프로젝트 LV2를 마무리하고, 깃허브 업로드를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 개선된 switch 문 (case '+': result = firstNo + secondNo; break 을 case '+' -&amp;gt; firstNo + secondNo; 로 개선된것을 볼수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public int calculate(int firstNo, int secondNo, char fbo) {
    int result = switch (fbo) {
        case '+' -&amp;gt; firstNo + secondNo;
        case '-' -&amp;gt; firstNo - secondNo;
        case '*' -&amp;gt; firstNo * secondNo;
        case '/' -&amp;gt; firstNo / secondNo;
        default -&amp;gt; 0;
    };&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ &lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;Calculator 클래스에 저장된 연산 결과들 중 가장 먼저 저장된 데이터를 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void deleteFirstSave() {
    if (!results.isEmpty()) {
        results.remove(0); // 첫 세이브값 삭제
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이후 출력부분에서 데이터 삭제 메서드 구현&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;System.out.println(&quot;가장 먼저 저장한 값을 삭제 하시겠습니까? (delete 입력시 삭제 or 아무키 입력으로 continue)&quot;);
String delete = sc.next();
if (delete.equalsIgnoreCase(&quot;delete&quot;)) { // equalIgnoreCase = 대소문자 구분없이 입력값 인식
    if (!calculator.getResults().isEmpty()) {
        calculator.deleteFirstSave(); // 첫 세이브값 삭제
        System.out.println(&quot;삭제 완료.&quot;); //&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 프로젝트 LV2 마무리 코드&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public class App {

    public static void main(String[] args) {
        System.out.println(&quot;Hello, Calculator!&quot;);
        Scanner sc = new Scanner(System.in);
        Calculator calculator = new Calculator(); // Calculator 인스턴스 생성

        while (true) {
            // 첫번째 값 입력받기
            System.out.println(&quot;첫 번째 숫자를 입력하세요: &quot;);
            int firstNo = sc.nextInt();
            // 사칙연산 입력받기
            System.out.println(&quot;연산자를 입력하세요: [+,-,*,/]&quot;);
            char fbo = sc.next().charAt(0);
            // 두번째 값 입력받기
            System.out.println(&quot;두 번째 숫자를 입력하세요: &quot;);
            int secondNo = sc.nextInt();

            // 결과값 출력
            int result = calculator.calculate(firstNo, secondNo, fbo);
            System.out.println(&quot;결과: &quot; + firstNo + &quot; &quot; + fbo + &quot; &quot; + secondNo + &quot; = &quot; + result);

            // 결과값 저장, 현재 저장된 값 출력 및 삭제 여부 출력
            System.out.println(&quot;현재 저장된 결과 : &quot; + calculator.getResults().size() + &quot; &quot; + calculator.getResults());

            System.out.println(&quot;가장 먼저 저장한 값을 삭제 하시겠습니까? (delete 입력시 삭제 or 아무키 입력으로 continue)&quot;);
            String delete = sc.next();
            if (delete.equalsIgnoreCase(&quot;delete&quot;)) { // equalIgnoreCase = 대소문자 구분없이 입력값 인식
                if (!calculator.getResults().isEmpty()) {
                    calculator.deleteFirstSave(); // 첫 세이브값 삭제
                    System.out.println(&quot;삭제 완료.&quot;); //
                }
            }

            System.out.println(&quot;계속 계산하시겠습니까? (exit 입력시 종료 or 아무키 입력으로 continue)&quot;);
            String exit = sc.next();
            if (exit.equalsIgnoreCase(&quot;exit&quot;)) {
                break;
            }
        }
        // 종료시 마지막 저장된 값 차례대로 출력
        System.out.println(&quot;최종 저장 결과: &quot;);
        for (int res : calculator.getResults()) {
            System.out.println(res);
        }
        sc.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Calculator {
    private List&amp;lt;Integer&amp;gt; results;

    public Calculator() {
        this.results = new ArrayList&amp;lt;&amp;gt;(); // 연산 결과를 저장하는 컬렉션 타입 필드 선언 및 생성
    }

    // 사칙연산 수행 메서드
    public int calculate(int firstNo, int secondNo, char fbo) {
        int result = switch (fbo) {
            case '+' -&amp;gt; firstNo + secondNo;
            case '-' -&amp;gt; firstNo - secondNo;
            case '*' -&amp;gt; firstNo * secondNo;
            case '/' -&amp;gt; firstNo / secondNo;
            default -&amp;gt; 0;
        };

        addResult(result);
        return result;
    }

    // Getter 메서드 - 캡슐화
    public List&amp;lt;Integer&amp;gt; getResults() { // 계산 결과를 저장
        return new ArrayList&amp;lt;&amp;gt;(results);
    }

    // Setter 메서드 - 캡슐화
    public void setResults(List&amp;lt;Integer&amp;gt; newResults) {
        this.results = new ArrayList&amp;lt;&amp;gt;(newResults);
    }

    public void addResult(int result) {
        results.add(result);
    }

    public void deleteFirstSave() {
        if (!results.isEmpty()) {
            results.remove(0); // 첫 세이브값 삭제
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마무리 회고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이번 프로젝트를 레벨2까지 마무리하며 어려웠던 점이라고 한다면, 물론 자신있게 처음부터 모든부분이 다 어려웠다고 할 수 있을거 같다. 하지만 그렇다고 힘들었다고는 생각하지 않는다. 어려운 부분이 나올때마다. 계속해서 복습 및 검색으로 해당 메서드는 어찌 작동하는지에 대해 더 자세히 들여다 볼수 있었던 시간이라고 생각한다. 처음 프로젝트를 시작했을땐 java에 e도 모르던 내가 그래도 기초를 갈고닦을수있던 좋은 경험이었다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/41</guid>
      <comments>https://cej4297.tistory.com/41#entry41comment</comments>
      <pubDate>Fri, 10 Jan 2025 11:26:27 +0900</pubDate>
    </item>
    <item>
      <title>TIL 2025/01/08</title>
      <link>https://cej4297.tistory.com/40</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 Java 3주차 강의와 계속 병행하던 '계산기 만들기' 프로젝트를 Lv 2단계 막바지까지 코드 구현을 완료하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 계산기 만들기 LV2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 계산기 만들기 LV2는 기존 진행한 LV1 에 비해 많은 어려움을 겪었다. 기존 LV1에선 단순히 입력받은 값을 조건문 (if)문을 사용해, 사칙연산 기호별 계산을 진행하면 되는거였다면, LV2는 별도 컬렉션 타입 필드를 가진 클래스를 활용하여, 결과값을 구현하고 연산 결과를 저장 &amp;amp; 불러오는 기능까지 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 클래스 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆ 사칙연산을 수행 후, 결과값 반환 메서드 구현 &amp;amp; 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 신규 Calculator 생성 후, 조건문 (switch) 사용하여&amp;nbsp; 사칙연산 수행 및 값 반환하는 메서드 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (기존 if문 &amp;rarr; switch 문으로 수정 진행 - TIL 2025/01/03)&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Calculator {
    private List&amp;lt;Integer&amp;gt; results;

    public Calculator() {
        results = new ArrayList&amp;lt;&amp;gt;(); // 연산 결과를 저장하는 컬렉션 타입 필드 선언 및 생성
    }

    // 사칙연산 수행 메서드
    public int calculate(int firstNo, int SecondNo, char fbo) {
        int result = 0;
        switch (fbo) {
            case '+':
                result = firstNo + SecondNo;
                break;
            case '-':
                result = firstNo - SecondNo;
                break;
            case '*':
                result = firstNo * SecondNo;
                break;
            case '/':
                result = firstNo / SecondNo;
                break;
        }

        results.add(result);
        return result;
    }

    public List&amp;lt;Integer&amp;gt; getResults() {
        return results;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆ App 클래스의 main 메서드에 Calculator 클래스가 활용될 수 있도록 수정 진행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (연산수행 역할은 Calculator 클래스가 담당 / 연산 결과도 Calculator 클래스의 연산 결과를 저장하는 필드에 저장)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;※ 별도로 예시에는 첫번째값, 두번째값 입력 후, 사칙연산 입력이었으나, 보기좋게 위치 변경 진행&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    System.out.println(&quot;Hello, Calculator!&quot;);
    Scanner sc = new Scanner(System.in);
    Calculator calculator = new Calculator(); // Calculator 인스턴스 생성

    while (true) {
        // 첫번째 값 입력받기
        System.out.println(&quot;첫 번째 숫자를 입력하세요: &quot;);
        int firstNo = sc.nextInt();
        // 사칙연산 입력받기
        System.out.println(&quot;사칙연산 기호를 입력하세요: &quot;);
        char fbo = sc.next().charAt(0);
        // 두번째 값 입력받기
        System.out.println(&quot;두 번째 숫자를 입력하세요: &quot;);
        int secondNo = sc.nextInt();

        int result = calculator.calculate(firstNo, secondNo, fbo);
        System.out.println(&quot;결과: &quot; + firstNo + &quot; &quot; + fbo + &quot; &quot; + secondNo + &quot; = &quot; + result); // 결과값 반환&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆ 연산 결과를 저장하고 있는 컬렉션 필드에 접근하지 못하도록 수정(캡슐화)&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Calculator {
    private List&amp;lt;Integer&amp;gt; results;

    public Calculator() {
        results = new ArrayList&amp;lt;&amp;gt;(); // 연산 결과를 저장하는 컬렉션 타입 필드 선언 및 생성
    }

    // 사칙연산 수행 메서드
    public int calculate(int firstNo, int SecondNo, char fbo) {
        int result = 0;
        switch (fbo) {
            case '+':
                result = firstNo + SecondNo;
                break;
            case '-':
                result = firstNo - SecondNo;
                break;
            case '*':
                result = firstNo * SecondNo;
                break;
            case '/':
                result = firstNo / SecondNo;
                break;
        }

        addResult(result);
        return result;
    }

    public List&amp;lt;Integer&amp;gt; getResults() { // 계산 결과를 저장
        return new ArrayList&amp;lt;&amp;gt;(results);
    }

    public void setResults(List&amp;lt;Integer&amp;gt; newResults) {
        this.results = new ArrayList&amp;lt;&amp;gt;(newResults);
    }

    public void addResult(int result) {
        results.add(result);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◆ Calculator 클래스에 저장된 연산 결과들 중 가장 먼저 저장된 데이터를 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 작업도중 에러 발생으로 수정 진행 中&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 트러블 슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 오전시간을 제외한 하루 대부분을 프로젝트 코드 작성에 쏟아 부었으나, 계산기를 불편함없이 좀더 활용적이게 작동시킬 방법이 없을까 고민하고 이런식으로 작동시키려면 어떻게 해야하지? 같은 물음이 꼬리에 꼬리를 물고 이어져, 아쉽게도 하루를 마감하기 전 LV2 완성을 하지 못하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 내가 짠 코드는 우선 각각 총 2개의 값을 내려받고 사칙연산을 입력받을시 계산이 진행되는데, 이후, 저장된 결과값을 삭제할 것인지, 아니면 계산으로 돌아갈 것인지의 선택지를 주는 방식의 코드 작성을 끝내지 못했다. 이것 말고도 번잡하게 여러 고민들이 있지만, 너무 난잡해지기에 우선적으로 내일은 위 과제를 먼저 해결해 보려 한다. 4주차 5주차 강의도 아직 못봣는데 너무 고민만 하고있는게 아닌지 모르겠다 ㅜㅜ...&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 배움이 얕아, 아직까지 내가 생각하는 방식의 코드를 짜는게 여간 쉬운일이 아니었다... 프로젝트 단계마다 이걸 적용해 보세요. 다음은 이걸 해보세요.. 하고 추가될때마다 기본 반나절은 잡고 진행하고 있는것 같다. 다른분들은 이미 후딱 해치우고 강의도 다 들었던데... 아직 3주차도 제대로 이해못하고 진도를 따라가는데 급급한 자신이 한심하다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/40</guid>
      <comments>https://cej4297.tistory.com/40#entry40comment</comments>
      <pubDate>Wed, 8 Jan 2025 23:39:40 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2025/01/03</title>
      <link>https://cej4297.tistory.com/39</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 진행사항&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 오늘은 Java 1주차 강의 숙제와, 새롭게 발의된 과제인 '계산기 만들기' 코드 작성을 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 1주차 강의 숙제 &amp;lt;요리 레시피 메모장 만들기&amp;gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 오늘은 java Scanner 크래스를 이용해, 입력한 데이터를 저장 및 출력하는 방법에 대해 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 Scanner의 메소드를 사용할때, 문자열(String) 으로 입력받고 싶다면, next(), nextLine() 을 사용하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정사(int)로 입력받고 싶다면 nextInt() 를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ Scanner 클래스 사용시 util 패키지 경로 Scanner 클래스 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;= import java.util.Scanner;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력받은 값을 토대로, 문자열을 만들고, 매 줄 앞에 부여할 번호도 for(반복)문을 사용하여 부여하고, 입력받은 title 값에 괄호[] 부여 후, 출력하는 코드를 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 작성한 코드&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String title = sc.nextLine(); // 첫 줄 제목값을 읽음
        float rate = sc.nextFloat(); // 둘째줄 별점을 읽음
        sc.nextLine(); // 나머지 줄 데이터를 읽음

        String[] inputs = new String[10]; // 10줄의 문자열을 저장하는 배열

        for (int i = 0; i &amp;lt; 10; i++) {
            inputs[i] = sc.nextLine();
        } // 매 줄 앞에 부여할 번호 입력

        title = &quot;[&quot; + title + &quot;]&quot;;
        System.out.println(title); // 제목 출력

        int intRate = (int) rate;
        System.out.println(&quot;별점 : &quot; + intRate); // 별점 출력
        double percentage = intRate * 100 / 5.0;
        System.out.println(&quot; (&quot; + percentage + &quot;%)&quot;); // 별점 퍼센트 출력

        for (int i = 0; i &amp;lt; 10; i++) {
            System.out.println((i + 1) + &quot;. &quot; + inputs[i]); // 각 줄 번호 부여 + 내용 출력
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;▷ 숙제를 진행하는 중엔 여기저기 데이터를 참고하여 작성하였지만, 2주차 강의에 들어서고 메소드별 해설을 들으니 이제야 이해가 가는듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 계산기 만들기 LV1&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 위 1주차 숙제와 같이, 스캐너 클래스를 활용하여, 필요한 값을 입력받을수 있게 준비하고, 조건문(if)을 사용하여, 사칙연산으로 계산한 값을 구했다. (+ 사칙연산에 이상한 값을 입력할경우 에러 메세지 출력)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 마지막 결과 값 및 계산을 계속할건지의 대한 질문 멘트 + exit 입력시 작동 종료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- if (sc.next().equals(&quot;exit)) break; -&amp;gt; exit 입력시 작동 종료&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;package com.example.calculator;

import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        System.out.println(&quot;Hello, Calculator!&quot;);
        Scanner sc = new Scanner(System.in);

        while (true) {
            // 첫번째 값 입력받기
            System.out.println(&quot;첫 번째 숫자를 입력하세요: &quot;);
            int num1 = sc.nextInt();
            // 두번째 값 입력받기
            System.out.println(&quot;두 번째 숫자를 입력하세요: &quot;);
            int num2 = sc.nextInt();
            // 사칙연산 입력받기
            System.out.println(&quot;사칙연산 기호를 입력하세요: &quot;);
            char fbo = sc.next().charAt(0);

            int result = 0;

            if (fbo == '+') {
                result = num1 + num2; // 더하기
            } else if (fbo == '-') {
                result = num1 - num2; // 빼기
            } else if (fbo == '*') {
                result = num1 * num2; // 곱하기
            } else if (fbo == '/') {
                result = num1 / num2; // 나누기
            } else {
                System.out.println(&quot;사칙연산 Error&quot;); // 에러메세지
            }

            System.out.println(&quot;결과 : &quot; + result);

            System.out.println(&quot;계산을 계속하시겠습니까? (exit 입력시 종료)&quot;);
            if (sc.next().equals(&quot;exit&quot;))
                break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; 마치며&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;오늘은 강의 수강과 병행하며, 프로젝트 (계산기 만들기)를 진행했다. 나름 여러 클래스와 문법을 알아가며 유익한 시간을 보냈다고 생각하지만 한편으론 막상 코드를 작성하려하면 막히는 내 자신을 보며 아쉬움또한 크게 다가왔다. 이렇게 차근차근 배우다보면 자동적으로 코드를 작성할수 있는 날이 올지 걱정된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/39</guid>
      <comments>https://cej4297.tistory.com/39#entry39comment</comments>
      <pubDate>Fri, 3 Jan 2025 22:36:54 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2024/12/31</title>
      <link>https://cej4297.tistory.com/38</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 오늘 하루 일과&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 새로운 한주의 시작과 함께 새로 편성된 조원들과 만나 가볍게 인사 후, 온종일 강의 수강에 매진하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 언어의 탄생부터 시작하여, 기능, JVM 등 기본적인 배경 지식에 대해 배운 후, 코드 해석하기 실습이 이어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼자 아무 강의와 책자들을 붙잡고 공부하던것보다 확실히 나에게 맡는 눈높이에서 기본부터 차근차근 가르쳐주시니 완벽하진 않지만 작동원리등을 대충이나마 이해할수 있어 긍정적으로 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 배운것&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본형 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 논리형 변수 : boolean = True/False 값만 저아함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문자형 변수 : char = 'A', '1'과 같은 문자 하나만 저아함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정수형 변수 : byte, short, int, long = 0,1,2,99와 같은 정수형 숫자값을 저장함&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqN51p/btsLCnhAu69/34wjSgolLat1gs3QEnK0JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqN51p/btsLCnhAu69/34wjSgolLat1gs3QEnK0JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqN51p/btsLCnhAu69/34wjSgolLat1gs3QEnK0JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqN51p%2FbtsLCnhAu69%2F34wjSgolLat1gs3QEnK0JK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;843&quot; height=&quot;382&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실수형 변수&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- float (4byte) : 3.4 * -10^38 ~ 3.4 * 10^38 (long 보다 큼)범위의 숫자 저장이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- double (8byte) 1.7 * -10^308 ~ 1.7 * 10^308 (long 보다 큼)범위의 숫자 저장이 가능하다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조형 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문자열 변수 : String = &quot;Apple&quot;, &quot;텍스트&quot;와 같은 문장을 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그 외 : Objefct, Array, List.... = 객체, 배열, 리스트와 같은 단일 저장공간에 담을 수 없는 값을 저장함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;래퍼 클래스 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본형 변수 타입명에서 첫글자를 대문자로 바꾸어서 래퍼 클래스를 정의해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 박스 VS 언박싱&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 기본 타입에서 래퍼 클래스 변수로 변수를 감싸는 것을 &quot;박싱&quot;이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 래퍼 클래스 변수를 기본 타입 변수로 가져오는 것을 &quot;언박싱&quot;이라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표하던 강의의 주차까지 진도를 빼지못해 아쉬움이 큰 하루다. 튜터님께서도 이해가 안되도 계속해서 진도를 뒤로 빼는게 중요하다 하셨는데, 이해력이 부족한지 강의 하나에 기본적으로 1시간 이상을 소요하여, 목표하던 목요일까지 3주차 강의까지 완료할수 있을지가 걱정이다. 부족하다면 시간을 더 쓰면 될일, 내일은 공휴일이라 공강이지만, 시간을 할애하여 3주차까지의 강의를 완강하는것을 목표로하자&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/38</guid>
      <comments>https://cej4297.tistory.com/38#entry38comment</comments>
      <pubDate>Tue, 31 Dec 2024 21:36:18 +0900</pubDate>
    </item>
    <item>
      <title>TIL - 2024/12/30</title>
      <link>https://cej4297.tistory.com/37</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 오늘 하루 일과&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘부로 본 부트캠프 1주차 프로젝트가 막을 내렷다. 일주일간 열심히 준비한 결과물이 좋은 평가를 받아 기분좋게 프로젝트를 마무리 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이번 프로젝트를 진행하며, 부족한 실력으로 내가 맡은 비중은 크지 않았으나, 사전 캠프에서 배운 기초 지식으로 나에게 할당된 일을 무사히 마친것에 나름 성취감도 느꼇고, 팀원들의 작업물을 보고 배운점 또한 많은 한 주가 된것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 프로젝트 발표, 특강 등으로 자습할 시간이 주어지지 않아, 별도의 배운것을 쓸게 없어 TIL 을 길게 작성하진 못할것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;▶ 마치며&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인생 첫 프로젝트를 진행하며, 나에게 부족한점을 절실히 느꼇다. 무엇보다 기본 지식 확보를 우선으로 해야겠다는 생각이 들고, 다음 프로젝트때는 당당히 한명 이상의 효율을 낼수 있게 되는것을 목표로 공부를 이어가야겠다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>호롤로</author>
      <guid isPermaLink="true">https://cej4297.tistory.com/37</guid>
      <comments>https://cej4297.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 30 Dec 2024 21:03:56 +0900</pubDate>
    </item>
  </channel>
</rss>